文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

一次教科书级别的Redis高可用架构设计实践

2024-12-11 19:38

关注

1、概述

Qunar Redis 集群是一个分布式的高可用架构,整个架构主要由以下几个重要部分组成:

2、架构原理图

3、客户端实现

1)当客户端根据 Redis 集群的 namespace 建立连接时,会先从 zk 中查找/config_addr 节点, 该节点下存放的是配置中心集群的实例信息,从中随机选择一个数据库实例进行连接。

2)在配置中心的特定库表中,根据 Redis 的 namespace 查询集群的节点的连接配置,然后建立 Redis 连接。

3)客户端建立 Redis 连接后,会启动了两个线程:

客户端与其他组件的关系示意图如下:

4、数据分片方法

开发人员提交 Redis 集群申请工单信息后,DBA 会依据工单中的内存大小、QPS 大小等几项主要的数据,规划集群分片节点数量为 N,所有节点平均分配 0~4294967295 范围内的值,即共有 2 的 32 次方个 key 的值,某一个 key 使用 murmurhash2 算法计算哈希值后,只会落在集群的一个节点上。

分片节点示意图如下:

分片节点信息在配置中心的存储信息如下:

5、架构特点

Quanr Redis 高可用架构具有以下特点:

6、架构局限性

Quanr Redis 高可用架构具有以下局限性:

二、安全机制

Redis 被设计成仅供可信环境下的可信用户才可以访问,并没有最大化的去优化安全方面,而是尽量可能的去优化高性能和易用性,因此 Redis 没有类似关系型数据库那样严格的权限控制,因此将 Redis 实例直接暴露在网络上或者让不可信的用户直接访问 Redis 的 TCP 端口,是非常危险的行为。

为了提高 Redis 使用的安全性,去哪儿网使用的 Redis Server 是在官方 Redis 4.0.14 版本上进行了部分的源代码改造,增加了一个白名单参数 trustedip,屏蔽了部分高危指令,除了 trustedip 中配置的 IP 之外,任何其他客户端连接都无法执行这些高危指令,同时为了提高 Redis 的性能,对主从实例进行了差异性配置。

1、clientcipher和IP白名单

Qunar Redis 客户端并没有直接通过 TCP 方式去连接 Redis 实例,而是首先要通过集群 namespace 和该集群唯一的 clientcipher 的验证,然后从配置中心获取真正的连接信息后,才可以连接 Redis 实例。同时白名单机制对客户端请求中的高危指令进行过滤,避免对线上 Redis 执行不合理的操作,进一步加强了其安全性。

IP 白名单功能涉及修改代码的地方:

1)在 config.c 文件的 configGetCommand 方法中增加参数 trustedip 

  1. void configGetCommand(client *c) {  
  2. robj *o = c->argv[2];  
  3. void *replylen = addDeferredMultiBulkLength(c);  
  4. char *pattern = o->ptr;  
  5. char buf[128];  
  6. int matches = 0 
  7. serverAssertWithInfo(c,o,sdsEncodedObject(o));  
  8. ...  
  9.   
  10. if (stringmatch(pattern,"trustedip",0)) {  
  11. sds buf = sdsempty();  
  12. int j;  
  13. int numips;  
  14. numips = server.trusted_ips.numips;  
  15. for (j = 0; j < numips; j++) { 
  16. buf = sdscat(buf, server.trusted_ips.ips[j]);  
  17. if (j != numips - 1)  
  18. buf = sdscatlen(buf," ",1);  
  19.  
  20. addReplyBulkCString(c,"trustedip");  
  21. addReplyBulkCString(c,buf);  
  22. sdsfree(buf);  
  23. matches++;  
  24.  
  25. setDeferredMultiBulkLength(c,replylen,matches*2);  

2)在 server.c 文件的 processCommand 方法中增加对 issuperclient 的认证 

  1. typedef struct trustedIPArray {  
  2. int numips;  
  3. sds* ips;  
  4. } trustedIPArray; 

3)在 networking.c 文件中增加 isTrustedIP 方法 

  1.   
  2. int isTrustedIP(int fd) {  
  3. char ip[128];  
  4. int i, port;  
  5. anetPeerToString(fd,ip,128,&port); 
  6. if (strcmp(ip, "127.0.0.1") == 0) {  
  7. return 1;  
  8.  
  9. for (i = 0; i < server.trusted_ips.numips; i++) {  
  10. if (strcmp(ip, server.trusted_ips.ips[i]) == 0) {  
  11. return 1;  
  12.  
  13.  
  14. return 0;  

4)在 networking.c 文件的 createClient 方法中增加 issuperclient 的设置 

  1. client *createClient(int fd) {  
  2. client *c = zmalloc(sizeof(client));  
  3.   
  4. if (fd != -1) {  
  5. anetNonBlock(NULL,fd);  
  6. anetEnableTcpNoDelay(NULL,fd);  
  7. if (server.tcpkeepalive)  
  8. anetKeepAlive(NULL,fd,server.tcpkeepalive);  
  9. if (aeCreateFileEvent(server.el,fd,AE_READABLE,  
  10. readQueryFromClient, c) == AE_ERR)  
  11.  
  12. close(fd);  
  13. zfree(c);  
  14. return NULL;  
  15.  
  16. ...  
  17.   
  18. if (isTrustedIP(fd)) {  
  19. c->is_super_client = 1 
  20. } else {  
  21. c->is_super_client = 0 
  22.  
  23. ...  
  24. return c;  

5)在 server.c 文件的 processCommand 方法中增加对 issuperclient 的认证 

  1. int processCommand(client *c) {  
  2.  
  3. if (!strcasecmp(c->argv[0]->ptr,"quit")) {  
  4. addReply(c,shared.ok);  
  5. c->flags |= CLIENT_CLOSE_AFTER_REPLY;  
  6. return C_ERR;  
  7.  
  8. ...  
  9.   
  10.   
  11. if (!c->is_super_client && server.requirepass && !c->authenticated && c->cmd->proc != authCommand)  
  12. ...  
  13. return C_OK;  

6)在 db.c 文件中增加 checkCommandBeforeExec 方法 

  1.   
  2. int checkCommandBeforeExec(client *c) {  
  3. if (c->is_super_client || (server.masterhost && (c->flags & CLIENT_MASTER))) {  
  4. return 1;  
  5.  
  6. addReplyError(c,"No permission to execute this command");  
  7. return 0;  

2、屏蔽高危指令

通过修改 Redis 源代码,在 Server 端屏蔽部分危险指令,规定只有通过白名单检查的客户端连接才可以执行这些指令。在执行高危指令前进行检查,如需对 save 指令进行屏蔽,可对 rdb.c 文件的 saveCommand 方法的第一行增加 checkCommandBeforeExec 检查。 

  1. void saveCommand(client *c) {  
  2. if (!checkCommandBeforeExec(c)) return;    
  3. if (server.rdb_child_pid != -1) {  
  4. addReplyError(c,"Background save already in progress");  
  5. return;  
  6.  
  7. rdbSaveInfo rsi, *rsiptr;  
  8. rsiptr = rdbPopulateSaveInfo(&rsi);  
  9. if (rdbSave(server.rdb_filename,rsiptr) == C_OK) { 
  10. addReply(c,shared.ok);  
  11. } else {  
  12. addReply(c,shared.err);  
  13.  

屏蔽的高危指令有:

在 Redis 源代码涉及这些指令的地方,都需要加上 checkCommandBeforeExec 方法进行检查。

3、配置优化

针对集群各个节点的主从实例进行差异化配置,由于每个节点只有主库对外提供服务,为了最大限度的提高主库的并发能力,一些比较耗时的操作可以放到从库去执行。

几项主要的配置如下:

当 Redis 集群部署完之后,会有定时任务去检查服务器上各个 Redis 实例的角色,根据角色的不同修改相关的配置参数,同时将修改后的持久化到配置文件。

三、自动化运维

初始化系统环境

在 Redis 服务器上部署集群之前,首先需要初始化系统环境,将这些环境配置添加到 Redis 的 rpm 打包程序的 spec 文件中,安装 Redis 软件包时会自动更改相关配置,主要的系统环境参数有以下几个: 

  1. sed -i -r '/vm.overcommit_memory.*/d' /etc/sysctl.conf  
  2. sed -i -r '/vm.swappiness.*/d' /etc/sysctl.conf  
  3. sed -i -r '/vm.dirty_bytes.*/d' /etc/sysctl.conf  
  4. echo "vm.overcommit_memory = 1>> /etc/sysctl.conf  
  5. echo "vm.swappiness = 0>> /etc/sysctl.conf  
  6. echo "vm.dirty_bytes = 33554432>> /etc/sysctl.conf  
  7. /sbin/sysctl -q -p /etc/sysctl.conf  
  8. groupadd redis >/dev/null 2>&1 || true  
  9. useradd -M -g redis redis -s /sbin/nologin >/dev/null 2>&1 || true  
  10. sed -i -r '/redis soft nofile.*/d' /etc/security/limits.conf  
  11. sed -i -r '/redis hard nofile.*/d' /etc/security/limits.conf  
  12. echo "redis soft nofile 288000" >> /etc/security/limits.conf  
  13. echo "redis hard nofile 288000" >> /etc/security/limits.conf  
  14. sed -i -r '/redis soft nproc.*/d' /etc/security/limits.conf  
  15. sed -i -r '/redis hard nproc.*/d' /etc/security/limits.conf  
  16. echo "redis soft nproc unlimited" >> /etc/security/limits.conf  
  17. echo "redis hard nproc unlimited" >> /etc/security/limits.conf  
  18. echo never > /sys/kernel/mm/transparent_hugepage/enabled 

2、统一运维管理工具

Qunar Redis 集群的统一管理套件,封装了系统环境初始化、实例安装、实例启动、实例关闭、监控报警、定时任务等脚本,实现了监控、统计、注册等自动化操作。 

  1. /etc/cron.d/appendonly_switch  
  2. /etc/cron.d/auto_upgrade_toolkit  
  3. /etc/cron.d/bgrewriteaof  
  4. /etc/cron.d/check_maxmemory  
  5. /etc/cron.d/dump_rdb_keys  
  6. /etc/cron.d/rdb_backup  
  7. /etc/profile.d/q_redis_path.sh  
  8. /xxx/collectd/etc/collectd.d/collect_redis.conf  
  9. /xxx/collectd/lib/collectd/collect_redis.py  
  10. /xxx/collectd/share/collectd/types_redis.db  
  11. /xxx/nrpe/libexec/q-check-redis-cpu-usage  
  12. /xxx/nrpe/libexec/q-check-redis-latency  
  13. /xxx/nrpe/libexec/q-check-redis-memory-usage  
  14. /xxx/nrpe/libexec/q-check-zookeeper-ruok  
  15. /xxx/redis/tools/cron_appendonly_switch.sh  
  16. /xxx/redis/tools/cron_bgrewrite_aof.sh  
  17. /xxx/redis/tools/cron_check_maxmemory.sh  
  18. /xxx/redis/tools/cron_dump_rdb_keys.sh  
  19. /xxx/redis/tools/cron_rdb_backup.sh  
  20. /xxx/redis/tools/dump_rdb_keys.py  
  21. /xxx/redis/tools/redis-cli5  
  22. /xxx/redis/tools/redis-latency  
  23. /xxx/redis/tools/redis_install.sh  
  24. /xxx/redis/tools/redis_start.sh  
  25. /xxx/redis/tools/redis_stop.sh 

3、单机多实例多版本部署

Qunar Redis 的安装工具包支持单机多实例安装,安装脚本提供选项和配置文件模板,可以自定义安装不同版本的 Redis,目前支持的 Redis Server 版本有 2.8.6、3.0.7 以及 4.0.14。 

  1.   
  2.  
  3. ├── multi  
  4. │ ├── server_2800   
  5. │ │ ├── bin  
  6. │ │ └── utils  
  7. │ ├── server_3000   
  8. │ │ ├── bin  
  9. │ │ └── utils  
  10. │ └── server_4000   
  11. │ ├── bin  
  12. │ └── utils  
  13. ├── redis10088   
  14. │ ├── bin  
  15. │ └── utils  
  16. ├── redis10803   
  17. │ ├── bin  
  18. │ └── utils  
  19. ├── redis11459   
  20. │ ├── bin  
  21. │ └── utils  
  22.   
  23. Usage: redis_install.sh -P <port> -v [2.8|3.0|4.0] -p <password> -m <size>  
  24. 必选参数:  
  25. -P redis端口  
  26. -p redis密码  
  27. -v 将要安装的redis版本,强烈推荐4.0版本  
  28. -m redis实例允许的最大内存大小,单位是G  
  29. 可选参数:  
  30. --cluster 集群模式,version>=3.0  
  31. --testenv 测试环境  
  32. example:  
  33. sudo redis_install.sh -P 6379 -v 4.0 -m 20 -p 1qaz2wsx 

4、使用git管理Redis哨兵

使用 git 集中管理所有的哨兵配置,一个地方发生变更,哨兵集群的所有服务器同时拉取进行同步更新。同时详细的 commit log,方便跟踪配置文件修改历史。Qunar Redis 哨兵具有以下特点:

5、运维操作平台化

以上几项规范统一的标准化流程,为 Qunar Redis 的整个运维平台化提供了有力的支撑,目前 Qunar Redis 的 90% 以上的运维操作都实现了平台自动化,包括工单申请及审核、集群部署、实例迁移、集群垂直伸缩、不同维度(服务器、集群、实例)的信息查看等,下面主要介绍下 Qunar Redis 集群部署和实例迁移的实现过程。

集群部署

Qunar Redis 集群部署时主要有以下步骤:

1)开发人员通过平台提交集群申请工单发起流程,TL 审核完成后流程扭转到 DBA。

2)DBA 根据申请工单的信息规划集群规模,如节点个数、内存大小、部署机房、Redis 版本等。

3)根据集群规划在 Redis 集群部署页面填写部署信息。

4)提交部署信息后平台会自动筛选资源空闲的服务器进行集群部署。

5)集群部署完成后会在在 Qtalk 上通知 DBA,集群的 clientcipher 会通过邮件方式通知开发人员,同时会将集群部署情况推送到公司运维事件平台,保留操作记录。

实例迁移

运维过程中实例迁移主要分为两大类:

1)部分实例迁移。当某台服务器的可用资源不足时,将这台机器上的部分实例迁移到其他资源比较空闲的服务器上。在页面输入实例的源主机和目前主机,提交后会自动生成迁移任务。

2)整机实例迁移。主要是替换过保服务器或者服务器需要停机维护时,将该机器上的所有实例自动迁移到其他资源比较空间的服务器上。在页面输入需要迁移的主机名,提交后会自动生成迁移任务。

迁移任务开始后,整个迁移过程无须人工介入,会自动更新执行进度并输出日志。

 

 

来源:DBAplus社群内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯