分享:唯品会大规模 Redis Cluster 的生产实践

这篇Blog转载我在Redis中国用户组分享的PPT,原文地址:唯品会大规模 Redis Cluster 的生产实践

———————————————————————————————————————————————————————————-
请及时关注“高效运维(微信ID:greatops)”公众号,并置顶公众号,以免错过各种干货满满的原创文章。

本文由Redis中国用户组和高效运维公众号联合首发,未经许可,严禁转载。

关于嘉宾

陈群,目前在唯品会主要负责redis/hbase的运维和开发支持工作,也参与工具开发工作。

本文是陈群同学在Redis中国用户组给大家分享redis cluster的生产实践。
———————————————————————————————————————————————————————————-

Outline

一、生产应用场景
二、存储架构演变
三、应用最佳实践
四、运维经验总结


第1、2节介绍redis cluster在唯品会的生产应用场景,以及存储架构的演变。第3节:redis cluster的稳定性,应用成熟度,踩到过那些坑,如何解决这些问题?这部分是大家比较关系的内容。第4节简单介绍大规模运营的一些经验,包括部署、监控、管理以及redis工具开发。

一、生产应用场景
1、业务范围
redis cluster在唯品会主要应用于后端业务,用作内存存储服务。主要大数据实时推荐/ETL、风控、营销三大业使用。cluster用于取代当前twemproxy三层架构,作为通用的存储架构。redis cluster可以大幅度简化我们的存储架构,也解决twemproxy架构无法在线扩容节点的问题。目前我们在线有生产几十个cluster集群,约2千个instances,单个集群最大达到250+instances。


2、三大业务特点
cluster作为数据量大, 单个cluster集群在几十个GB到上TB级别内存存储量。

作为后端应用的存储,数据来源主要以下三种方式:

Kafka –> Redis Cluster,Storm/Spark实时

Hive –> Redis Cluster, MapReduce程序

MySQL –> Redis Cluster,Java/C++程序。

数据由离线/实时job生成, 读写请求量大, 对读写性能也要求高。

业务高峰期请求量急剧上升,几倍的读写量增加,需要多个redis实例承担业务的读写压力。

业务需求变化快, schema变化频繁。如果使用MySQL作为存储,那么将会是频繁的DLL变更,而且需要做online schema change。

大促销活动时扩容频繁。


3、为什么选择redis cluster
3.1 cluster适合我们后端生产应用场景
在线水平扩展能力,能够解决我们大量的扩容需求。

Failover能力和高可用性。

虽然cluster不保证主从数据强一致性,但是后端业务能够容忍failover后少量的数据丢失。


3.2 架构简单
无中心架构,各个节点度等。slave节点提供数据冗余,master节点异常时提升为master。

取代twemproxy三层架构,系统复杂性降低。

可以节约大量的硬件资源,我们的Lvs + Twemproxy层 使用了近上千台物理机器。

少了lvs和twemproxy层,读写性能提升明显。响应时间从100-200us减少到50-100us。

系统瓶颈更少。lvs层网卡和pps吞吐量瓶颈;对于请求长度加大的业务,twemproxy单节点性能低。


二、存储架构演变
1、架构演变
1)在2014年7月,为了准备当时的814撒娇节大促销活动,我们把单个redis的服务平滑的迁移到twemproxy上。twemproxy在后端快速完成数据分片和扩容。为了避免再次扩容,我们静态分配足够多的资源。

2)之后,twemproxy暴露出来的系统瓶颈很多,资源使用也很多也存在一定的浪费。我们决定用redis cluster取代这种复杂的三层架构。


2、Twemproxy架构
优点
sharding逻辑对开发透明,读写方式和单个redis一致。

可以作为cache和storage的proxy(by auto-eject)。


缺点
架构复杂,层次多。包括lvs、twemproxy、redis、sentinel和其控制层程序。

管理成本和硬件成本很高。

2 * 1Gbps 网卡的lvs机器,最大能支撑140万pps。

流量高的系统,proxy节点数和redis个数接近。

Redis层仍然扩容能力差,预分配足够的redis存储节点。


3、Redis Cluster架构
优点
无中心架构。

数据按照slot存储分布在多个redis实例上。

增加slave做standby数据副本,用于failover,使集群快速恢复。

实现故障auto failover。节点之间通过gossip协议交换状态信息;投票机制完成slave到master角色的提升。

亦可manual failover,为升级和迁移提供可操作方案。

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


缺点
client实现复杂,驱动要求实现smart client,缓存slots mapping信息并及时更新。

目前仅JedisCluster相对成熟,异常处理部分还不完善,比如常见的“max redirect exception”。

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

节点会因为某些原因发生阻塞(阻塞时间大于clutser-node-timeout),被判断下线。这种failover是没有必要,sentinel也存在这种切换场景。

三、应用最佳实践
redis cluster的稳定性如何?

存在哪些坑?

develop guideline & best practice


1、稳定性
不扩容时集群非常稳定。

扩容resharding时候,早期版本的Jedis端有时会出现“max-redirect”异常。

分析Jedis源码,请求重试次数达到了上限,仍然没有请求成功。两方面分析:redis连接不上?还是集群节点信息不一致?

存活检测机制缺陷

redis 存活检测机制可能因为master 节点上慢查询、阻塞式命令、或者其它的性能问题导致长时间没有响应,这个节点会认为处于failed状态,并进行切换。这种切换是没必要的。

优化策略:a) 默认的cluster-node-timeout为15s,可以适当增大; b) 避免使用会引起长时间阻塞的命令,比如save/flushdb等阻塞操作,或者keys pattern这种慢查询。


2、有哪些坑?
2.1 迁移过程中Jedis“Max Redirect”异常。
github上讨论的结果是程序retry。

max redirt issues:https://github.com/xetorthio/jedis/issues/1238

retry时间应该大于failover 时间。

Jedis参数优化调整:增大jedis中的‘DEFAULT_MAX_REDIRECTIONS’参数,默认值是5.

避免使用multi-keys操作,比如mset/mget. multi-key操作有些客户端没有支持实现。


2.2 长时间阻塞引起的不必要的failover
阻塞的命令。比如save/flushall/flushdb

慢查询。keys *、大key的操作、O(N)操作

rename危险操作:

rename-command FLUSHDB REDIS_FLUSHDB

rename-command FLUSHALL REDIS_FLUSHALL

rename-command KEYS REDIS_KEYS

2.3 同时支持ipv4和ipv6侦听服务埋下的坑
具体现象:redis启动正常,节点的协议端口只有ipv6 socket创建正常。异常节点也无法加入到集群中,也无法获取epoch。

解决方法:启动时指定网卡ipv4地址,也可以是0.0.0.0,配置文件中添加:bind 0.0.0.0


2.4 数据迁移速度较慢
主要使用的redis-trib.rb reshard来完成数据迁移。

redis-3.0.6版本以前migrate操作是单个key逐一操作。从redis-3.0.6开始,支持单次迁移多个key。

redis集群内部最多只允许一个slot处于迁移状态,不能并发的迁移slots。

redis-trib.rb reshard如果执行中断,用redis-trib.rb fix修复集群状态。


2.5 版本选择/升级建议
我们已经开始使用3.0.7版本,很多3.2.0修复的bug已经backport到这个版本。

另外我们也开始测试3.2.0版本,内存空间优化很大。

Tips

redis-trib.rb支持resharding/rebalance,分配权重。

redis-trib.rb支持从单个redis迁移数据到cluster集群中。


3、最佳实践
3.1 应用做好容错机制
连接或者请求异常,进行连接retry和reconnect。

重试时间应该大于cluster-node-time时间


3.2 制定开发规范
慢查询,进程cpu 100%、客户端请求变慢,甚至超时。

避免产生hot-key,导致节点成为系统的短板。

避免产生big-key,导致网卡打爆、慢查询。

TTL, 设置合理的ttl,释放内存。避免大量key在同一时间段过期,虽然redis已经做了很多优化,仍然会导致请求变慢。

key命名规则。

避免使用阻塞操作,不建议使用事务。


3.3 优化连接池使用
主要避免server端维持大量的连接。

合理的连接池大小。

合理的心跳检测时间。

快速释放使用完的连接。

*Jedis一个连接创建异常问题(fixed): https://github.com/xetorthio/jedis/issues/1252


3.4 区分redis/twemproxy和cluster的使用
redis建议使用pipeline和multi-keys操作,减少RTT次数,提高请求效率。

twemproxy也支持pipeline, 支持部分的multi-key可以操作。

redis cluster不建议使用pipeline和multi-keys操作,减少max redirect产生的场景。


3.5 几个需要调整的参数
1)设置系统参数vm.overcommit_memory=1,可以避免bgsave/aofrewrite失败。

2)设置timeout值大于0,可以使redis主动释放空闲连接。

3)设置repl-backlog-size 64mb。默认值是1M,当写入量很大时,backlog溢出会导致增量复制不成功。

4)client buffer参数调整

* client-output-buffer-limit normal 256mb 128mb 60

* client-output-buffer-limit slave 512mb 256mb 180


四、运维经验总结
1、自动化管理
CMDB管理所有的资源信息。

Agent方式上报硬软件信息。

标准化基础设置。机型、OS内核参数、软件版本。

Puppet管理和下发标准化的配置文件、公用的任务计划、软件包、运维工具。

资源申请自助服务。


2、自动化监控
zabbix作为主要的监控数据收集工具。

开发实时性能dashboard,对开发提供查询。

单机部署多个redis,借助于zabbix discovery。

开发DB响应时间监控工具Titan。

基本思想来源于pt-query-degest,通过分析tcp应答报文产生日志。flume agent + kafka收集,spark实时计算,hbase作为存储。最终得到hotquery/slowquery,request source等性能数据。


3、自动化运维
资源申请自助服务化。

如果申请合理,一键即可完成cluster集群部署。


4、redis开源工具介绍
4.1 redis实时数据迁移工具
1) 在线实时迁移

2) redis/twemproxy/cluster 异构集群之间相互迁移。

3)github:https://github.com/vipshop/redis-migrate-tool


4.2 redis cluster管理工具
1)批量更改集群参数

2)clusterrebalance

3)很多功能,具体看github :

https://github.com/deep011/redis-cluster-tool



4.3 多线程版本Twemproxy
1)大幅度提升单个proxy的吞吐量,线程数可配置。

2)压测情况下,20线程达到50w+qps,最优6线程达到29w。

3)完全兼容twemproxy。

4)github:

https://github.com/vipshop/twemproxies



4.4 在开发的中的多线redis
1)Github:

https://github.com/vipshop/vire

2)欢迎一起参与协作开发

此条目发表在redis分类目录,贴了标签。将固定链接加入收藏夹。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>