高可靠机制在twemproxy缓存代理中间件中的应用

Nginx多进程高并发、低时延、高可靠机制在缓存(redis、memcache)twemproxy代理中的应用

关于作者

前滴滴出行技术专家,现任OPPO 文档数据库  mongodb 负责人,负责  oppo 千万级峰值  TPS/ 十万亿级数据量文档数据库  mongodb 内核研发及运维工作,一直专注于分布式缓存、高性能服务端、数据库、中间件等相关研发。  Github 账号地址  :

1. 开发背景

       现有开源缓存代理中间件有  twemproxy    codis  等,其中  twemproxy  为单进程单线程模型,只支持  memcache  单机版和  redis  单机版,都不支持集群版功能。

       由于  twemproxy  无法利用多核特性,因此性能低下,短连接  QPS  大约为  3W  ,长连接  QPS  大约为  13W  ,同时某些场景时延抖动厉害。

        为了适应公有云平台上业务方的高并发需求,因此决定借助于  twemproxy  来做二次开发,把  nginx  的高性能、高可靠、高并发机制引入到  twemproxy  中,通过  master+    worker  进程来实现七层转发功能。

2    Twemproxy

2.1  Twemproxy简介

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

i)  速度快

ii)  轻量级

iii)  维护持久的服务器连接

iiii)  启用请求和响应的管道

iiiii)  支持代理到多个后端缓存服务器

iiiii)  同时支持多个服务器池

iiiiii)  多个服务器自动分享数据

iiiiiii)  可同时连接后端多个缓存集群

iiiiiiii)  实现了完整的          协议  .

iiiiiiiii)  服务器池配置简单,通过一个   YAML   文件即可

iiiiiiiiii)  一致性  hash

iiiiiiiiii)  详细的监控统计信息

iiiiiiiiiii)  支持   Linux, *BSD, OS X and Solaris (SmartOS)

iiiiiiiiiiii)  支持设置  HashTag

iiiiiiiiiiiiiii)  连接复用,内存复用,提高效率

2.2   memcache缓存集群拓扑结构

      图  1 twemproxy  缓存集群拓扑图

      如上图所示,实际应用中业务程序通过轮询不同的  twemproxy  来提高  qps  ,同时实现负载均衡。

      说明:官方memcache没有集群版和持久化功能,集群版和持久化功能由我们自己内部开发完成。

2.3 推特原生twemproxy瓶颈

      如今  twemproxy  凭借其高性能的优势    在很多互联网公司得到了广泛的应用,已经占据了其不可动摇的地位    然而在实际的生产环境中    存在以下缺陷,如下:

i)  单进程单线程    无法充分发挥服务器多核  cpu  的性能

ii)    twemproxy qps  短连接达到  8000  后,消耗  cpu  超过  70%  ,时延陡增。

iii)  大流量下造成  IO  阻塞,无法处理更多请求,  qps  上不去,业务时延飙升

iiii)  维护成本高,如果想要充分发挥服务器的所有资源包括  cpu     网络  io  等,就必须建立多个  twemproxy  实例,维护成本高

iiiii)  扩容、升级不便

      原生  twemproxy  进程呈现了下图现象:一个人干活,多个人围观。多核服务器只有一个  cpu  在工作,资源没有得到充分利用。

3. Nginx

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

i)  完全借助  epoll  机制实现异步操作,避免阻塞。

ii)  重复利用现有服务器的多核资源。

iii)  充分利用  CPU   亲和性(  affinity  ),把每个进程与固定  CPU  绑定在一起,给定的   CPU   上尽量长时间地运行而不被迁移到其他处理器的倾向性,减少进程调度开销。

iiii)  请求响应快

iiiii)  支持模块化开发,扩展性好

iiiii)Master+    worker  进程方式,确保  worker  进程可靠工作。当  worker  进程出错时,可以快速拉起新的  worker  子进程来提供服务。

iiiiii)  内存池、连接池等细节设计保障低内存消耗。

iiiiii)  热部署支持,  master    worker  进程分离设计模式,使其具有热部署功能。

iiiiiii)  升级方便,升级过程不会对业务造成任何伤害。

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

4    Nginx master+worker多进程机制在twemproxy中的应用

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

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

Nginx充分利用了多核cpu资源,性能好,时延低。

4.2  Master-worker多进程机制原理

      Master-worker进程机制采用一个master进程来管理多个worker进程。每一个worker进程都是繁忙的,它们在真正地提供服务,master进程则很“清闲”,只负责监控管理worker进程, 包含:接收来自外界的信号,向各worker进程发送信号,监控worker进程的运行状态,当worker进程退出后(异常情况下),会自动重新启动新的worker进程。

worker进程负责处理客户端的网络请求,多个worker进程同时处理来自客户端的不同请求,worker进程数可配置。

4.3 多进程关键性能问题点

      master-worker多进程模式需要解决的问题主要有:

i)linux内核低版本(2.6以下版本), “惊群”问题

ii) linux内核低版本(2.6以下版本),负载均衡问题

iii)linux内核高版本(3.9以上版本)新特性如何利用

iii)如何确保进程见高可靠通信

iiii)如何减少worker进程在不同cpu切换的开销

iiiii)master进程如何汇总各个工作进程的监控数据

iiiiii)worker进程异常,如何快速恢复

   4.3.1  linux内核低版本关键技术问题

      由于linux低内核版本缺陷,因此存在”惊群”、负载不均问题,解决办法完全依赖应用层代码保障。

 4.3.1.1 如何解决“惊群”问题

      当客户端发起连接后,由于所有的worker子进程都监听着同一个端口,内核协议栈在检测到客户端连接后,会激活所有休眠的worker子进程,最终只会有一个子进程成功建立新连接,其他子进程都会accept失败。

      Accept失败的子进程是不应该被内核唤醒的,因为它们被唤醒的操作是多余的,占用本不应该被占用的系统资源,引起不必要的进程上下文切换,增加了系统开销,同时也影响了客户端连接的时延。

      “惊群”问题是多个子进程同时监听同一个端口引起的,因此解决的方法是同一时刻只让一个子进程监听服务器端口,这样新连接事件只会唤醒唯一正在监听端口的子进程。

      因此“惊群”问题通过非阻塞的accept锁来实现进程互斥accept(),其原理是:在worker进程主循环中非阻塞trylock获取accept锁,如果trylock成功,则此进程把监听端口对应的fd通过epoll_ctl()加入到本进程自由的epoll事件集;如果trylock失败,则把监听fd从本进程对应的epoll事件集中清除。

      Nginx实现了两套互斥锁:基于原子操作和信号量实现的互斥锁、基于文件锁封装的互斥锁。考虑到锁的平台可移植性和通用性,改造twemproxy选择时,选择文件锁实现。

      如果获取accept锁成功的进程占用锁时间过长,那么其他空闲进程在这段时间内无法获取到锁,从而无法接受新的连接。最终造成客户端连接相应时间变长,qps低,同时引起负载严重不均衡。为了解决该问题,选择通过post事件队列方式来提高性能,trylock获取到accept锁成功的进程,其工作流程如下:

1.trylock获取accept锁成功

2.通过epoll_wait获取所有的事件信息,把监听到的所有accept事件信息加入accept_post列表,把已有连接触发的读写事件信息加入read_write_post列表。

3.执行accept_post列表中的所有事件

4.Unlock锁

5.执行read_write_post列表中的事件。

Worker进程主循环工作流程图如下:


请使用浏览器的分享功能分享到微信等