一步一个脚印:解密唯品会中Redis集群架构演进与功能定制

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: 在2016杭州云栖大会的“开源数据库之Redis专场”上,来自唯品会的高级数据工程师申政带来了题为《Redis在唯品会的应用实践》的精彩分享。分享中,他主要介绍Redis集群架构演进、Redis使用经验以及唯品会对Redis二次开发实践积累三部分,干货满满,精彩不容错过。

在2016杭州云栖大会的“开源数据库之Redis专场”上,来自唯品会的高级数据工程师申政带来了题为《Redis在唯品会的应用实践》的精彩分享。分享中,他主要介绍Redis集群架构演进、Redis使用经验以及唯品会对Redis二次开发实践积累三部分,干货满满,精彩不容错过。

以下内容根据演讲PPT及现场分享整理。


Redis集群架构演进

目前在唯品会内对Redis的使用属于重量级别,目前在唯品会内大概有8000个Redis实例、1000台物理机、500个应用。

ac5f135676f37a118e26fdb366e39b687e02b8e9

上图是唯品会对Redis使用的演进历史图。在2014年7月左右,采用的是客户端分片(Client Sharding)的架构;2014年7月到2015年12月期间,主要采用的是Twemproxy集群模式;从2015年6月至今,唯品会内主要采用Redis Cluster框架。

下面简单介绍上述三种框架的优缺点。

Client Sharding架构

9130e5cd0b9cb2ec393426c003b39088df42c2ca

Client Shareding的架构如上图所示,从图上可以看出该架构十分简单稳定,但它需要业务方面自定义Key分布,进而增加了业务开发难度和工作量;其次该架构的在线扩容能力非常弱,并且不能在数据库层面提供Failover能力。

Twemproxy架构

1eeba89c40e45d3cad1b0223df02e72574e3c186

唯品会内对Twemproxy的使用超过2000个实例、800台物理机、150个应用,其框架如上图所示,相比于Client Shareding的架构复杂了很多,通过在Twempoxy层上增加了LVS,既增加了Twempoxy的高可用,又可以在LVS下任意增加或删除Twempoxy节点,很好的支持了增量业务。

Twemproxy负责数据分片,下面可以挂载多个Redis节点,此外架构中通过采用Redis官方提供的HA保证主从之间的高可用。Twemproxy具有很多优点:

  1. 支持数据自分片和一致性Hash
  2. 同时支持RedisMC协议
  3. 支持pipelinemgetmset等多Key操作
  4. Twemproxy自身扩容简单,可以做到用户无感知,降低了业务开发复杂度

事有正反面,在使用Twemproxy过程中也发现其存在很多不足:首先该架构十分复杂,导致机器成本高;其次,Redis和MC扩容比较难;此外,该架构分为三层,每一个环节都可能成为集群的性能瓶颈;客户端的请求需要经过三层的请求链路,导致请求相应时间长;最后尤其值得注意的一点是:它的运维成本很高。

Redis Cluster

adabc412cf3cc1e54c7df768fefa7f91a58302e0

Redis Cluster框架如上图所示,从图中可以看出:它是一个无中心框架,集群中每个节点完全对等,任一节点都与其他节点保持一个长连接,通过高速协议维护整个集群的状态信息;并且该架构还提供了自动Failover和在线扩缩容能力;同时采用单层框架,相应时间短;此外,由于该架构中客户端与Redis直接相连,相比于Twemproxy架构,节省了一半的机器开销。

但该架构对客户端依赖非常重,需要智能客户端支持;对Mget、Mset、Pipeline支持不友好。

一些经验

下面分享一下在使用Redis过程中踩过的坑,供大家借鉴。

f01cd70dd9f0e516d586027c86673a131e6036a3

在使用Twemproxy时,常发现线上同目录实例的内存特别大,达到几G、几十G,甚至比Redis占据的内存还要大。这是因为在业务开发时,一次使用Pipeline过大,命令数量特别多,这是由于Twemproxy是一次性接受完客户端发来的所有数据再转发导致;同时Twemproxy申请的内存申请后不释放,进而导致了内存只增不减。

因此,建议在使用Twemproxy时,一次Pipeline包含的命令量适中,最好不要超过1000个。

ac90c8d9040c8479e5f99a4c0e6a05d37bf90744

按照Twemproxy执行Hash规则,当后端server出现问题时,理论上只会影响当前Server内的Key。但我们遇到的问题是:当其中的一个Server出现问题时,其他Server返回请求都出现问题。这是由Twemproxy代码结构所决定的,它对每一个客户端的链接都有一个队列,当队列头部的请求恰好是出现问题Server的请求(不能响应到Twemproxy),则该请求会将队列中后续的其他Server请求全部卡死,此时这些请求都缓存在Twemproxy,不能相应到客户端,进而导致Twemproxy的内存飙升。

还有一点需要注意:Twemproxy中Timeout参数,默认是永远等待,即便Server没用相应,但其仍认为该Server是正常的,一直等待下去。因此在使用Twemproxy时,务必要注意Timeout参数的设置。

b0966ed7566afdcbaf3b4647de3bdf63aa0d8029

Twemproxy中设计了剔除策略。有时Twemproxy下面挂载的Redis/MC并没有挂掉,网络也没出现问题,但Twemproxy会剔除某些Server。这是由Twemprox自身的设计缺陷导致,在Twemproxy中存在server_connections和server_failure_limit两个参数,前者表示Twemproxy与后端Server建立长连接的数量;后者是Twemproxy与后端server出现问题的连接数,如果连接连续出现问题,则触发剔除策略。

在实际使用时,建议设置server_connections数目小于server_failure_limit,以规避剔除现象的发生。

416ca2d5df964361d451af1f7c64646bf899a469

在使用Twemproxy时,曾出现过这种情况:业务监控客户端连接只有几十个,而Twemproxy端连接却有几千个、甚至上万个。

这是由LVS机制导致的:LVS内有一个专门维护客户端向后端发起连接数量的表,其内置了exprie机制,当连接在15min没有活跃的请求时,会将该连接从表内剔除,而不通知双方。此时,Twemproxy认为该连接是正常的,而客户端发现连接不通时,会新建连接继续发送请求,长此以往,两者的连接数差距越来越大;并且Twemproxy的文件描述符会消耗很快,直到不能再正常建立连接。

为了解决该问题,在Twemproxy中增加了TCPKeepalive功能,完美地规避了该情况的发生。

 

37416899a9f477866a9d30a70ccaab1e991a303c

如果在使用Twemproxy时,发现线上Twemproxy内存监控曲线如上图所示,并且在业务中还用到了Mset命令,基本上可以确定是由Mset引起的内存泄露。

在Mset命令进行拆分时,由于特殊情景导致内存不被释放,进而导致Twemproxy内存越来越大。应对该问题,可以采用重启Twemproxy进行解决。

在使用Redis Cluster的过程中,唯品会积累了一些实践技巧,先总结如下:

  •  Cluster-require-full-coverage建议为no(官方默认为yes)
  •  Cluster-node-timeout建议适当增大
  •  jedisCluster注意捕获异常MaxRedirectionsException(该异常表示命令执行不成功)
  •  不建议使用mget、mset等multi-key命令
  •  尽量使用官方redis-trib脚本管理集群,不要轻易使用Cluster命令

二次开发

在使用Redis过程中,为了更加满足业务需求,唯品会对其进行了二次开发。

de641c00e05d1c9c27218ac63f24aa43a051aecb

对于Twemproxy,为了保障其高可用性,增加了replace_server命令,当Redis Master挂掉之后,Sentinel调用脚本通过replace_server命令把Twemproxy中的Master替换成Slave。

 

d41ae42b8e8819e3467426d13b867095d318c57a

目前唯品会线上最大的Twemproxy集群用到的实例超过100个,如果想更改Twemproxy配置时,工作量是比较大的。因此,唯品会在Twemproxy集群中集成zookeeper,Twemproxy集群的配置信息统一由Zookeeper管理、分发,用户无感知。

7b00f3dbdd75ed4dc66eb1c2c1b9e3d68045bb72

唯品会对MC也进行可二次开发,由于MC中不存在主从概念,但MV集群中其中一个节点挂掉之后会对后端的数据库造成很大的压力。为了解决该问题,在Twemproxy层面增加了复制池(Replication pool)功能,在Master pool和Slave pool之间建立主从关系,客户端同时写入两个pool内;读取时,首先读取Master pool中内容,当Master pool中无数据时,并不会回传到数据库,而是从Slave pool中获取数据,有效减轻由于MC挂掉带给后端数据库的压力。

5ca14f3eeba46123bc54f4936b91a64204afd701

借鉴Redis,在Twemproxy中增加了Slowlog功能,停留时间;此外,还增加简单统计信息功能,将一天分为几个时间段,每个时间段记录Slowlog次数,便于定位Slowlog和解决Slowlog。

5989cc4624654a74592b33027b19acb6e76b2382

增加多线程功能是对Twemproxy一次大的改动。Twemproxy提供的QPS在几万左右,由于线上每个物理机上只能部署一个Twemproxy,导致了物理机极大地浪费。借鉴MC多线程模型,建立了master线程+N个worker线程多线程模型:master线程负责监听端口,接受新的客户端连接;worker线程负责处理客户端请求。Twemproxy多线程开6个线程时,QPS可以达到35万/s,同时也节约了千万服务器成本。

24c6e2cb35f47e6255af217b3364285d26ad5e5f

很多用户在使用Redis Cluster是都会遇到这样问题:flushall删不掉数据;明明Master是存活的,网络也正常,但Cluster却执行了failover。这是因为Redis是单线程的,在执行时间复杂度为O(n)命令时,线程被阻塞,无法响应其他节点的ping命令,造成假死现象,进而导致主从切换。

针对该问题的处理方式是:增加了额外进程监听额外端口(extra-port),当超过cluster-node-timeout/2s时间,ping请求没有收到回复,主动向extra-port发送ping请求。

4de373083adff8a7b9db3fc9760ed44b6428c9d2

最初上线Redis cluster时,很多客户端并不是友善支持,因此增加了Redis Cluster客户端功能,在Hiredis上进行功能改造使其支持集群模式,用于:

  •  解析并更新路由表
  •  处理moved/ask错误
  •  内含Max redirect机制
  •  支持mget、mset、pipeline、异步API

8020c304170a7b009eab361a302367e726e0cb6a

为了应对Redis集群之间的数据迁移,唯品会开发了Redis Migrate迁移工具,它是基于Redis复制功能的,在迁移过程中,老集群正常对外提供服务;并且支持多线程异构迁移,支持Twemproxy、Redis Cluster、RDB文件和AOF文件恢复;同时迁移过程也可以实时查看;此外,该迁移工具还具有比较完善的数据抽样校验机制,保障迁移数据的一致性。

da2a33785b5631e0b8b19b0aab6b7870d735ed89

Redis Migrate具体迁移步骤如上所示,这其中关键点是左侧的配置文件,这里不不再一一叙述。

300f6c5c8d2863d3b4d85d4e5cf38be5f180c631

Reids多线程是目前唯品会正在改造,借鉴于上文提到的Twemproxy多线程改造,将Redis改造成Master+N个worker多线程模型:客户端有worker线程管理;多线程中不可能避免有锁的存在,Redis中存在DB级别读写锁,通过单独后台线程处理过期key和dict维护。

目前Redis多线程实现支持五大数据结构(String/list/hash/set/zset);支持100个Redis命令(包括管理命令)。

398fdd57fcd40c0314e1a88f15ef067169523599

Redis多线程中,为了降低DB锁竞争,引入了逻辑DB。一个逻辑DB包含N个真实物理DB,用户使用的是逻辑DB。一个逻辑DB的所有Key分散在各个物理DB上吗,每个物理DB拥有一把读写锁——pthread_rwlock_t。

7797f7ac18a774ed376d836a16bb654796a67b88

上图是Redis处理客户端请求的命令过程,这里不再一一叙述。每个Worker线程都会进行上图六个步骤,DB锁的竞争主要是在第四步和第五步上,其他步骤Worker之间完全并行。

Redis多线程-性能测试

abc7b2d2cf9e6a9203b335cdc826978a946d20e5

上图是用于Redis多线程性能测试的测试环境配置。

701aae11ee987a1785bc3e85d0e15162b523e802

测试用例图上图所示,从图上可以看出SET的效率为34万左右;GET效率为40万左右。

ce87b1f542640e0d5eeb0f800f21ea02c854373b

热Key问题是使用Redis中不可避免的问题。在Redis多线程中,遇到热Key首先将其拆分,将其分散到不同的Redis实例中。上图是多线程中针对热Key的性能测试:只写一个key时,四个线程的QPS可以达到30万/s;只读一个Key时,四个线程的QPS可以达到43万/s,一定程度上有效改善了热Key问题。

附录:

文章中提到的唯品会对Redis二次开发的源代码开源地址:http://github.com/vipshop

 

相关实践学习
基于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
相关文章
|
20天前
|
存储 缓存 NoSQL
【赵渝强老师】基于Redis的旁路缓存架构
本文介绍了引入缓存后的系统架构,通过缓存可以提升访问性能、降低网络拥堵、减轻服务负载和增强可扩展性。文中提供了相关图片和视频讲解,并讨论了数据库读写分离、分库分表等方法来减轻数据库压力。同时,文章也指出了缓存可能带来的复杂度增加、成本提高和数据一致性问题。
【赵渝强老师】基于Redis的旁路缓存架构
|
23天前
|
人工智能 云计算 网络架构
阿里云引领智算集群网络架构的新一轮变革
11月8日~10日在江苏张家港召开的CCF ChinaNet(即中国网络大会)上,众多院士、教授和业界技术领袖齐聚一堂,畅谈网络未来的发展方向,聚焦智算集群网络的创新变革。
阿里云引领智算集群网络架构的新一轮变革
|
24天前
|
负载均衡 Dubbo 算法
集群容错架构设计
集群容错架构设计
27 1
集群容错架构设计
|
22天前
|
人工智能 运维 网络架构
阿里云引领智算集群网络架构的新一轮变革
11月8日至10日,CCF ChinaNet(中国网络大会)在江苏张家港召开,众多院士、教授和技术领袖共聚一堂,探讨网络未来发展方向。阿里云研发副总裁蔡德忠发表主题演讲,展望智算技术发展趋势,提出智算网络架构变革的新思路,发布高通量以太网协议和ENode+超节点系统规划,引起广泛关注。阿里云HPN7.0引领智算以太网生态蓬勃发展,成为业界标杆。未来,X10规模的智算集群将面临新的挑战,Ethernet将成为主流方案,推动Scale up与Scale out的融合架构,提升整体系统性能。
|
20天前
|
存储 缓存 NoSQL
【赵渝强老师】Memcached集群的架构
Memcached 是一个高性能的分布式内存对象缓存系统,通过在内存中维护一个巨大的 Hash 表来存储各种格式的数据,如图像、视频、文件及数据库检索结果等。它主要用于减轻数据库压力,提高网站系统的性能。Memcached 不支持数据持久化,因此仅作为缓存技术使用。其数据分布式存储由客户端应用程序实现,而非服务端。
【赵渝强老师】Memcached集群的架构
|
23天前
|
存储 NoSQL PHP
如何用Redis高效实现点赞功能?用Set?还是Bitmap?
在众多软件应用中,点赞功能几乎成为标配。本文从实际需求出发,探讨如何利用 Redis 的 `Set` 和 `Bitmap` 数据结构设计高效点赞系统,分析其优缺点,并提供 PHP 实现示例。通过对比两种方案,帮助开发者选择最适合的存储方式。
28 3
|
20天前
|
调度 Docker 容器
【赵渝强老师】Docker Swarm集群的体系架构
Docker Swarm自1.12.0版本起集成至Docker引擎,无需单独安装。它内置服务发现功能,支持跨多服务器或宿主机创建容器,形成集群提供服务。相比之下,Docker Compose仅限于单个宿主机。Docker Swarm采用主从架构,Swarm Manager负责管理和调度集群中的容器资源,用户通过其接口发送指令,Swarm Node根据指令创建容器运行应用。
|
2月前
|
负载均衡 安全 调度
Docker Swarm集群架构
【10月更文挑战第8天】
64 1
|
2月前
|
消息中间件 分布式计算 Kafka
大数据-98 Spark 集群 Spark Streaming 基础概述 架构概念 执行流程 优缺点
大数据-98 Spark 集群 Spark Streaming 基础概述 架构概念 执行流程 优缺点
42 0