欧易

欧易(OKX)

国内用户最喜爱的合约交易所

火币

火币(HTX )

全球知名的比特币交易所

币安

币安(Binance)

全球用户最多的交易所

这些年,我们一起追过的缓存数据库

时间:2022-10-09 14:53:28 | 浏览:434

人生不过如此,且行且珍惜。自己永远是自己的主角,不要总在别人的戏剧里充当着配角。我以林语堂的《人生不过如此》中一句话来开篇。背景在互联网高速发展、快速演化的时代,想必在你的系统架构设计中,缓存服务是不是已经成为必不可少的一层,丰富的数据结构


人生不过如此,且行且珍惜。自己永远是自己的主角,不要总在别人的戏剧里充当着配角。

我以林语堂的《人生不过如此》中一句话来开篇。

背景

在互联网高速发展、快速演化的时代,想必在你的系统架构设计中,缓存服务是不是已经成为必不可少的一层,丰富的数据结构、高性能的读写、简单的协议,让缓存数据库很好的承担起关系型数据库的上层。畅途网为了解决节假日或高峰期的车次查询、抢票等大数据量的访问请求,很早以前就引进了 Redis,来作为数据库的上游缓存层,缓解底层数据库的读写压力。

REDIS HA 架构

世界上唯一可以不劳而获的就是贫穷,唯一可以无中生有的是梦想。没有哪件事,不动手就可以实现。世界虽然残酷,但只要你愿意走,总会有路;看不到美好,是因为你没有坚持走下去。人生贵在行动,迟疑不决时,不妨先迈出小小一步。前进不必遗憾,若是美好,叫做精彩;若是糟糕,叫做经历。**——林语堂《人生不过如此》

2014 年 10 月,为了避免单点故障,我们尝试在生产环境的 Redis 主从架构中,引入了 Redis Sentinel,实现了 Redis 服务的 failover。当 Redis-Master 主机异常宕机或 Redis-Master 服务异常崩溃时,原有的 Redis-Slave 自动升级为 master 角色,当原有 Redis-Master 恢复后,自动恢复为 slave 角色。

由于 Redis Sentinel 只能做到 Redis 服务级别的切换,无法做到 IP 地址的切换,无法完全满足现网系统架构的需要,我们又尝试在 HA 架构中加入了负载均衡器设备,引用了浮动 IP,所有应用程序访问浮动 IP,IP 地址的切换操作由负载均衡器设备来实现。


Redis Sentinel 配置文件


测试小结:

主 Redis 服务器:redis-sent-0-17

从 Redis 服务器:redis-sent-0-18

域名
redis-sent.cache.changtu.pvt

    重启 redis-sent-0-17 节点,60 秒后,redis-sent-0-18 节点成为 master,用户访问 redis-sent.cache.changtu.pvt 域名 redis 服务恢复正常,2 分钟后,redis-sent-0-17 节点重启完成,自动成为 slave;

    重启 redis-sent-0-18 节点,60 秒后,redis-sent-0-17 节点成为 master,用户访问 redis-sent.cache.changtu.pvt 域名 redis 服务恢复正常,2 分钟后,redis-sent-0-18 节点重启完成,自动成为 slave。

对应用程序的要求

    缓存应用服务统一通过域名访问。

    缓存应用服务对 Redis 域名的访问有断点重连的功能。

2015 年新增 2 台 Redis Sentinel 服务器,负责平台所有 Redis 服务器集群管理。并对平台现有 Redis 服务进行改造,逐步升级为 Redis HA 架构。

CODIS 分布式集群

你可以一辈子不登山,但你心中一定要有座山。它使你总往高处爬,它使你总有个奋斗的方向,它使你任何一刻抬起头,都能看到自己的希望。——林语堂《人生不过如此》

随着畅途网业务量上涨,数据量猛增,单点的 Redis 容量受限于服务器的内存,Redis 主从架构已经力不从心了。在业务系统对性能要求逐渐提高情况下,我们更希望将数据能存在内存中,本地持久化,而不希望写入数据库中。虽然当时用 SSD 将内存换成磁盘,以获取更大的容量,但是我们更想如何将 redis 变成一个可以水平扩展的分布式缓存服务?

在 Codis 发布之前,业界只有 Twemproxy,Twemproxy 本身是一个静态的分布式 Redis 方案,进行扩容、缩容对运维要求非常高,而且很难做到平滑的扩缩容。Codis 的目标就是尽量兼容 Twemproxy,并且加上数据迁移的功能以实现扩容和缩容,最终替换 Twemproxy。本文省略了对 Twemproxy 的介绍。

REDIS-CLUSTER

与 Codis 同时期发布的官方 redis-cluster,采用 P2P 的模式,完全去中心化架构, 其实我们花了大精力研究测试过,由于当时对 failover 判断方式提出怀疑,高耦合的模块设计思想、客户端问题、不太友好的维护等方面, 我司目前没有投入生产,没有了实际的生产维护经验,我先不发表看法。抱拳,我知道在缓存数据库里最不应该缺少的就是 Redis-cluster 了,以后有机会单独介绍吧!


容我感叹一下,别指望所有的人都能懂你,因为萝卜白菜,各有所爱。你做了萝卜,自然就做不成青菜。

好了,回归正题,先简单介绍一下 Codis,由豌豆荚于 2014 年 11 月开源,基于 Go 和 C 开发,引用作者的一段原话, Codis 采用一层无状态的 proxy 层,将分布式逻辑写在 proxy 上,底层的存储引擎是 Redis,数据的分布状态存储于 zookeeper(etcd) 中,底层的数据存储变成了可插拔的部件。各个部件是可以动态水平扩展的,尤其无状态的 proxy 对于动态的负载均衡,对业务而言完全是透明的。*


核心组件说明

1. ZooKeeper:

用来存放数据路由表和 Codis-proxy 节点的元信息,Codis-config 发起的命令都会通过 ZooKeeper 同步到各个存活的 Codis-proxy 中。

2. Codis-Proxy :

是客户端连接的 Redis 代理服务,本身是没状态的,Codis-proxy 实现了 Redis 协议,对于一个业务来说,可以部署多个 Codis-proxy, 提供连接集群 Redis 服务的入口。

3. Codis-Config :

是 Codis 的集成管理工具,支持添加 / 删除 Redis 节点、添加 / 删除 Proxy 节点、以及发起数据迁移等操作,Codis-config 还自带了 http server,会启动 dashboard,用户可以在 WEB 上监控 Codis 集群的状态。

4. Codis-Server:

是 Codis 项目维护的一个 Redis 分支,基于 redis-2.8.21 分支开发,增加了额外的数据结构,以支持 slot 有关的操作以及数据迁移指令。

5.Pre-Sharding 技术

Codis 采用 Pre-Sharding 的技术来实现数据的分片, 默认分成 1024 个 slots (0-1023), 对于每个 key 来说, 通过以下公式确定所属的 Slot Id : SlotId = crc32(key) % 1024,每一个 slot 都会有一个特定的 server group id 来表示这个 slot 的数据由哪个 server group 来提供。

在 2016 年 6 月左右,我们引进了 Codis(当时版本是 3.0,并没有 Redis-Sentinel、Codis-fe 等组件,1 年后,才升级到 3.2 的,文章主要以 3.0 版本为背景),首先介绍一下基础环境。


系统架构

在公司硬件资源有限条件下,我们计划用 6 台服务器部署 Codis,简单分了两层,Codis-Proxy 层和 Codis-Server 层。

    Codis-Proxy 层用了三台配置相对较低服务器,部署了 ZooKeeper、Codis-Proxy、Keepalived、LVS 等 ,3 个节点都做了负载均衡。

    Codis-Server 层用来三台配置相对较高的服务器,并用 SSD,3 个 Codis-group,每个 group 有一主一从,交叉部署,每个主从分配 30G 内存。



我们分别通过 jredis 编写测试程序和使用 redis-benchmark 工具模拟压力测试(请求量:1000 万~1 亿,并发数:1000~50000,长度:固定 / 可变):

    在性能方面:基本上能达到我们的预期,理想情况 Codis 性能值能达到 50~60K OP/S,各个 codis-group 中 master-slave 实例数据能实时同步,详情可以参考《Codis 高可用集群性能测试报告 _20160315》。

    数据一致性问题:一方面,Codis 的 HA 并不能保证数据完全不丢失,由于 M-S 是异步复制,当 master 节点异常或崩溃,将 slave 切换成 master 后,刚刚没来得及同步的数据就会丢失。另一方面,Codis 支持的 mget/mset 命令是无法保证单点时的原子语义的,如果 mset 指定 KEY 分布在不同 slot 上,从而导致 KEY 在不同机器上,造成要不一起成功,不要一起失败。所以对于分布式事务的问题,这是一个痛点。在实际场景中,也有人使用了 lua 脚本以扩展 Redis 的功能,虽然 Codis 支持,但是并不保证你的脚本操作的数据是否在正确的节点执行,仅仅起到一个转发功能。如果你并不能保证 lua 操作的 KEY 是否在同一个机器上,Codis 只能将这个脚本分配到参数列表中的第一个 key 的机器上执行。

    不支持命令列表,参考

    https://github.com/CodisLabs/codis/blob/release3.2/doc/unsupported_cmds.md

    Redis 修改部分(增加若干指令),参考

    https://github.com/CodisLabs/codis/blob/release3.2/doc/redis_change_zh.md

倔强的青铜

于是组织研发同事进行多次分析讨论,并提出了对缓存服务进行接口改造,经过 2 个多月的辛劳,取得了很大进展,让我们 Codis 项目顺利上线迈开了重要一步,打断一下,容我在此特别感谢一下同事王慧,在他的主导下,完成公司绝大部分缓存服务接口改造工作。

几点改造思路

1. 缓存服务分类。

    针对业务缓存服务不容许数据丢失,在现有的逻辑中,Codis 和数据库都会保留,优先从 Codis 读取,如读取不到时,会从后端数据库里读取。

    针对车次、合作方缓存服务,由于数据量大,拉取频率高的数据,只会从 Codis 里读取。

2. 对缓存服务进行接口改造,新增基础缓存服务层,将生产的 Redis/Codis 相关的服务纳入基础缓存服务进行统一管理。


    制定一套标准 KEY 命名、管理规范,包括数据类型的选择、长度、过期时间等。我们会统一在后台管理系统公示,限定新数据的规则,限制一切不合规范的行为。

    在基础缓存服务层,对部分 Codis 不支持的命令进行改写,规范 Redis/Codis 日常操作。

    统计热点数据,维护热点数据,在基础缓存服务层上假设二级缓存,作为热点数据的快速通道。

3.SLOT 的分配

哈希算法

Codis 采用 Pre-sharding 的技术来实现数据的分片, 默认分成 1024 个 slots (0-1023), 对于每个 key 来说, 通过以下公式确定所属的 Slot Id : SlotId = crc32(key) % 1024。例如 pub_cty_ct018 根据算法得出的值是 997。


key 值重定向分配

比如你有一个脚本是操作某个用户的多个信息,如 uid1age,uid1sex,uid1name 形如此类的 key,如果你不用 hashtag 的话,这些 key 可能会分散在不同的机器上,如果使用了 hashtag(用花括号扩住计算 hash 的区域):{uid1}age,{uid1}sex,{uid1}name,这样就保证这些 key 分布在同一个机器上。这个是 twemproxy 引入的一个语法,我们这边也支持了。

以 pub_cty 为例,通过 crc32hash 算法得出,key 存放在 237 slot 中,类似测试了{pub_cty}_ct01,{pub_cty}_ct02…{pub_cty}_ctnn 都存放在 237 slot 中。第一,有了 hashtag 算法支持,我们可以对特定需求的 key 做一些特需的规划,将这些特殊的 key 有序的存放在 codis slot 中,保证 mget/mset, 以及 lua 脚本正常执行。我们目前大概管理 200 多个 redis 键,统一锁定到一个 codis-server(slot)中。第二,在某些极端情况(不希望发生),如某 codis-group 中的 master 异常或崩溃时,我们从程序设计角度,尽可能对出现的无法进行操作 KEY 的行为做一些 " 某种意义上 " 保护。譬如,当某 codis-group 的 maser 宕机时,对 codis 进行写操作,如果对应的 key 落到宕机的主机上,会得到异常或者错误,可以通过捕获异常信息,将异常的 key 通过改变 key 名的规则将其存放到其他 codis-group 上。同理,如果是读取宕机主机上的 key 数据时,将其引导到调整后的 key 上,在一定程度上保障 codis 的完整性(不保障数据不丢失,只保证业务系统操作缓存数据完整性)。

有点意思的整改

在长达几年的迭代演变过程中,维护团队推动多次缓存服务架构的升级与优化,缓存服务逐渐完善和稳定。 记下了一些“有点意思”的整改,提供大家参考。

热点数据

统计缓存热点数据,在基础缓存服务层上假设二级缓存,作为热点数据的快速通道,具备可动态获取,最快访问,少变化的特点 。

根据缓存服务各主、子键关系,使用 index_{主键}的方式来作为管理主子键关系的 SortedSet 集合,统计数据的使用频率,抽取 Top100 的数据,作为热点数据。对这批数据进行分析,结合数据的改动频率,制定这批数据缓存在内存中的时长。


二级缓存设计

缓存数据列表生成与维护

内存缓存数据的 key 列表由缓存服务生成和维护,Key 列表包括后台手动配置(如,10 个)和系统根据使用热度生成(如,20 个)共同组成,其中 cache-manager 的 jar 包只负责对该数据使用,通过定时任务获取 codis 中的前 20 位和后台手动配置的相关数据,期间要保证获取到数据的有效性。


维护本地内存中的数据

自然统计内存缓存: 用 sortedSet 集合,统计各主键下的所有键 Get 的次数,汇总成 score_{主键}方式的集合。利用 ZIncrby 命令统计对应的子键的次数,最终汇总每个主键,统计出 Top100 的 key,利用 zunionstore 命令将信息统计汇总作为内存缓存的基础,此集合内数据均从内存中获取。

管理类内存缓存: 分析和统计项目主流程的关键的基础缓存数据保存到内存中, 保障对应区域的数据获取与缓存时间,在离开数据源后能够最大程度的展现畅途网的功能。

在发生手动更新时,对内存中对应的主键进行更新

在发生更新时,由后台发起,在缓存服务向 codis 中置入标志位,各客户端在定时任务中获取标志位,如果标志位(cache_memory_update_flag)为 Y,则清空内存和 Key 规则表,等到下一个更新周期来临重新获取数据。

总结

多年后,再回想年少时的迷茫和执著,或许原因都记不得了。青春就是让你张扬的笑,也给你莫名的痛。——林语堂《人生不过如此》

经过大半年的时间测试、缓存服务接口改造,在 2016 年 9 月份,赶在国庆前,我们的 Codis3.0 上线了,在车次查询等方面,有了质的飞越,尤其节假日或高峰期期间,平滑的扩缩容、数据迁移、高可用等方面展示出巨大优势。


三个 codis_proxy 节点的均衡情况:

1 年后,2018 年 8~9 月份,我们将 Codis 升级到 3.2 的,由之前 6 台服务器,扩展到 7 台,实际上多一台 Codis-web 节点,独立承担 Codis-fe、Codis-dashboard 等组件。对于 Redis-Sentinel、Codis-fe 等组件的引进,解决了运维人员很多问题,在此不再描述,有兴趣的可以参考。

https://github.com/CodisLabs/codis/blob/3.2.2/doc/tutorial_zh.md


目前 Codis 作为畅途网最为核心的缓存层,一如既往的稳定输出,肩负起它的神圣使命!

相关资讯

数据库:什么是数据库,数据库管理系统,数据库系统,数据库管理员?

数据库 : 数据库(DataBase 简称 DB)就是信息的集合或者说数据库是由数据库管理系统管理的数据的集合。数据库管理系统 : 数据库管理系统(Database Management System 简称 DBMS)是一种操纵和管理数据库

数据库超详细讲解,MySQL数据库的简介、及常用数据库介绍

数据库简介数据库:顾名思义,就是数据的仓库,它是长期存储在计算机内,有组织的、可共享的数据的集合。数据库管理系统(DBMS: 用来对数据进行存储、管理等操作的软件)数据库分类数据库通常分为:层次式数据库、网络式数据库和关系式数据库三种。而不

什么是数据库DataBase?数据库和数据记录的概念简单讲解

大家好,在讲数据库之前,我用了很长的时间,和大家分享了很多VBA方面的一些知识点,其中很多是我个人对VBA的理解。从这讲开始我们要在原先的基础上深入的讲解一些VBA的提高利用,就是我们要开始讲解的数据库。在《VBA与数据库利用》中我会讲解到

数据库看这一篇就够了!MySQL、Redis、Mongodb等常见数据库教程

数据库是系统健康和用户行为健康的重要指标。数据库中的异常行为可能会引起应用程序中的问题。或者当应用程序中存在异常时,都可以使用数据库指标来帮助加快调试过程。先来认识下市面上常用的数据库:关系型数据库1. MySQL数据库2. Microso

为什么要使用数据库,什么是数据库

1、为什么要使用数据库持久化(persistence):把数据保存到可掉电式存储设备中以供之后使用。持久化的大多数时候是将内存中的数据存储在数据库中,当然也可以存储在磁盘文件、XML数据文件中。方便管理数据(例如:快速的检索等)2、什么是数

重塑数据库发展路径业界聚焦我国数据库产业发展

人民网北京12月27日电 (记者乔雪峰)近日发布的《软件和信息技术服务业十四五规划》中,明确提出我国“十四五”时期要加快实施国家软件发展战略,不断提升软件产业创新活力,聚力攻坚基础软件,有效满足多层次、多样化市场需求,为构建以国内大循环为主

常见的数据库类型及各种数据库特点的简单介绍

大家好,在上一讲中,讲了数据库的概念及表的概念,通过上讲的内容,我们大概了解了一些数据库的基本知识。其实,在我的日常生产中,数据库和我们也是息息相关的,当我们打电话、上网、去银行交易等等,都要访问不同的数据库,这些数据库各有自己的特点,但都

数据库篇-第一章:数据库基本概念

基础知识学习,面试必备,关注吧 骚年01 第一,什么是数据库?维基百科上是这样定义的:所谓“数据库”是以一定方式储存在一起、能予多个用户共享、具有尽可能小的冗余度、与应用程序彼此独立的数据集合。一个数据库由多个表空间(Tablespace)

C++基础语法梳理:数据库!带你深入浅出了解数据库

基本概念数据(data):描述事物的符号记录称为数据。数据库(DataBase,DB):是长期存储在计算机内、有组织的、可共享的大量数据的集合,具有永久存储、有组织、可共享三个基本特点。数据库管理系统(DataBase Management

数据库指南:一文让你浅显易懂地了解数据库

在数据分析的技能中,数据库与SQL会是性价比最高的技能之一。数据库是逻辑上的概念,它是一堆互相关联的数据,放在物理实体上,是一堆写在磁盘上的文件,文件中有数据。这些最基础的数据组成了表(table),我们把它想象成一张Excel的sheet

数据库技术新版图-Serverless数据库

数据库的发展已走过近四十年,作为基础软件之一,数据库称得上是一个“古老”的领域。而随着新技术的涌现,这个传统的领域也正不断焕发出新的生机。如果说云时代的到来推动了数据库的变革,那么,与 Serverless 的结合,则再次为数据库的发展添了

什么是数据库?用最简单的方法讲明白数据库

数据库基本概念数据库是一个以某种有组织的方式存储的数据集合。数据库(database)是保存有组织的数据的容器。数据库管理系统(DBMS)是一种数据库软件,MySQL是一种DBMS,即它是一种数据库软件,作者使用的数据库管理系统是MySQL

一文读懂Access数据库,从此不用Access数据库

1992年11月,Microsoft Access 1.0版本发布。同时,这也是Access数据库,第一次进入大家的视野。起初,Access的原名并不叫Access,而叫Cirrus。Ciruus开发于Visual Basic之前,当时的窗

闲聊数据库发展历史三个阶段、分类、数据库规范及趋势

概述数据库(Database)是存储与管理数据的软件系统,就像一个存入数据的物流仓库。在商业领域,信息就意味着商机,取得信息的一个非常重要的途径就是对数据进行分析处理,这就催生了各种专业的数据管理软件,数据库就是其中的一种。当然,数据库管理

数据库行业研究报告:数据库,云化底座,百舸争流

(报告出品方/作者:中信证券,杨泽原、丁奇)报告综述:安全可控势在必行,数据库国产替代加速开展,以党政为代表的国产替代先行,并不断向金融、电信等领域拓展。同时,伴随云计算、大数据技术的快速发展, 云数据库、数据仓库、大数据分析等领域快速增长

友情链接

网址导航 SEO域名抢注宝宝起名网妈妈知道币圈泸州老窖A股本间球杆郑恺影迷网珠穆朗玛峰游玩攻略外国洋酒品牌网勒布朗·詹姆斯球迷网克徕帝钻戒宋仲基影迷网桂林三花酒友网电脑组装教程网豆粕期货行情网贵阳交友相亲网南京旅游网欢乐谷游玩攻略网瑰夏咖啡品鉴网
MYSQL数据库应用网-mysql数据库基础知识、Mysql还原数据库、mysql数据库迁移方案、mysql数据库增删改查、mysql数据备份和恢复、mysql数据迁移工具、mysql数据库迁移详细步骤、mysql数据库存储目录迁移、mysql数据库不停机迁移方法、mysql数据备份和恢复、免费mysql服务器、mysql官网免费版安装教程。
MySQL数据库应用 nincu.cn ©2022-2028版权所有