优酷土豆的Redis服务平台化之路

优酷土豆的Redis服务平台化之路


1

Redis架构的方案经历阶段

1.1. 客户端分片

客户端分片:

优点

不依赖于第三方中间件,实现方法和代码自己掌控,可随时调整

这种分片机制的性能比代理式更好(少了一个中间分发环节)

可控的分发请求,分发压力落在客户端,无服务器压力增加

缺点

不能平滑的水平扩展节点,扩容/缩容时,必须手动调整分片程序

出现故障,不能自动转移,运维性很差

客户端得自己维护一套路由算法

升级复杂

1.2. Twemproxy

Twemproxy:

优点

运维成本低。业务方不用关心后端Redis实例,跟操作Redis一样

Proxy 的逻辑和存储的逻辑是隔离的

缺点

代理层多了一次转发,性能有所损耗

进行扩容/缩容时候,部分数据可能会失效,需要手动进行迁移,对运维要求较高,而且难以做到平滑的扩缩容

出现故障,不能自动转移,运维性很差

升级复杂

1.3. Redis Cluster

Redis Cluster:

优点

无中心节点

数据按照Slot存储分布在多个Redis实例上

平滑的进行扩容/缩容节点

自动故障转移(节点之间通过Gossip协议交换状态信息,进行投票机制完成Slave到Master角色的提升)

降低运维成本,提高了系统的可扩展性和高可用性

缺点

严重依赖外部Redis-Trib

缺乏监控管理

需要依赖Smart Client(连接维护, 缓存路由表, MultiOp和Pipeline支持)

Failover节点的检测过慢,不如“中心节点ZooKeeper”及时

Gossip消息的开销

无法根据统计区分冷热数据

Slave“冷备”,不能缓解读压力

1.4. Proxy+Redis Cluster

Smart Client vs Proxy:

优点

Smart Client:

a. 相比于使用代理,减少了一层网络传输的消耗,效率较高。

b. 不依赖于第三方中间件,实现方法和代码自己掌控,可随时调整。

Proxy:

a. 提供一套HTTP Restful接口,隔离底层存储。对客户端完全透明,跨语言调用。

b. 升级维护较为容易,维护Redis Cluster,只需要平滑升级Proxy。

c. 层次化存储,底层存储做冷热异构存储。

d. 权限控制,Proxy可以通过秘钥控制白名单,把一些不合法的请求都过滤掉。并且也可以控制用户请求的超大Value进行控制,和过滤。

e. 安全性,可以屏蔽掉一些危险命令,比如Keys、Save、Flush All等。

f. 容量控制,根据不同用户容量申请进行容量限制。

g. 资源逻辑隔离,根据不同用户的Key加上前缀,来进行资源隔离。

h. 监控埋点,对于不同的接口进行埋点监控等信息。

缺点

Smart Client:

a. 客户端的不成熟,影响应用的稳定性,提高开发难度。

b. MultiOp和Pipeline支持有限。

c. 连接维护,Smart客户端对连接到集群中每个结点Socket的维护。

Proxy:

a.  代理层多了一次转发,性能有所损耗。

b.进行扩容/缩容时候对运维要求较高,而且难以做到平滑的扩缩容。

2

为什么选择Nginx开发Proxy

1.单Master多Work模式,每个Work跟Redis一样都是单进程单线程模式,并且都是基

于Epoll事件驱动的模式。

2.Nginx采用了异步非阻塞的方式来处理请求,高效的异步框架。

3.内存占用少,有自己的一套内存池管理方式,。将大量小内存的申请聚集到一块,能够比Malloc 更快。减少内存碎片,防止内存泄漏。减少内存管理复杂度。

4.  为了提高Nginx的访问速度,Nginx使用了自己的一套连接池。

5.  最重要的是支持自定义模块开发。

6.  业界内,对于Nginx,Redis的口碑可称得上两大神器。性能也就不用说了。

3

Proxy+Redis Cluster介绍

3.1  Proxy+Redis Cluster架构方案介绍

1. 用户在ACL平台申请集群资源,如果申请成功返回秘钥信息。

2. 用户请求接口必须包含申请的秘钥信息,请求至LVS服务器。

3. LVS根据负载均衡策略将请求转发至Nginx Proxy。

4. Nginx Proxy首先会获取秘钥信息,然后根据秘钥信息去ACL服务上获取集群的种子信息。(种子信息是集群内任意几台IP:PORT节点)

然后把秘钥信息和对应的集群种子信息缓存起来。并且第一次访问会根据种子IP:PORT获取集群Slot对应节点的Mapping路由信息,进行缓存起来。最后根据Key计算SlotId,从缓存路由找到节点信息。

5. 把相应的K/V信息发送到对应的Redis节点上。

6. Nginx Proxy定时(60s)上报请求接口埋点的QPS,RT,Err等信息到Open-Falcon平台。

7. Redis Cluster定时(60s)上报集群相关指标的信息到Open-Falcon平台。

3.2  Nginx Proxy功能介绍

目前支持的功能:

HTTP Restful接口:

解析用户Post过来的数据, 并且构建Redis协议。客户端不需要开发Smart Client, 对客户端完全透明、跨语言调用

权限控制:

根据用户Post数据获取AppKey,Uri, 然后去ACL Service服务里面进行认证。如果认证通过,会给用户返回相应的集群种子IP,以及相应的过期时间限制等信息

限制数据大小:

获取用户Post过来的数据,对Key,Value长度进行限制,避免产生超大的Key,Value,打满网卡、阻塞Proxy

数据压缩/解压:

如果是写请求,对Value进行压缩(Snappy),然后在把压缩后的数据存储到Redis Cluster。

如果是读请求,把Value从Redis Cluster读出来,然后对Value进行解压,最后响应给用户。

缓存路由信息:

维护路由信息,Slot对应的节点的Mapping信息

结果聚合:

MultiOp支持

批量指令支持(Pipeline/Redis+Lua+EVALSHA进行批量指令执行)

资源逻辑隔离:

根据用户Post数据获取该用户申请的NameSpace,然后以NameSpace作为该用户请求Key的前缀,从而达到不同用户的不同NameSpace,进行逻辑资源隔离

重试策略:

针对后端Redis节点出现Moved,Ask,Err,TimeOut等进行重试,重试次数可配置

连接池:

维护用户请求的长连接,维护后端服务器的长连接

配额管理:

根据用户的前缀(NameSpace), 定时的去抓取RANDOMKEY,根据一定的比率,估算出不同用户的容量大小值,然后在对用户的配额进行限制管理

过载保护:

通过在Nginx Proxy Limit模块进行限速,超过集群的承载能力,进行过载保护。从而保证部分用户可用,不至于压垮服务器

监控管理:

Nginx Proxy接入了Open-Falcon对系统级别,应用级别,业务级别进行监控和告警

例如: 接口的QPS,RT,ERR等进行采集监控,并且展示到DashBoard上

告警阈值的设置非常灵活,配置化

待开发的功能列表:

层次化存储:

利用Nginx Proxy共享内存定制化开发一套LRU本地缓存实现,从而减少网络请求

冷数据Swap到慢存储,从而实现冷热异构存储

主动Failover节点:

由于Redis Cluster是通过Gossip通信, 超过半数以上Master节点通信(cluster-node-timeout)认为当前Master节点宕机,才真的确认该节点宕机。判断节点宕机时间过长,在Proxy层加入Raft算法,加快失效节点判定,主动Failover

3.3  Nginx Proxy性能优化

3.3.1  批量接口优化方案

1. 子请求变为协程

案例:

用户需求调用批量接口mget(50Key)要求性能高,吞吐高,响应快。

问题:

由于最早用的Nginx Subrequest来做批量接口请求的处理,性能一直不高,CPU利用率也不高,QPS提不起来。通过火焰图观察分析子请求开销比较大。

解决方案:

子请求效率较低,因为它需要重新从Server Rewrite开始走一遍Request处理的PHASE。并且子请求共享父请求的内存池,子请求同时并发度过大,导致内存较高。

协程轻量级的线程,占用内存少。经过调研和测试,单机一两百万个协程是没有问题的,

并且性能也很高。

优化前:

a) 用户请求mget(k1,k2)到Proxy

b) Proxy根据k1,k2分别发起子请求subrequest1,subrequest2

c) 子请求根据key计算slotid,然后去缓存路由表查找节点

d) 子请求请求Redis Cluster的相关节点,然后响应返回给Proxy

e) Proxy会合并所有的子请求返回的结果,然后进行解析包装返回给用户

优化后:

a) 用户请求mget(k1,k2)到Proxy

b) Proxy根据k1,k2分别计算slotid, 然后去缓存路由表查找节点

c) Proxy发起多个协程coroutine1, coroutine2并发的请求Redis Cluster的相关节点

d) Proxy会合并多个协程返回的结果,然后进行解析包装返回给用户

2. 合并相同槽,批量执行指令,减少网络开销

案例:

用户需求调用批量接口mget(50key)要求性能高,吞吐高,响应快。

问题:

经过上面协程的方式进行优化后,发现批量接口性能还是提升不够高。通过火焰图观察分析网络开销比较大。

解决方案:

因为在Redis Cluster中,批量执行的key必须在同一个slotid。所以,我们可以合并相同slotid的key做为一次请求。然后利用Pipeline/Lua+EVALSHA批量执行命令来减少网络开销,提高性能。

优化前:

a) 用户请求mget(k1,k2,k3,k4) 到Proxy。

b) Proxy会解析请求串,然后计算k1,k2,k3,k4所对应的slotid。

c) Proxy会根据slotid去路由缓存中找到后端服务器的节点,并发的发起多个请求到后端服务器。

d) 后端服务器返回结果给Proxy,然后Proxy进行解析获取key对应的value。

e) Proxy把key,value对应数据包装返回给用户。

优化后:

a) 用户请求mget(k1,k2,k3,k4) 到Proxy。

b) Proxy会解析请求串,然后计算k1,k2,k3,k4所对应的slotid,然后把相同的slotid进行合并为一次Pipeline请求。

c) Proxy会根据slotid去路由缓存中找到后端服务器的节点,并发的发起多个请求到后端服务器。

d) 后端服务器返回结果给Proxy,然后Proxy进行解析获取key对应的value。

e) Proxy把key,value对应数据包装返回给用户。

3. 对后端并发度的控制

案例:

当用户调用批量接口请求mset,如果k数量几百个甚至几千个时,会导致Proxy瞬间同时发起几百甚至几千个协程同时去访问后端服务器Redis Cluster。

问题:

Redis Cluster同时并发请求的协程过多,会导致连接数瞬间会很大,甚至超过上限,CPU,连接数忽高忽低,对集群造成不稳定。

解决方案:

单个批量请求对后端适当控制并发度进行分组并发请求,反向有利于性能提升,避免超过Redis Cluster连接数,同时Redis Cluster 波动也会小很多,更加的平滑。

优化前:

a) 用户请求批量接口mset(200个key)。(这里先忽略合并相同槽的逻辑)

b) Proxy会解析这200个key,会同时发起200个协程请求并发的去请求Redis Cluster。

c) Proxy等待所有协程请求完成,然后合并所有协程请求的响应结果,进行解析,包装返回给用户。

优化后:

a) 用户请求批量接口mset(200个key)。 (这里先忽略合并相同槽的逻辑)

b) Proxy会解析这200个key,进行分组。100个key为一组,分批次进行并发请求。

c) Proxy先同时发起第一组100个协程(coroutine1, coroutine100)请求并发的去请求Redis Cluster。

d) Proxy等待所有协程请求完成,然后合并所有协程请求的响应结果。

e) Proxy然后同时发起第二组100个协程(coroutine101, coroutine200)请求并发的去请求Redis Cluster。

f) Proxy等待所有协程请求完成,然后合并所有协程请求的响应结果。

g) Proxy把所有协程响应的结果进行解析,包装,返回给用户。

4.单Work分散到多Work

案例:

当用户调用批量接口请求mset,如果k数量几百个甚至几千个时,会导致Proxy瞬间同时发起几百甚至几千个协程同时去访问后端服务器Redis Cluster。

问题:

由于Nginx的框架模型是单进程单线程, 所以Proxy发起的协程都会在一个Work上,这样如果发起的协程请求过多就会导致单Work CPU打满,导致Nginx 的每个Work CPU使用率非常不均,内存持续暴涨的情况。(nginx 的内存池只能提前释放大块,不会提前释放小块)

解决方案:

增加一层缓冲层代理,把请求的数据进行拆分为多份,然后每份发起请求,控制并发度,在转发给Proxy层,避免单个较大的批量请求打满单Work,从而达到分散多Work,达到Nginx 多个Wrok CPU使用率均衡。

优化前:

a) 用户请求批量接口mset(200个key)。(这里先忽略合并相同槽的逻辑)

b) Proxy会解析这200个key,会同时发起200个协程请求并发的去请求Redis Cluster。

c) Proxy等待所有协程请求完成,然后合并所有协程请求的响应结果,进行解析,包装返回给用户。

优化后:

a) 用户请求批量接口mset(200个key)。(这里先忽略合并相同槽的key的逻辑)

b) Proxy会解析这200个key,然后进行拆分分组以此来控制并发度。

c) Proxy会根据划分好的组进行一组一组的发起请求。

d) Proxy等待所有请求完成,然后合并所有协程请求的响应结果,进行解析,包装返回给用户。

总结,经过上面一系列优化,我们可以来看看针对批量接口mset(50个k/v)性能对比图,Nginx Proxy的响应时间比Java版本的响应时间快了5倍多。

Java版本:

Nginx版本:

3.3.2  网卡软中断优化

irqbalance根据系统中断负载的情况,自动迁移中断保持中断的平衡。但是在实时系统中会导致中断自动漂移,对性能造成不稳定因素,在高性能的场合建议关闭。

1. 首先关闭网卡软中断

service irqbalance stop

service cpuspeed stop

2. 查看网卡是队列

grep eth /proc/interrupts | awk '{print $1, $NF}'

77: eth0

78: eth0-TxRx-0

79: eth0-TxRx-1

80: eth0-TxRx-2

81: eth0-TxRx-3

82: eth0-TxRx-4

83: eth0-TxRx-5

84: eth0-TxRx-6

85: eth0-TxRx-7

3. 绑定网卡软中断到CPU0-2号上

(注意这里的echo 是十六进制)

echo "1" > /proc/irq/78/smp_affinity

echo "1" > /proc/irq/79/smp_affinity

echo "2" > /proc/irq/80/smp_affinity

echo "2" > /proc/irq/81/smp_affinity

echo "2" > /proc/irq/82/smp_affinity

echo "4" > /proc/irq/83/smp_affinity

echo "4" > /proc/irq/84/smp_affinity

echo "4" > /proc/irq/85/smp_affinity

3.3.3  绑定进程到指定的CPU

绑定nginx或者redis的pid到cpu3-cpu10上:

taskset -cp 3 1900

taskset -cp 4 1901

taskset -cp 5 1902

taskset -cp 6 1903

taskset -cp 7 1904

taskset -cp 8 1905

taskset -cp 9 1902

taskset -cp 10 1902

或者通过Nginx Proxy配置:

worker_cpu_affinity 绑定CPU亲缘性

3.3.4  性能优化神器火焰图

3.4  Redis Cluster运维

3.4.1 运维功能

1. 创建集群

2. 集群扩容/缩容

3. 节点宕机

4. 集群升级

5. 迁移数据

6. 副本迁移

7. 手动failover

8. 手动rebalance

以上相关运维功能,目前是通过脚本配置化一键式操作,依赖于官方的redis-rebalance.rb进行扩展开发。运维非常方便快捷。

3.5  性能测试报告

3.5.1  测试环境

软件:

Jmeter

Nginx Proxy(24核)

Redis集群(4 Master,4 Slave)

测试Key(100000)

硬件:

OS: Centos6.6

CPU:24核

带宽:千兆

内存:62G

测试结果:

场景:普通K/V

QPS:18W左右

RT: 99都在10ms以内

CPU:Nginx Proxy CPU在50%左右

4

监控告警

4.1 系统级别

通过Open-Falcon Agent采集服务器的CPU、内存、网卡流量、网络连接、磁盘等信息。

4.2 应用级别

通过Open-Falcon Plugin采集Nginx/Redis进程级别的CPU,内存,Pid等信息。

4.3 业务级别

通过在Proxy里面埋点监控业务接口QPS,RT(50%,99%,999%),请求流量,错误次数等信息,定时的上报给Open-Falcon。

通过Open-Falcon Plugin采集Redis Cluster集群信息,QPS,连接数等相关指标指标信息。

作者介绍:

李航: 5年多互联网工作经验,先后在58同城,汽车之家,优酷土豆集团工作。目前主要在优酷土豆集团任职高级开发工程师,目前主要负责大数据基础平台Redis集群开发及运维等工作。主要关注领域Nginx,Redis,分布式系统,分布式存储。如果对redis/hbase/spark/storm/kafka等大数据领域有深厚的兴趣,可以发送简历给gaosong@youku.com。

本文来源自“Redis技术交流群”线上分享。李航ID:Lucien_168。群主ID:gnuhpc。后期的分享我们会同期进行。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260

推荐阅读更多精彩内容

  • 转发:Redis Cluster探索与思考 Redis Cluster的基本原理和架构 Redis Cluster...
    meng_philip123阅读 3,519评论 0 14
  • 本文将从Redis的基本特性入手,通过讲述Redis的数据结构和主要命令对Redis的基本能力进行直观介绍。之后概...
    kelgon阅读 60,957评论 24 626
  • 转载地址:http://gnucto.blog.51cto.com/3391516/998509 Redis与Me...
    Ddaidai阅读 21,397评论 0 82
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,087评论 18 139
  • 不知从什么时候开始,我竟给自己画了张脸谱,而且时时改变着,乐此不疲。慢慢地,我发现,几乎所有的人都为自己画了脸谱,...
    jerrybirdy阅读 149评论 0 2