码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • 18. 从零开始编写一个类nginx工具, 主动式健康检查源码实现


    合集 - wmproxy(17)
    1.用Rust手把手编写一个Proxy(代理), 动工09-192.用Rust手把手编写一个Proxy(代理), UDP绑定篇09-213.5. 用Rust手把手编写一个Proxy(代理), 通讯协议建立, 为内网穿透做准备09-284.6. 用Rust手把手编写一个wmproxy(代理,内网穿透等), 通讯协议源码解读篇09-305.7. 用Rust手把手编写一个wmproxy(代理,内网穿透等), HTTP及TCP内网穿透原理及运行篇10-046.8. 用Rust手把手编写一个wmproxy(代理,内网穿透等), HTTP改造篇之HPACK原理10-087. 用Rust手把手编写一个Proxy(代理), 准备篇, 动手造轮子09-168.9. 用Rust手把手编写一个wmproxy(代理,内网穿透等), HTTP2改造篇之HPACK示例, 了解http2头信息如何处理10-099.10. 用Rust手把手编写一个wmproxy(代理,内网穿透等), HTTP内网穿透支持修改头信息10-1010.11. 用Rust手把手编写一个wmproxy(代理,内网穿透等), 实现健康检查10-1211.12. 用Rust手把手编写一个wmproxy(代理,内网穿透等), TLS的双向认证信息及token验证10-1412.13. 从零开始编写一个类nginx工具, HTTP中的压缩gzip,deflate,brotli算法10-1713.14. 从零开始编写一个类nginx工具, HTTP文件服务器的实现过程及参数10-1914.15. 从零开始编写一个类nginx工具, 如果将nginx.conf转成yaml,toml,json会怎么样10-2015.16. 从零开始编写一个类nginx工具, 反向代理upstream源码实现10-2316.17. 从零开始编写一个类nginx工具, Rust中一些功能的实现10-24
    17.18. 从零开始编写一个类nginx工具, 主动式健康检查源码实现10-26
    收起

    wmproxy

    wmproxy将用Rust实现http/https代理, socks5代理, 反向代理, 静态文件服务器,后续将实现websocket代理, 内外网穿透等, 会将实现过程分享出来, 感兴趣的可以一起造个轮子法

    项目地址

    gite: https://gitee.com/tickbh/wmproxy

    github: https://github.com/tickbh/wmproxy

    为什么我们需要主动

      主动可以让我们掌握好系统的稳定性,假设我们有一条连接不可达,连接超时的判定是5秒,需要检测失败3次才认定为失败,那么此时从我们开始检测,到判定失败需要耗时15秒。
      如果此时我们是个高并发的系统,每秒的QPS是1000,我们有三个地址判定,那么此时我们有1/3的失败概率。那么在15秒内,我们会收到15000个请求,会造成5000个请求失败,如果是重要的数据,我们会丢失很多重要数据。
      如果此时客户端拥有重试机制,那么客户端在失败的时候会发起重试,而且系统可能会反复的分配到那台不可达的系统,将会造成短时间内请求数激增,可能引发系统的雪崩。
      所以此时我们主动知道目标端的系统稳定性极其重要。

    网络访问示意图

    以下是没有主动健康检查

    客户端代理服务器后端1后端2机器宕机不可达请求数据(0.5s)连接并请求数据(5s)失败返回失败0.5s(总耗时6s)重新请求数据(0.5s)请求数据成功(0.2s)返回数据成功(0.2s)返回数据成功0.5s(总耗时1.4s)客户端代理服务器后端1后端2

    如果出错的时候,一个请求的平均时长可能会达到(1.4s + 5s) / 2 = (3.2s),比正常访问多了(3.2 - 1.4) = 1.8s,节点的宕机会对系统的稳定性产生较大的影响

    以下是主动健康检查,它保证了访问后端服务器组均是正常的状态

    客户端代理服务器服务器组(只访问1)loop[健康检查]处理客户端数据请求数据(0.5s)定时请求,保证存活,1检查成功,2检查失败请求数据(0.2s)返回数据成功(0.2s)返回数据成功(0.5s)(总耗时1.4s)客户端代理服务器服务器组(只访问1)

    服务器2出错的时候,主动检查已经检查出服务器2不可用,负载均衡的时候选择已经把服务器2摘除,所以系统的平均耗时1.4s,系统依然保持稳定

    健康检查的种类

    在目前的系统中有以下两分类:

    • HTTP 请求特定的方法及路径,判断返回是否得到预期的status或者body
    • TCP 仅只能测试连通性,如果能连接表示正常,会出现能连接但无服务的情况

    健康检查的准备

    我们需要从配置中读出所有的需要健康检查的类型,即需要去重,把同一个指向的地址过滤掉
    配置有可能被重新加载,所以我们需要预留发送配置的方式(或者后续类似nginx用新开进程的方式则不需要),此处做一个预留。

    • 如何去重
      像这种简单级别的去重通常用HashSet复杂度为O(1)或者用简单的Vec复杂度为O(n),以SocketAddr的为键值,判断是否有重复的数据。

    • 如何保证不影响主线程
      把健康请求的方法移到异步函数,用tokio::spawn中处理,在健康检查的情况下保证不影响其它数据处理

    • 如果同时处理多个地址的健康检查
      每一次健康检查都会在一个异步函数中执行,在我们调用完请求后,我们会对当前该异步进行tokio::time::sleep以让出当前CPU。

    • 如何按指定间隔时间请求
      因为每一次健康请求都是在异步函数中,我们不确认之前的异步是否完成,所以我们在每次请求前都记录last_request,我们在请求前调用HealthCheck::check_can_request判断当前是否可以发送请求来保证间隔时间内不多次请求造成服务器的压力。

    • 超时连接判定处理
      利用tokio::time::timeout和future做组合,等超时的时候直接按错误处理

    部分实现源码

    主要源码定义在check/active.rs中,主要的定义两个类

    /// 单项健康检查
    #[derive(Debug, Clone)]
    pub struct OneHealth {
    /// 主动检查地址
    pub addr: SocketAddr,
    /// 主动检查方法, 有http/https/tcp等
    pub method: String,
    /// 每次检查间隔
    pub interval: Duration,
    /// 最后一次记录时间
    pub last_record: Instant,
    }
    /// 主动式健康检查
    pub struct ActiveHealth {
    /// 所有的健康列表
    pub healths: Vec,
    /// 接收健康列表,当配置变更时重新载入
    pub receiver: Receiver<Vec>,
    }

    我们在配置的时候获取所有需要主动检查的数据

    /// 获取所有待健康检查的列表
    pub fn get_health_check(&self) -> Vec {
    let mut result = vec![];
    let mut already: HashSet = HashSet::new();
    if let Some(proxy) = &self.proxy {
    // ...
    }
    if let Some(http) = &self.http {
    // ...
    }
    result
    }

    主要的检查源码,所有的最终信息都落在HealthCheck中的静态变量里:

    pub async fn do_check(&self) -> ProxyResult<()> {
    // 防止短时间内健康检查的连接过多, 做一定的超时处理, 或者等上一条消息处理完毕
    if !HealthCheck::check_can_request(&self.addr, self.interval) {
    return Ok(())
    }
    if self.method.eq_ignore_ascii_case("http") {
    match tokio::time::timeout(self.interval + Duration::from_secs(1), self.connect_http()).await {
    Ok(r) => match r {
    Ok(r) => {
    if r.status().is_server_error() {
    log::trace!("主动健康检查:HTTP:{}, 返回失败:{}", self.addr, r.status());
    HealthCheck::add_fall_down(self.addr);
    } else {
    HealthCheck::add_rise_up(self.addr);
    }
    }
    Err(e) => {
    log::trace!("主动健康检查:HTTP:{}, 发生错误:{:?}", self.addr, e);
    HealthCheck::add_fall_down(self.addr);
    }
    },
    Err(e) => {
    log::trace!("主动健康检查:HTTP:{}, 发生超时:{:?}", self.addr, e);
    HealthCheck::add_fall_down(self.addr);
    },
    }
    } else {
    match tokio::time::timeout(Duration::from_secs(3), self.connect_http()).await {
    Ok(r) => {
    match r {
    Ok(_) => {
    HealthCheck::add_rise_up(self.addr);
    }
    Err(e) => {
    log::trace!("主动健康检查:TCP:{}, 发生错误:{:?}", self.addr, e);
    HealthCheck::add_fall_down(self.addr);
    }
    }
    }
    Err(e) => {
    log::trace!("主动健康检查:TCP:{}, 发生超时:{:?}", self.addr, e);
    HealthCheck::add_fall_down(self.addr);
    }
    }
    }
    Ok(())
    }

    结语

    主动检查可以及时的更早的发现系统中不稳定的因素,是系统稳定性的基石,也可以通过更早的发现因素来通知运维介入,我们的目的是使系统更稳定,更健壮,处理延时更少。

    点击 [关注],[在看],[点赞] 是对作者最大的支持

  • 相关阅读:
    【网安AIGC专题10.19】论文6:Java漏洞自动修复+数据集 VJBench+大语言模型、APR技术+代码转换方法+LLM和DL-APR模型的挑战与机会
    在WPF应用中使用FastReport.WPF报表模块
    项目质量管理
    Yapi浏览器插件
    SLS 1508 支持艾默生DeltaV报警抑制模块的设计
    书赞桉诺中国研创中心正式动工 以创新力推动可持续发展
    检测文件目录及其子文件到底的代码-实现可展开的目录列表和文件浏览功能的HTML代码
    关于Flask_运行导入Flask的py文件的两种方式
    【斯坦福大学公开课CS224W——图机器学习】三、节点和图嵌入
    Hexo博客主题Next添加动态线条背景canvas_nest
  • 原文地址:https://www.cnblogs.com/wmproxy/p/wmproxy18.html
  • 最新文章
  • 攻防演习之三天拿下官网站群
    数据安全治理学习——前期安全规划和安全管理体系建设
    企业安全 | 企业内一次钓鱼演练准备过程
    内网渗透测试 | Kerberos协议及其部分攻击手法
    0day的产生 | 不懂代码的"代码审计"
    安装scrcpy-client模块av模块异常,环境问题解决方案
    leetcode hot100【LeetCode 279. 完全平方数】java实现
    OpenWrt下安装Mosquitto
    AnatoMask论文汇总
    【AI日记】24.11.01 LangChain、openai api和github copilot
  • 热门文章
  • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
    奉劝各位学弟学妹们,该打造你的技术影响力了!
    五年了,我在 CSDN 的两个一百万。
    Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
    面试官都震惊,你这网络基础可以啊!
    你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
    心情不好的时候,用 Python 画棵樱花树送给自己吧
    通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
    13 万字 C 语言从入门到精通保姆级教程2021 年版
    10行代码集2000张美女图,Python爬虫120例,再上征途
Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1
正则表达式工具 cron表达式工具 密码生成工具

京公网安备 11010502049817号