专栏首页架构说代理单点故障如何解决(面试必备)

代理单点故障如何解决(面试必备)

大家好,

我是程序员小王。今天分享的是代理单点故障解决方法。

总耗时4个小时,累计3天时间查看了代理单点故障的解决方式。

2019-6-9

参考工业级产品 nginx,redis,twemproxy 并且对应优缺点。 说明:代理最终还是没有缓存数据,依然存在概率失败问题。

原则

思考一个问题

什么说 twemproxy 对平滑扩容、故障恢复不友好支持,nginx支持吗?

  • Nginx 仅仅支持http功能代理模块。
  • Twemproxy 仅仅支持tcp代理模块。
  • 借助于 Twemproxy 来做二次开发,把 Nginx 的高性能、高可靠、高并发机制引入到 Twemproxy 中 代码地址: https://github.com/meitu/twemproxy(彩蛋)

1. 推特原生 Twemproxy 瓶颈

如今 Twemproxy 凭借其高性能的优势, 在很多互联网公司得到了广泛的应用,已经占据了不可动摇的地位,

然而在实际的生产环境中,Twemproxy 存在以下缺陷:(前方高能)

  1. 单进程单线程,无法充分发挥服务器多核 CPU 的性能。
  2. 当 Twemproxy QPS 短连接达到 8000 后,消耗 CPU 超过 70%,时延陡增。
  3. 大流量下造成 IO 阻塞,无法处理更多请求,QPS上不去,业务时延飙升。
  4. 维护成本高,如果想要充分发挥服务器的所有资源包括 CPU、 网络 IO 等,就必须建立多个 Twemproxy 实例,维护成本高。
  5. 扩容、升级不便。 目前成熟的 twemproxy 对平滑扩容、故障恢复和集群管理方面多做得不够

旁白:为什么这样说呢? 因为每次扩容,需要停止业务,迁移数据,重新加装配置上访

  1. 在原生的 twemproxy 里面是不支持 Redis 主从模式的 这个应该主要是因为 twemproxy 把 Redis/Memcached 当做是缓存而不是存储

原生 Twemproxy 进程呈现了下图现象:

一个人干活,多个人围观。多核服务器只有一个 CPU 在工作,资源没有得到充分利用。

Nginx 多进程高并发、低时延在滴滴缓存代理中的应用

2. Nginx

Nginx 是俄罗斯软件工程师 Igor Sysoev 开发的免费开源 Web 服务器软件,聚焦于高性能,高并发和低内存消耗问题,成为业界公认的高性能服务器,并逐渐成为业内主流的 Web 服务器。

.Nginx 主要特点有:

  1. 完全借助 Epoll 机制实现异步操作,避免阻塞。(epoll解决不了)
  2. 重复利用现有服务器的多核资源。
  3. 充分利用 CPU 亲和性(affinity),把每个进程与固定 CPU 绑定在一起,给定的 CPU 上尽量长时间地运行而不被迁移到其他处理器的倾向性,减少进程调度开销。
  4. 请求响应快。
  5. 支持模块化开发,扩展性好。
  6. Master+ 多 worker 进程方式,确保 worker 进程可靠工作。当 worker 进程出错时,可以快速拉起新的 worker 子进程来提供服务。
  7. 内存池、连接池等细节设计保障低内存消耗。
  8. 热部署支持,master 与 worker 进程分离设计模式,使其具有热部署功能。
  9. 升级方便,升级过程不会对业务造成任何伤害。

Nginx 多进程提供服务过程如下图所示:

Nginx 多进程高并发、低时延在滴滴缓存代理中的应用

3.为什么要选择 twemproxy

twemproxy 是一款由 twitter 开源的 Redis/Memcached 代理,主要目标是减少后端资源的连接数以及为缓存横向扩展能力。

twemproxy 支持多种 hash 分片算法,同时具备失败节点自动剔除的功能。除此之外,其他比较成熟的开源解决方案还有 codis,codis 具备在线的 auto-scale 以及友好的后台管理, 但整体的功能更接近于 Redis Cluster,而不是代理。

Twemproxy 是一个快速的单线程代理程序,支持 Memcached ASCII 协议和更新的 Redis 协议。它全部用 C 写成,使用 Apache 2.0 License 授权。

支持以下特性: 轻量级 维护持久的服务器连接 启用请求和响应的管道 支持代理到多个后端缓存服务器 !!!! 同时支持多个服务器池 多个服务器自动分享数据!!!! 可同时连接后端多个缓存集群 !!!! 实现了完整的 Memcached Ascii 和 Redis 协议. 服务器池配置简单,通过一个 YAML 文件即可 一致性 Hash 详细的监控统计信息 支持 Linux,* BSD,OS X and Solaris ( SmartOS ) 支持设置 HashTag 连接复用,内存复用,提高效率

需要的是一个 Redis 和 Memcached 协议类 PaaS 服务的代理(网关),所以我们最终选择了 twemproxy。

twemproxy 实现

twemproxy 主要的功能是解析用户请求后转发到后端的缓存资源,成功后在把响应转发回客户端。

代码实现的核心是三种连接对象:

  1. proxy connection, 用来监听用户建立连接的请求,建立连接成功后会对应产生一个客户端连接;
  2. client connection,由建连成功后产生,用户读写数据都是通过 client;connection 解析请求后,根据 key 和哈希规则选择一个 server 进行转发;
  3. server connection,转发用户请求到缓存资源并接收和解析响应数据转回 client connection,client connection 将响应返回到用户。

三种连接的数据流向如下图:

美图高性能twemproxy的改造之路

上图的 client connection 之所以没有 imsgq 是因为请求解析完可以直接进入 server 的 imsgq

  1. 用户通过 proxy connection 建立连接,产生一个 client connection;
  2. client connection 开始读取用户的请求数据,并将完整的请求根据 key 和设置的哈希规则选择 server, 然后将这个请求存放到 server 的 imsgq;
  3. 接着 server connection 发送 imsgq 请求到远程资源,发送完成之后(写 tcp buffer) 就会将 msg 从 imsgq 迁移到 omsgq,响应回来之后从 omsgq 队列里面找到这个对应的 msg 以及 client connection;
  4. 最后将响应内容放到 client connection 的 omsgq,由 client connection 将数据发送回客户端。

上面提到的用户请求和资源响应的数据都是在解析之后放到内存的 buf 里面,在 client 和 server 两种连接的内部流转也只是指针的拷贝(官网 README 里面提到的 Zero Copy)。

这也是 twemproxy 单线程模型在小包场景能够达到 10w qps 的原因之一,几乎不拷贝内存。

4.Nginx Master+Worker 多进程机制在 Twemproxy 中的应用

  • 4.1 为什么选择 Nginx 多进程机制做为参考?

Twemproxy 和 Nginx 都属于网络 IO 密集型应用,都属于七层转发应用,时延要求较高,应用场景基本相同。

Nginx 充分利用了多核 CPU 资源,性能好,时延低。 多进程模式

  • 4.2 Master-Worker 多进程机制原理

Master-worker 进程机制采用一个 master 进程来管理多个 worker 进程。每一个 worker 进程都是繁忙的,它们在真正地提供服务,master 进程则很“清闲”,只负责监控管理worker进程。

  • master 进程包含:接收来自外界的信号;
  • 向各 worker 进程发送信号;
  • 监控 worker 进程的运行状态;
  • 当 worker 进程退出后 ( 异常情况下 ),会自动重新启动新的 worker 进程。
  • Worker 进程负责处理客户端的网络请求,多个 worker 进程同时处理来自客户端的不同请求,worker 进程数可配置。

Nginx 多进程高并发、低时延在滴滴缓存代理中的应用

Nginx 多进程高并发、低时延在滴滴缓存代理中的应用

5说明 没有解决问题

  • 如何实现资源缩容/扩容对业务无感? 扩容过程,proxy起到什么作用。我么想明白。

这依靠redis本身,用多进程之后可以分片重启。

1.是无感知,即对redis集群的用户来说服务ip和port保持不变 2.弹性扩容,指的是在需要时刻可以按照业务扩大redis存储容量。

正实现无感知弹性扩容方案 最终的方案新增了一个VIP,用这个VIP来解决无感知的问题,即扩容对客户端来说是无感知的。

  • 无感知的解决类似”双buffer交换“的思路, 即上图的twemproxy-C和twemproxy-D, 当需要重启twemproxy代理时,
  • 可以进行如下操作:

1.现假设vip只访问到twemproxy-C 2.更改twemproxy-D使用最新的配置,重启 3.vip切换服务到只访问twemproxy-D

当还需要重启代理时,以此循环。

  • 单点故障,正在处理请求如何解决,我没看明白? 我理解是 这个无法解决,因为代理不缓存数据。

.6 Twemproxy 改造前后性能对比(时延、QPS 对比)

6.1 线上真实流量时延对比

6.1.1 改造前线上 Twemproxy 集群时延

线上集群完全采用开源 Twemproxy 做代理,架构如下:

Nginx 多进程高并发、低时延在滴滴缓存代理中的应用

未改造前线上 Twemproxy+Memcache 集群,QPS=5000~6000,长连接,客户端时延分布如下图所示:

Nginx 多进程高并发、低时延在滴滴缓存代理中的应用

长连接

Nginx 多进程高并发、低时延在滴滴缓存代理中的应用

在 Twemproxy 机器上使用 tcprstat 监控到的网卡时延如下:

Nginx 多进程高并发、低时延在滴滴缓存代理中的应用

从上面两个图可以看出,采用原生 Twemproxy 时延高,同时抖动厉害。

6.2 参考 Nginx 多进程改造后的 Twemproxy 线下压测结果 ( 开启 Reuseport 功能 )

监听同一个端口,数据长度 100 字节,压测结果如下:

– Linux 内核版本:Linux-3.10

– 物理机机型: M10 ( 48 CPU

改正后的性能

7 总结: 参照 Nginx 改造后的 Twemproxy 特性

7.1 多进程、多线程机制选择

选择参照 Nginx 多进程机制,而不选择多线程实现原因主要有:

  • 多进程机制无锁操作,实现更容易。
  • 多进程的代理,整个 worker 进程无任何锁操作,性能更好。 如果是多线程方式,如果代码出现 Bug 段错误,则整个进程挂掉,整个服务不可用。而如果是多进程方式, 因为 Bug 触发某个 worker 进程段错误异常,其他工作进程不会受到如何影响,20 个 worker 进程,如果触发异常,同一时刻只有 1/20 的流量受到影响。 而如果是多线程模式,则 100% 的流量会受到影响。
  • worker 进程异常退出后,master 进程立马感知拉起一个新进程提供服务,可靠性更高。
  • 配置热加载、程序热升级功能实现更加容易。

7.2 参照 Nginx 改造后的 Twemproxy 特性

支持 Nginx 几乎所有的优秀特性,同时也根据自己实际情况新增加了自有特性:

  • master+ 多 worker 进程机制
  • 适配所有 Linux 内核版本,内核低版本惊群问题避免支持
  • quic_ack 支持
  • reuser_port 适配支持
  • worker 进程异常,master 进程自动拉起功能支持 90%、95%、98%、100% 平均时延统计功能支持
  • Memcache 单机版、集群版支持
  • Redis 单机版、集群版支持
  • 二进制协议、文本协议同时支持
  • Redis、Memcache 集群在线扩容、缩容、数据迁移支持,扩缩容、数据迁移过程对业务无任何影响。【最关键地方,如何做到的】
  • 多租户支持,一个代理可以接多个 Memcache、Redis 集群,并支持混部。
  • mget、gets、sets 等批量处理命令优化处理
  • 慢响应日志记录功能支持
  • 内存参数实时修改支持
  • 详细的集群监控统计功能
  • CPU 亲缘性自添加
  • 内存配置动态实时修改

信念会影响你的行为

本文分享自微信公众号 - 架构说(JiaGouS),作者:程序员小王

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-06-09

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 进程fork函数

    验证1 fork会重新拷贝父进程的一份资源 例如 环境变量 公共变量 代码地址: https://code.csdn.net/snippets/1697496...

    程序员小王
  • 关于linux进程间的close-on-exec机制

    待我们仔细分析流量已经用netstat查看具体的连接数,离我们设置的上限还差很远。这个时候开始怀疑我们的程序是不是有bug导致文件描述符泄露了。

    程序员小王
  • leetcode打家劫舍问题

    https://leetcode-cn.com/problems/house-robber/description/

    程序员小王
  • Python 列表知识大全

    序列是Python中最基本的数据结构(可变数据类型)。序列中的每个元素都分配一个数字 - 它的位置,或索引,第一个索引是0,第二个索引是1,依此类推。

    Python知识大全
  • 对于 bug 铺天盖地的 Python 程序,该如何高效的调试?

    不管用什么语言在编写程序的时候,总会出现形形色色的 bug,由于程序员经常被玩坏,各种属于程序员的“俚语”也被大众熟知,出现了 bug 估计连我隔壁老王的三姨妈...

    Rocky0429
  • 一个简单的购物商城,记录一下。

    py3study
  • Linux atop监控

    atop是一个功能非常强大的linux服务器监控工具,它的数据采集主要包括:CPU、内存、磁盘、网络、进程等,并且内容非常的详细,特别是当那一部分存在压力它会以...

    sunsky
  • 软件定义交付宣言(Software Defined Delivery Manifesto)

    原文链接:https://github.com/sdd-manifesto/manifesto 中文链接:https://github.com/wizardby...

    顾宇
  • 运维=平台+数据

    运维的发展日新月异,曾几何时,运维仅仅是被认知为跑机房,装系统,设计网络,给开发擦屁股。但是现在运维变得极度重要,运维职责也更加细化,譬如稍大点的公司就将运维划...

    用户2936994
  • Python:基础入门

    py3study

扫码关注云+社区

领取腾讯云代金券