腾讯云超火开源数据库产品架构揭秘

时间:2021-07-15 | 标签: | 作者:Q8 | 来源:腾讯云数据库网络

小提示:您能找到这篇{腾讯云超火开源数据库产品架构揭秘}绝对不是偶然,我们能帮您找到潜在客户,解决您的困扰。如果您对本页介绍的腾讯云超火开源数据库产品架构揭秘内容感兴趣,有相关需求意向欢迎拨打我们的服务热线,或留言咨询,我们将第一时间联系您!

Redis作为高性能缓存经常被广泛应用到各个业务——如游戏的排行榜、分布式锁等场景。

但Redis也并非万能的,在长期的使用过程中,我们也遇到Redis一些痛点问题,比如内存占用高,数据可靠性差,业务维护缓存和存储的一致性繁琐等。

因此,腾讯云数据库Tendis诞生了,今天,我们就一起回顾腾讯云数据库Tendis混合存储版的整体架构,并且详细揭秘其内部的原理。

Redis&Tendis

使用Redis有哪些痛点?我大致分类为以下三种:

一、内存成本高

首先,在产品的不同阶段,业务对QPS的要求不同,以游戏业务为例,刚上线的新游戏通常来说都特别火爆,为了支持上千万同时在线,需要不断的进行扩容增加机器。而在运营一段时间后,游戏玩家逐渐变少到一个正常的用户量级,访问频率(QPS)没那么高,依然占用大量机器,维护成本很高。

其次,Redis保存全量数据时,需要Fork一个进程。Linux的fork系统调用基于Copy On Write机制,如果在此期间Redis有大量的写操作,父子进程就需要各自维护一份内存。因此部署Redis的机器往往需要预留一半的内存。

二、缓存一致性的问题

对于Redis+MySQL的架构需要业务方花费大量的精力来维护缓存和数据库的一致性。

三、数据可靠性

Redis本质上是一个内存数据库,用户虽然可以使用AOF的Always来落盘保证数据可靠性,但是会带来性能的大幅下降,因此生产环境很少有使用。另外不支持回档,Master故障后,异步复制会造成数据的丢失。

四、异步复制

Redis主备使用异步复制,这个是异步复制固有的问题。主备使用异步复制,响应延迟低,性能高,但是Master故障后,会造成数据丢失。

关于Tendis,我们已经做了很多介绍(开源一周star上千,什么产品这么香?)在此不再赘述。接下来我们对Tendis混合存储版的整体架构进行详细的解读。

Tendis混合存储版整体架构



Tendis冷热混合存储版主要由Proxy、缓存层Redis、存储层Tendis存储版和同步层Redis-sync组成,其中每个组件的功能如下:

一、Proxy组件

负责对客户端请求进行路由分发,将不同的Key的命令分发到正确的分片,同时Proxy还负责了部分监控数据的采集,以及高危命令在线禁用等功能。

二、缓存层Redis Cluster

缓存层Redis基于社区Redis 4.0进行开发。Redis具有以下功能:

版本控制;自动将冷数据从缓存层中淘汰,将热数据从存储层加载到缓存层;使用Cuckoo Filter表示全量Keys,防止缓存穿透;基于RDB+AOF扩缩容方式,扩缩容更加高效便捷。

三、存储层Tendis Cluster

Tendis存储版是腾讯基于RocksDB自研的兼容Redis协议的KV存储引擎,该引擎已经在腾讯内部运营多年,性能和稳定性得到了充分的验证。在混合存储系统中主要负责全量数据的存储和读取,以及数据备份,增量日志备份等功能。

四、同步层Redis-sync

并行数据导入存储层Tendis;服务无状态,故障重新拉起;数据自动路由。

Tendis冷热混合存储的一些重要特性总结:

缓存层Redis Cluster和存储层Tendis Cluster分别进行扩缩容,集群自治管理等;

冷数据自动降冷,降低内存成本;热数据自动缓存,降低访问延迟。

缓存层Redis Cluster

一、版本控制

首先基于社区版Redis改动是版本控制。我们为每个Key和每条Aof增加一个Version,并且Version是单调递增的。在每次更新/新增一个Key后,将当前节点的Version赋值给Key和Value,然后对全局的Version++;

如下所示,在redisObject中添加64bits,其中48bits用于版本控制。

typedef struct redisObject {

unsigned type:4;

unsigned encoding:4;

unsigned lru:LRU_BITS; /* LRU time (relative to global lru_clock) or

                            * LFU data (least significant 8 bits frequency

                            * and most significant 16 bits access time). */

int refcount;


/* for hybrid storage */

unsigned flag:4;                           /* OBJ_FLAG_... */

unsigned reserved:4;

unsigned counter:8;                        /* for cold-data-cache-policy */

unsigned long long revision:REVISION_BITS; /* for value version */


void *ptr;

} robj;

引入版本控制主要带来以下优势:

1.增量RDB

社区版Redis主备在断线重连后,如果slave发送的psync_offset对应的数据不在当前的Master的repl_backlog中,则主备需要重新进行全量同步。

再引入Ver药品销售平台sion之后,slave断线重连,给Master发送带Version的PSYNC replid psync_offset version命令。如果出现上述情况,Master将大于等于Version的数据生成增量RDB,发给Slave,进而解决需要增量,同步比较慢的问题。

2.Aof的幂等

如果同步层Redis-sync出现网络瞬断(短暂的和缓存层或者存储层断开),作为一个无状态的同步组件,Redis-sync会重新拉取未同步到Tendis的增量数据,重新发送给Tendis。每条Aof都具有一个Version,Tendis在执行的时候仅会执行比当前Version大的Aof,避免aof执行多次导致的数据不一致。

二、冷热数据交互

冷数据的恢复指当用户访问的Key不在缓存层,需要将数据从存储层重新加载到缓存层。数据恢复这里是缓存层直接和存储层直接交互,当冷Keys访问的请求比较大,数据恢复很容易成为瓶颈,因此为每个Tendis节点建立一个连接池,专门负责与这个Tendis节点进行冷热数据恢复。

用户访问一个Key的具体流程如下:

首先判断Key是否在缓存层,如果缓存层存在,则执行命令;如果缓存层不存在,查询Cuckoo Filter,判断Key是否有可能在存储层;

如果Key可能在存储层,则向存储层发送dumpx dbid key withttl命令尝试从存储层获取数据,并且阻塞当前请求的客户端;

存储层收到dumpx,如果Key在存储层,则向缓存层返回RESTOREEX dbid key ttl value;如果Key不在存储层(Cuckoo Filter的误判),则向缓存层返回DUMPXERROR key;

存储层收到RESTOREEX或者DUMPXERROR后,将冷数据恢复。然后就可以唤醒阻塞的客户端,执行客户端的请求。

三、Key降冷与Cuckoo Filter

这里主要讲解混合存储从1:1版的缓存层缓存全量Keys,到N:M版的缓存层将Key和Value同时驱逐的演进,以及我们引入Cuckoo Filter避免缓存穿透,同时节省大量内存。

1.Key降冷的背景介绍

2020年6月份上线的1:1版的冷热混合存储,缓存层Redis存储全量的Keys和热Values(All Keys+Hot values),存储层Tendis存储全量的Keys和Values(All Keys+All values)。在上线运行了一段时间后,发现全量Keys的内存开销特别大,冷热混合的收益并不明显。为了进一步释放内存空间,提高缓存的效率,我们放弃了Redis缓存全量Keys的方案,驱逐的时候将key和Value都从缓存层淘汰。

2.Cuckoo Filter解决缓存击穿和缓存穿透

如果缓存层不存储全量的Keys,就会出现缓存击穿和缓存穿透的问题。为了解决这一问题,缓存层引入Cuckoo Filter表示全量的keys。我们需要一个支持删除、可动态伸缩并且空间利用率高的Membership Query结构,经过我们的调研和对比,最终选择Dynamic Cuckoo Filter。



3.Dynamic Cuckoo Filter实现

项目初期参考了RedisBloom中Cuckoo Filter的实现,在开发的过程中也遇到了一些坑,RedisBloom实现的Cuckoo Filter在删除的时候会出现误删,最终给RedisBloom提PR修复了问题。

4.Key降冷的收益

最终采用将Key和Value同时从缓存层淘汰,降低内存的收益很大。比如现网的一个业务,总共有6620 W个Keys,在缓存全量Keys的时候占用18408 MB的内存,在Key降冷后仅仅占用593MB。

四、智能淘汰/加载策略

作为冷热混合存储系统,热数据在缓存层,全量数据在存储层。关键的问题是淘汰和加载策略,这里直接影响缓存的效率,细分主要有两点:当缓存层内存满时,选择哪些数据淘汰?当用户访问存储层的数据时,是否需要将其放入缓存层?

首先介绍混合存储的淘汰策略,主要有以下两个淘汰策略:

1.maxmemory-policy

当缓存层Redis内存使用到达maxmemory,系统将按照maxmemory-policy的内存策略将Key/Value从缓存层驱逐,释放内存空间。(驱逐是指将Key/Value从缓存层中淘汰掉,存储层和缓存层的Cuckoo Filter依然存在该Key;

2.value-eviction-policy

如果配置value-eviction-policy,后台会定期将用户N天未访问的Key/Value被驱逐出内存;

其次讲一下缓存加载策略,为了避免缓存污染的问题(比如类似Scan的访问,遍历存储层的数据,将缓存层真正的热数据淘汰,从而造成了缓存效率低下)。我们实现缓存加载策略:仅仅将规定时间内访问频率超过某个阈值的数据加载到缓存中,这里的时间和阈值都是可配置的。

五、基于RDB+AOF扩缩容

社区版Redis的扩容流程如下所示:

而社区版Redis扩容也存在以下三个问题:

1.importing和migrating的设置不是原子的

先设置目标节点slot为importing状态,再设置源节点的slot为migrating状态。如果反过来,由于两次操作非原子:源节点设置为migrating,目标节点还未设置migrating状态,请求在这两个节点间反复Move。

2.搬迁以Key为粒度,效率较低

Migrate命令每次搬迁一个或者多个Keys,将整个Slot搬迁到目标节点需要多次网络交互。

3.大Key问题

由于Migrate命令是同步命令,在搬迁过程中是不能处理其他用户请求的,因此可能会影响业务(延迟时间波动较大)。

由于社区版Redis存在的上述问题,我们实现了基于RDB+Aof的扩缩容方式,大致流程如下:

1)管控添加新节点,规划待搬迁slots;

2)管控端向目标节点下发slot同步命令:cluster slotsync beginSlot endSlot[[beginSlot endSlot]...]

3)目标节点向源节点发送sync[slot...],命令请求同步slot数据

4)源节点生成指定slot数据的一致性快照全量数据(RDB),并将其发送给目标节点

5)源节点开始持续发送增量数据(Aof)

6)管控端定位获取源节点和目标节点的落后值(diff_bytes),如果落后值在指定的阈值内,管控端向目标节点发送cluster slotfailover(流程类似Redis的cluster failover,首先阻塞源节点写入,然后等待目标节点和源节点的落后值为0,最后将搬迁的slots归属目标节点)

同步层Redis-sync

同步层Redis-sync模拟Redis Slave的行为,接收RDB和Aof,然后并行地导入到存储层Tendis。同步层主要需要解决以下问题:

1)并发地导入到存储层Tendis,如何保证时序正确?

2)特殊命令的处理,比如FLUSHALL/FLUSHDB/SWAPDB/SELECT/MULTI等?

3)作为一个无状态的同步组件,如何保证故障后,数据断点续传?

4)缓存层和存储层分别进行扩缩容,如何将请求路由到正确的Tendis节点?

为了解决上述问题,我们实现了下面的功能:

1.Slot内串行,Slot间并行

针对问题1,Redis-sync中采用与Redis相同的计算Slot的算法,解析到具体的命令后,根据Key所属的slot,将其放到对应的队列中(slot%QueueSize)。因此同一个Slot的数据是串行写入,不同slot的数据可以并行写入,不会出现时序错乱的行为。

2.串并转换

针对问题2,Redis-sync会在并行和串行模式之间进行转换。比如收到FLUSHDB命令,这是需要将FLUSHDB命令前的命令都执行完,再执行FLUSHDB命令。

3.定期上报

针对问题3,Redis-sync会定期将已发送给存储层的aof的Version持久化到存储层。如何Redis-sync故障,首先从存储层获取上次已发送的位置,然后向对应的Redis节点发送psync,请求同步。

4.数据自动路由

针对问题4,Redis-sync会定期从存储层获取Slot到Tendis节点的映射关系,并且维护这些Tendis节点的连接池。请求和颐酒店危机公关声明截图从缓存层到达,然后计算请求所属的slot,然后发送到正确的Tendis节点。

存储层Tendis Cluster

Tendis是兼容Redis核心数据结构与协议的分布式高性能KV数据库,主要具有以下特性:

1.兼容Redis协议

完全兼容redis协议,支持redis主要数据结构和接口,兼容大部分原生Redis命令。

2.持久化存储

使用rocksdb作为存储引擎,所有数据以特定格式存储在rocksdb中,最大支持PB级存储。

3.去中心化架构

类似于redis cluster的分布式实现,所有节点通过gossip协议通讯,可指定hashtag来控制数据分布和访问,使用和运维成本极低。

4.水平扩展

集群支持增删节点,并且数据可以按照slot在任意两节点之间迁移,扩容和缩容过程中对应用运维人员透明,支持扩展至1000个节点。

5.故障自动切换

自动检测故障节点,当故障发生后,slave会自动提升为master继续对外提供服务。

腾讯云超火开源数据库产品架构揭秘

上一篇:Shopify:如何评估最适合你业务的电商平台?
下一篇:敦煌网:评价修改与删除


版权声明:以上主题为“腾讯云超火开源数据库产品架构揭秘"的内容可能是本站网友自行发布,或者来至于网络。如有侵权欢迎联系我们客服QQ处理,谢谢。
相关内容
推荐内容
扫码咨询
    腾讯云超火开源数据库产品架构揭秘
    打开微信扫码或长按识别二维码

小提示:您应该对本页介绍的“腾讯云超火开源数据库产品架构揭秘”相关内容感兴趣,若您有相关需求欢迎拨打我们的服务热线或留言咨询,我们尽快与您联系沟通腾讯云超火开源数据库产品架构揭秘的相关事宜。

关键词:腾讯云超火开源数据库产

关于 | 业务 | 案例 | 免责 | 隐私
客服邮箱:sales@1330.com.cn
电话:400-021-1330 | 客服QQ:865612759
沪ICP备12034177号 | 沪公网安备31010702002418号