技术前沿:分布式缓存Redis Cluster在华泰证券的探索与实践

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介:

Redis Cluster作为最热门的开源分布式缓存,在券商领域会有怎样的应用场景?本文从华泰证券的应用现状出发,介绍了Redis Cluster在华泰证券的大规模实践经验。

引言
Redis 是一个开源(BSD许可)的内存 Key-Value 存储系统,它可以用作数据库、缓存和消息中间件。它支持多种类型的数据结构,如:字符串、散列、列表、集合、有序集合与范围查询等。 Redis 内置了复制、LRU 驱动事件、事务、磁盘持久化等特性,并通过Redis哨兵(主从模式)和自动分区(Redis Cluster模式)提供高可用性。

官方的Redis Cluster推出前,常见的Redis Cluster开源方案主要是Codis和Twemproxy,两者均采用Proxy的方式实现分布式。通过引入Proxy层来屏蔽底层数据的分布,可以简化客户端的实现,但使得集群架构变得复杂,维护成本上升。
Redis从3.0开始支持自动分区,采用无中心节点方式实现Cluster模式。访问Redis Cluster时,无需Proxy代理,具备Smart特性的客户端直接与Redis Cluster中的每个节点连接。

Redis 引入 Cluster 模式带来的优势在于:
1.可靠性:具有分区机制、副本机制和自动容错机制;
2.高性能:保证了 Redis 高吞吐的前提下,可线性扩展到上千个节点;
3.可扩展性:基于分区的自动扩容、缩容,客户端透明的数据迁移。

目前,Redis 在互联网、金融、传统行业内的应用已十分广泛。随着金融业接入互联网的业务增加,活动、促销、节假日、热门事件等可能带来突发数倍甚至几十倍的访问峰值的情况时有发生,Redis Cluster 是抵御突发海量访问的有效手段。
基本原理及概念
Redis Cluster 整体设计是比较简单的,集群架构采用无中心节点的方式实现,集群中的节点通过Gossip协议相互交换集群状态。客户端无需代理直接访问服务端,客户端通过Hash算法计算出Key对应的哈希槽,然后直接访问哈希槽对应的服务端节点。

Redis Cluster 的拓扑结构如下图所示:

image


图1 Redis Cluster架构图


集群构建:
Redis Cluster提供了一组集群搭建和管理命令,如:CLUSTER INFO、CLUSTER NODES、CLUSTER MEET等。实际使用过程中可以借助命令行工具redis-trib.rb,可以方便的搭建一个集群、平衡集群哈希槽分布、删除添加节点等。

搭建一个Redis Cluster仅需两步:
1.节点准备,将编译好的Redis发布到至少三台服务器上,修改配置文件并启动Redis节点;
2.节点握手,使用redis-tribcreate host1:port1 … hostN:portN命令完成节点握手并确认槽位分配。

服务器上有多个Redis实例时,注意修改服务的端口、工作目录、AOF和RDB文件名等配置。创建集群时可以指定副本数,也可以在集群创建完成后,将从节点逐个添加到集群中去。

数据分布:
Redis Cluster基于哈希槽(分片)的方式将数据分布到16384个槽中,每个Master节点负责一部分哈希槽的数据存储。Redis中的每个键都会被映射到这些哈希槽的其中一个,集群使用Hash公式CRC16(key)%16384来计算键key属于哪个槽。

Redis的Smart客户端在访问集群时,先获取并缓存哈希槽和节点的映射关系,然后通过计算Key对应的哈希槽编号查找应该访问的节点。为了配合集群扩缩容、数据迁移等哈希槽映射需要改变的操作,Redis服务端添加了MOVED、ASK两种响应策略,前者通知客户端所访问的哈希槽所在的新节点,后者则通知客户端哈希槽正在迁移到哪个节点。

主从复制:
Redis Cluster 节点间使用异步冗余备份(Asynchronous Replication),不能保证数据的强一致性。可能出现数据丢失的场景:修改操作完成主节点上更新,当主节点回复客户端成功后,增量改动未能同步到从节点,此时主节点异常(宕机、故障转移等),从节点成为主节点;客户端路由表更新窗口期间,集群内或许会有主从角色快速出现两次切换,此时数据仍有可能写错节点,最终造成数据丢失。

虽然Redis主从复制不能保证强一致性,但在不出现主从切换的情况下,数据出现不一致的情况还是很难出现的。实际生产环境下,出现主从切换的概率不大,但仍建议业务系统要有容忍缓存数据丢失的能力。

故障检测:
Redis Cluster 中的每个节点都存储有一份其他已知节点的标识列表,其中有两个标识是用于失效检测,分别是 PFAIL 和 FAIL。当一个节点在超过NODE_TIMEOUT时间后仍无法访问某个节点,他会将被检测节点标识为PFAIL,表示可能失效;一个节点被大多数主节点确认不可达,则会标识为FAIL,表示已经失效。

每个节点定时向其他节点发送Gossip消息,消息中包含一些随机的已知节点的状态。最终每个节点都能收到一份其他节点的标识。当节点被标记为FAIL时,就需要提升一个从节点来做主节点。

故障转移:
当一个负责槽位数大于0的主节点处于FAIL状态时,他的从节点可以自动的发起选举。一旦某个从节点收到了大多数主节点的回应,那么它将提升为新的主节点。另外,Redis Cluster提供了手动故障迁移的命令CLUSTER FAILOVER,可以在运维使用。
Redis Cluster 在华泰证券背景介绍及建设现状

2015年,随着华泰证券互联网金融自主研发的大规模投入,面对海量用户并发场景,迫切需要建设统一化、服务化的分布式缓存平台。

通过对Redis Cluster、Codis及Twemproxy等开源Redis集群解决方案进行验证和对比,最终从性能、易维护、高可用等方面考虑,选择Redis 3.2.0版本的Cluster模式作为公司级缓存解决方案。Redis Cluster获得了开源社区的持续支持,功能、特性一直在迭代改进。相比之下,Codis及Twemproxy社区活跃度较低,维护成本相对较高,吞吐量也略逊于Redis Cluster。

目前,在华泰证券建设有多套 Redis Cluster 资源池,总体集群服务器数量20余台。在交易时段,峰值访问量超 20万次/秒,服务了30个以上应用系统,包括:行情中心、涨乐财富通、互联网用户中心等,在缓存、分布式锁、内存存储、任务队列等业务场景都有应用。

实践经验
(1)高可用多活架构
如图2所示,Redis Cluster数据节点采用同城三数据中心部署方式,通常其中两个数据中心部署数量相等的机器,另一数据中心部署单台机器。为加速重做从节点的速度,主机采用万兆网卡。为保证访问缓存的延时足够小,跨数据中心之间的网络通信采用独立的万兆波分通道。

image

图2 Redis Cluster部署架构图

实际部署时,需要调整 Redis Cluster的Master 节点分布,要保证任意一个数据中心 Master 节点数小于集群的一半。采取这样的部署架构,如果单数据中心出现问题,另一个中心能自动进行接管,业务系统可以无感知切换。
(2)Java客户端层面的调优
1、推荐使用Jedis2.8.x及以上版本,关闭TestOnReturn和TestOnBorrow;
2、推荐使用Jedis的JedisPoolConfig,它是对GenericObjectPoolConfig的优化版本;
3、合理使用HGETALL、SMEMBERS等O(N)操作。
(3)服务端层面的优化
1、重命名KEYS、FLUSHALL、FLUSHDB等耗时且危险的操作;
2、适度加大client-output-buffer-limitslave避免不必要的重做从节点;
3、适度加大repl-backlog-size和repl-backlog-ttl,值越大slave可丢失的时间越长;
4、AOF,关闭RDB,减少服务端fork操作造成的访问出现卡顿的现象;
5、根据实际场景配置cluster-require-full-coverage为yes,减少集群不可用的时间。
(4)Redis Cluster的功能限制
Redis cluster是分布式的Redis实现,具有一定的容错性和线性可扩展性,这些特性牺牲了以下功能:
1、不能使用SELECT命令,不支持对多个槽位内的KEY进行操作,比如MSET、SUNION;
2、发布订阅功能不推荐使用,集群规模越大,产生的网络流量越大;
3、采用Redis主从模式的应用,客户端代码需要少量的改造才能升级到Cluster模式。
(5)问题跟进及版本更新
开源中间件难免出现Bug及其它性能问题,大部分问题开源社区都能找到问题的解决方案,积极的跟进社区讨论是有效的避免生产事故的有效途径。在实际使用中,我们发现了多个Redis的Bug,社区均有解决方案。

目前,我们已经将生产环境上部分Redis节点升级到3.2.7版本,主要因为遇到以下问题:
1、从节点同步Ziplist后,List索引更新错误,造成从节点Crash;
2、Ziplist中成员长度增长,List索引更新错误,造成主节点和从节点的AOF重写均失败,产生大量临时文件。
(6)持续跟进
Redis 2.8.0版本开始引入 PSYNC 机制,PSYNC通过添加缓冲队列,缓存从节点断开连接期间的数据变化增量,当从节点重新连接且缓存队列未溢出时,则可避免早期版本从节点重连后必然需要SYNC操作全量同步主节点数据的问题。

PSYNC可以有效地解决网络抖动造成的从节点短暂断开连接的问题,但无法避免当主节点、从节点相继出现网络失连、重启、进程推出的情况发生后的全量数据同步和恢复,Redis 4.0引入PSYNC 2和PSYNC 3等新特性来解决相关问题。目前Redis 4.0仍处于验证阶段,需要持续验证和密切关注。

典型场景

与其它开源的 key-value 内存存储系统相比,Redis支持的数据更加丰富,常用的value数据类型包括:字符串、哈希表、链表、集合、有序集合。同时,Redis还内置了这些数据结构的常见操作。目前,Redis的应用已经非常广泛,常见的使用场景包括:缓存热数据、计数器、队列、分布式锁、排行榜、新闻列表、评论等场景。Redis Cluster 在华泰证券的新建信息系统中也得到了广泛的应用,使用的部分场景举例如下:

行情截面

某些应用场景可能需要获取某个市场或多个股票的最新行情,可以使用Redis的Hash结构来实现这个需求。示例代码如下:
添加或更新一只股票的行情
HSETMD:XSHG:STOCKTYPE “601688.SH” 17.88
获取多只股票最新行情
HMGET MD:XSHG:STOCKTYPE “601688.SH” “601689.SH”
获取某个交易所所以股票最新行情,HGETALL操作为O(N)操作,不建议频繁调用
HGETALL MD:XSHG:STOCKTYPE
K线
常见的K线为日K线或分钟K线,以日K线为例,可以使用Redis的有序集合来实现,示例代码如下:
添加某只股票2018年3月1的K线
ZADD KLINE:1DAY:601688.SH 20180301 kline_value
获取某只股票多天的K线
ZRANGEBYSCORE KLINE:1DAY:601688.SH 20180301 20180302

任务队列

任务队列用来在任务的生产者和消费者之间传递任务,实现任务的产生和任务执行模块间的松耦合。实例代码如下:
生产者生成一个任务task01
RPUSH TASK:QUEUE “task01”
消费者堵塞等待100秒等待任务,BLPOP是LPOP的堵塞版本
BLPOP TASK:QUEUE 100

未来规划

随着业务的不断发展,Redis Cluster 在华泰证券内部已成为核心组件。未来重点进行 PaaS 平台建设,加强集群自动化灾备;建立分级保障制度,对重点业务进行独立管理。目前,Redis 的最新版本 4.0.x 解决了 Redis 3.2.x 版本在面对网络剧烈抖动时,偶尔会出现部分分片所在的主从节点均不可用的情况。

尽早验证Redis 4.0.x版本的稳定性,制定有效的升级方案和计划,也将是未来工作的重点之一。

原文发布时间为:2018-07-03
本文作者:樊建 陈营 葛宝磊
本文来自云栖社区合作伙伴“数据和云”,了解相关信息可以关注“数据和云”。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
4天前
|
缓存 NoSQL Redis
【后端面经】【缓存】36|Redis 单线程:为什么 Redis 用单线程而 Memcached 用多线程?-- Redis多线程
【5月更文挑战第21天】Redis启用多线程后,主线程负责接收事件和命令执行,IO线程处理读写数据。请求处理流程中,主线程接收客户端请求,IO线程读取并解析命令,主线程执行后写回响应。业界普遍认为,除非必要,否则不建议启用多线程模式,因单线程性能已能满足多数需求。公司实际场景中,启用多线程使QPS提升约50%,或选择使用Redis Cluster以提升性能和可用性。
10 0
|
5天前
|
NoSQL Redis 数据库
【后端面经】【缓存】36|Redis 单线程:为什么 Redis 用单线程而 Memcached 用多线程?-- Memcache + Redis 多线程
【5月更文挑战第20天】Redis采用单线程模式以避免上下文切换和资源竞争,简化调试,且其性能瓶颈在于网络IO和内存,而非多线程。相比之下,Memcache使用多线程能更好地利用多核CPU,但伴随上下文切换和锁管理的开销。尽管Redis单线程性能不俗,6.0版本引入多线程以提升高并发下的IO处理能力。启用多线程后,Redis结合Reactor和epoll实现并发处理,提高系统性能。
25 0
|
6天前
|
Cloud Native 数据管理 关系型数据库
【阿里云云原生专栏】云原生数据管理:阿里云数据库服务的分布式实践
【5月更文挑战第21天】阿里云数据库服务在云原生时代展现优势,应对分布式数据管理挑战。PolarDB等服务保证高可用和弹性,通过多副本机制和分布式事务确保数据一致性和可靠性。示例代码展示了在阿里云数据库上进行分布式事务操作。此外,丰富的监控工具协助用户管理数据库性能,支持企业的数字化转型和业务增长。
174 1
|
6天前
|
缓存 NoSQL 中间件
【后端面经】【缓存】36|Redis 单线程:为什么 Redis 用单线程而 Memcached 用多线程?epoll、poll和select + Reactor模式
【5月更文挑战第19天】`epoll`、`poll`和`select`是Linux下多路复用IO的三种方式。`select`需要主动调用检查文件描述符,而`epoll`能实现回调,即使不调用`epoll_wait`也能处理就绪事件。`poll`与`select`类似,但支持更多文件描述符。面试时,重点讲解`epoll`的高效性和`Reactor`模式,该模式包括一个分发器和多个处理器,用于处理连接和读写事件。Redis采用单线程模型结合`epoll`的Reactor模式,确保高性能。在Redis 6.0后引入多线程,但基本原理保持不变。
24 2
|
7天前
|
缓存 NoSQL Redis
【后端面经】【缓存】36|Redis 单线程:为什么 Redis 用单线程而 Memcached 用多线程?--epoll调用和中断
【5月更文挑战第18天】`epoll`包含红黑树和就绪列表,用于高效管理文件描述符。关键系统调用有3个:`epoll_create()`创建epoll结构,`epoll_ctl()`添加/删除/修改文件描述符,`epoll_wait()`获取就绪文件描述符。`epoll_wait()`可设置超时时间(-1阻塞,0立即返回,正数等待指定时间)。当文件描述符满足条件(如数据到达)时,通过中断机制(如网卡或时钟中断)更新就绪列表,唤醒等待的进程。
35 6
|
8天前
|
NoSQL Redis 缓存
【后端面经】【缓存】36|Redis 单线程:为什么 Redis 用单线程而 Memcached 用多线程?
【5月更文挑战第17天】Redis常被称为单线程,但实际上其在处理命令时采用单线程,但在6.0后IO变为多线程。持久化和数据同步等任务由额外线程处理,因此严格来说Redis是多线程的。面试时需理解Redis的IO模型,如epoll和Reactor模式,以及其内存操作带来的高性能。Redis使用epoll进行高效文件描述符管理,实现高性能的网络IO。在讨论Redis与Memcached的线程模型差异时,应强调Redis的单线程模型如何通过内存操作和高效IO实现高性能。
37 7
【后端面经】【缓存】36|Redis 单线程:为什么 Redis 用单线程而 Memcached 用多线程?
|
11天前
|
存储 监控 NoSQL
【Redis】分布式锁及其他常见问题
【Redis】分布式锁及其他常见问题
42 0
|
11天前
|
缓存 NoSQL 关系型数据库
【Redis】Redis 缓存重点解析
【Redis】Redis 缓存重点解析
28 0
|
11天前
|
缓存 NoSQL 关系型数据库
【Redis】Redis作为缓存
【Redis】Redis作为缓存
13 0
|
11天前
|
NoSQL Java Redis
【Redis】Redis实现分布式锁
【Redis】Redis实现分布式锁
16 0