分析redis的各种使用情景

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
简介: 原文:https://www.zeusro.tech/2019/05/24/redis-on-cloud/

使用docker-compose演示redis的各种使用情景,最后介绍了codiskubernetes方案

总结

模式 特点
单机版-RDB 备份快,但数据可能不完整
单机版-AOF 备份慢,但是数据比较完整
1主N从 读写分离的典范
树状主从(N级缓存) 为了规避主重启导致的大规模全量复制,但是需要维持每一个中间master的健康
主从自动切换(Sentinel) 在主从的基础上加了Sentinel角色,通过Sentinel实现主从的自动切换
集群(N主N从) 基于slot的key分片,客户端支持得不是很多,所以用的人不多

单机版

RDB模式(默认模式)

定期快照模式

version: '3'
services:   
    redis-master: 
        image: redis
        ports: 
        - "12660:6379"
        expose:
          - "6379"
        networks:
        - default        
        entrypoint:
        - redis-server
        volumes:
          - ./data:/data

AOF模式

逐一写入,数据比较完整,文件较大,但恢复较慢

version: '3'
services:   
    redis-master: 
        image: redis
        ports: 
        - "12660:6379"
        expose:
          - "6379"
        networks:
        - default        
        entrypoint:
        - redis-server 
        - --appendonly yes
        volumes:
          - ./data:/data

主从复制版

1主N从

这种模式简单粗暴,但是master一旦重启,多从节点全量复制,IO将会比较繁重

version: '3'
services:   
    redis-master: 
        image: redis
        ports: 
        - "12660:6379"
        expose:
          - "6379"
        networks:
        - default        
        entrypoint:
        - redis-server 
        - --save 1 1
        volumes:
          - ./data:/data
    redis-slave1: 
        image: redis
        ports: 
        - "12661:6379"
        expose:
          - "6379"        
        networks:
        - default             
        entrypoint:
        - redis-server 
        - --slaveof redis-master 6379
        - --slave-serve-stale-data yes
        #当从机与主机断开连接时,或者当复制仍在进行时,slave仍然会回复client请求, 尽管数据可能会出现过期或者如果这是第一次同步,数据集可能为空。
        - --slave-read-only yes
        #0作为一个特殊的优先级,标识这个slave不能作为master 
        - --slave-priority 100
    redis-slave2: 
        image: redis
        ports: 
        - "12662:6379"
        expose:
          - "6379"            
        entrypoint:
        - redis-server         
        - --slaveof redis-master 6379
        - --slave-serve-stale-data yes
        #当从机与主机断开连接时,或者当复制仍在进行时,slave仍然会回复client请求, 尽管数据可能会出现过期或者如果这是第一次同步,数据集可能为空。
        - --slave-read-only yes
        #0作为一个特殊的优先级,标识这个slave不能作为master 
        - --slave-priority 100

树状主从(N级缓存)

从节点作为主节点.

这种模式规避了单master

version: '3'
services:   
    redis-master: 
        image: redis
        ports: 
        - "12660:6379"
        expose:
          - "6379"
        networks:
        - default        
        entrypoint:
        - redis-server 
        - --save 1 1
        volumes:
          - ./data:/data
    redis-slave1: 
        image: redis
        ports: 
        - "12661:6379"
        expose:
          - "6379"        
        networks:
        - default             
        entrypoint:
        - redis-server 
        - --slaveof redis-master 6379
        - --slave-serve-stale-data yes
        #当从机与主机断开连接时,或者当复制仍在进行时,slave仍然会回复client请求, 尽管数据可能会出现过期或者如果这是第一次同步,数据集可能为空。
        - --slave-read-only yes
        #0作为一个特殊的优先级,标识这个slave不能作为master 
        - --slave-priority 100
        # - --masterauth xxx
    redis-slave2: 
        image: redis
        ports: 
        - "12662:6379"
        expose:
          - "6379"            
        entrypoint:
        - redis-server         
        - --slaveof redis-slave1 6379
        - --slave-serve-stale-data yes
        #当从机与主机断开连接时,或者当复制仍在进行时,slave仍然会回复client请求, 尽管数据可能会出现过期或者如果这是第一次同步,数据集可能为空。
        - --slave-read-only yes
        #0作为一个特殊的优先级,标识这个slave不能作为master 
        - --slave-priority 100
        # - --masterauth xxx

主从自动切换(Sentinel模式)

这时需要引入 Sentinel 的概念

Redis 的 Sentinel 系统用于管理多个 Redis 服务器(instance), 该系统执行以下三个任务:

  1. 监控(Monitoring): Sentinel 会不断地检查你的主服务器和从服务器是否运作正常。
  2. 提醒(Notification): 当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。
  3. 自动故障迁移(Automatic failover): 当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作, 它会将失效主服务器的其中一个从服务器升级为新的主服务器, 并让失效主服务器的其他从服务器改为复制新的主服务器; 当客户端试图连接失效的主服务器时, 集群也会向客户端返回新主服务器的地址, 使得集群可以使用新主服务器代替失效服务器。

默认的Sentinel配置去掉注释后长这样

port 26379
daemonize no
pidfile /var/run/redis-sentinel.pid
logfile ""
dir /tmp
# 监视主服务器,下线master需要2个Sentinel同意
sentinel monitor mymaster redis-master 6379 2
# 30秒内有效回复视为master健康,否则下线
sentinel down-after-milliseconds mymaster 30000
# 故障转移时,从服务器同部数最大值
sentinel parallel-syncs mymaster 1
# 1. 同一个sentinel对同一个master两次failover之间的间隔时间。
# 2. 当一个slave从一个错误的master那里同步数据开始计算时间。直到slave被纠正为向正确的master那里同步数据时。
# 3.当想要取消一个正在进行的failover所需要的时间。  
# 4.当进行failover时,配置所有slaves指向新的master所需的最大时间。不过,即使过了这个超时,slaves依然会被正确配置为指向master,但是就不按parallel-syncs所配置的规则来了。
sentinel failover-timeout mymaster 90000

基本格式是sentinel <选项的名字> <主服务器的名字> <选项的值>

原本我想通过docker-compose up --scale redis-sentinel=3直接启动3个容器,结果发现这容器竟然会修改配置文件,所以只能分开写了

初版

# docker-compose up --scale redis-sentinel=3 虽然可以启动,但是3个容器同时写同一个文件,感觉不是很好
version: '3'
services:   
    redis-master: 
        image: redis
        ports: 
        - "12660:6379"
        expose:
          - "6379"  
        entrypoint:
        - redis-server 
        - --save 1 1
        volumes:
          - ./data:/data
        # 重启策略改为no手动让他宕机模拟主从切换
        restart: "no"
    redis-slave1: 
        image: redis
        ports: 
        - "12661:6379"
        expose:
          - "6379"          
        entrypoint:
        - redis-server 
        - --slaveof redis-master 6379
        - --slave-serve-stale-data yes
        #当从机与主机断开连接时,或者当复制仍在进行时,slave仍然会回复client请求, 尽管数据可能会出现过期或者如果这是第一次同步,数据集可能为空。
        - --slave-read-only yes
        #0作为一个特殊的优先级,标识这个slave不能作为master 
        - --slave-priority 100
        # - --masterauth xxx
    redis-slave2: 
        image: redis
        ports: 
        - "12662:6379"
        expose:
          - "6379"            
        entrypoint:
        - redis-server         
        - --slaveof redis-slave1 6379
        - --slave-serve-stale-data yes
        #当从机与主机断开连接时,或者当复制仍在进行时,slave仍然会回复client请求, 尽管数据可能会出现过期或者如果这是第一次同步,数据集可能为空。
        - --slave-read-only yes
        #0作为一个特殊的优先级,标识这个slave不能作为master 
        - --slave-priority 100
        # - --masterauth xxx
    redis-sentinel:
        image: redis
        expose:
          - "26379"
        entrypoint:
        - redis-server
        - /usr/local/etc/redis/redis.conf
        - --sentinel
        volumes:
        - ./redis-sentinel.conf:/usr/local/etc/redis/redis.conf

最终版:

version: '3'
services:   
    redis-master: 
        image: redis
        ports: 
        - "12660:6379"
        expose:
          - "6379"  
        entrypoint:
        - redis-server 
        - --save 1 1
        volumes:
          - ./data:/data
        # 重启策略改为no手动让他宕机模拟主从切换
        restart: "no"
    redis-slave1: 
        image: redis
        ports: 
        - "12661:6379"
        expose:
          - "6379"          
        entrypoint:
        - redis-server 
        - --slaveof redis-master 6379
        - --slave-serve-stale-data yes
        #当从机与主机断开连接时,或者当复制仍在进行时,slave仍然会回复client请求, 尽管数据可能会出现过期或者如果这是第一次同步,数据集可能为空。
        - --slave-read-only yes
        #0作为一个特殊的优先级,标识这个slave不能作为master 
        - --slave-priority 100
        # - --masterauth xxx
    redis-slave2: 
        image: redis
        ports: 
        - "12662:6379"
        expose:
          - "6379"            
        entrypoint:
        - redis-server         
        - --slaveof redis-slave1 6379
        - --slave-serve-stale-data yes
        #当从机与主机断开连接时,或者当复制仍在进行时,slave仍然会回复client请求, 尽管数据可能会出现过期或者如果这是第一次同步,数据集可能为空。
        - --slave-read-only yes
        #0作为一个特殊的优先级,标识这个slave不能作为master 
        - --slave-priority 100
        # - --masterauth xxx
    redis-sentinel1:
        image: redis
        expose:
          - "26379"
        entrypoint:
        - redis-server
        - /usr/local/etc/redis/redis.conf
        - --sentinel
        volumes:
        - ./redis-sentinel1.conf:/usr/local/etc/redis/redis.conf
    redis-sentinel2:
        image: redis
        expose:
          - "26379"
        entrypoint:
        - redis-server
        - /usr/local/etc/redis/redis.conf
        - --sentinel
        volumes:
        - ./redis-sentinel2.conf:/usr/local/etc/redis/redis.conf
    redis-sentinel3:
        image: redis
        expose:
          - "26379"
        entrypoint:
        - redis-server
        - /usr/local/etc/redis/redis.conf
        - --sentinel
        volumes:
        - ./redis-sentinel3.conf:/usr/local/etc/redis/redis.conf

sentinel启动之后,配置发生了变化

这些内容没了

sentinel monitor mymaster redis-master 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1

变成

sentinel myid 3ae98d6815c1a9b941f8283b7e48bfeef7435905
sentinel deny-scripts-reconfig yes
# Generated by CONFIG REWRITE
sentinel config-epoch mymaster 0
sentinel leader-epoch mymaster 0
sentinel known-replica mymaster 172.24.0.4 6379
sentinel known-sentinel mymaster 172.24.0.7 26379 19ac7e0519e3c30a75e23bac34a7033594256c54
sentinel known-sentinel mymaster 172.24.0.5 26379 c596734a7f55ba2b6c7e3e81562aa6687e45fdeb
sentinel current-epoch 0

之后通过docker psdocker stop手动停掉了master那个容器,sentinel发觉了,并重新选主.

此时通过redis-cli输入info,发现它已经成功变成了可以写入数据的master

# Generated by CONFIG REWRITE
sentinel config-epoch mymaster 1
sentinel leader-epoch mymaster 1
sentinel known-replica mymaster 172.24.0.3 6379
sentinel known-replica mymaster 172.24.0.2 6379
sentinel known-sentinel mymaster 172.24.0.7 26379 19ac7e0519e3c30a75e23bac34a7033594256c54
sentinel known-sentinel mymaster 172.24.0.5 26379 c596734a7f55ba2b6c7e3e81562aa6687e45fdeb
sentinel current-epoch 1

此时重启master,虽然他以server形式启动,但是角色已经自动被贬为slave.

此时master没有变化,所以sentinel的配置内容没有变

集群版(N主N从)

集群基于16384个slot做分片.目前各语言客户端实现比较少.所以用的人不是很多.

在docker中运行时,需要使用host网络模式(--net=host)

redis-trib.rb

redis版本<5时,可以用redis-trib.rb建集群

./redis-trib.rb create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 \
127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005

# 引入新节点
./redis-trib.rb add-node 127.0.0.1:7006 <任意节点IP>:<节点端口>

# 重新分片
./redis-trib.rb reshard <任意节点IP>:<节点端口>

redis-cli

=5直接用redis-cli即可.

redis-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001 \
127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 \
--cluster-replicas 1
redis-cli --cluster reshard 127.0.0.1:7000
redis-cli reshard <host>:<port> --cluster-from <node-id> --cluster-to <node-id> --cluster-slots <number of slots> --cluster-yes
redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7000
# Adding a new node as a replica
redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7000 --cluster-slave
redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7000 --cluster-slave --cluster-master-id 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e
redis-cli --cluster del-node 127.0.0.1:7000 `<node-id>`

集群指令

CLUSTER REPLICATE <master-node-id>
cluster nodes

Kubernetes

个人觉得吧,redis跟Kubernetes不是特别契合.kubernetes本身有网络瓶颈的问题,通过svc去访问,频繁DNS解析也不好对吧.这对于高频访问redis的场景来说是致命的.

而且pod这种易失架构注定了在Kubernetes上面用redis要么用数据卷挂载,要么用主从自动切换模式(纯内存的话至少要1主2从,并且用反亲和度错开彼此的运行节点).

主从和单机版倒好解决,单机的话挂载好数据卷,主从的话,主和从分开2个deploy/statefulset部署即可.

但是集群版就比较麻烦.官方的设计还是偏向于传统二进制人工运维,没有做到云原生

看了一下官方的helm chart,也是用的主从模式.

codis

codis是redis集群没出来之前,豌豆荚团队做的一个方案,通过proxy,隔离了后端的redis集群

优点

  1. 支持Kubernetes
  2. 有web图形界面,方便运维
  3. Redis获得动态扩容/缩容的能力,增减redis实例对client完全透明、不需要重启服务

缺点

  1. 稳定性堪忧
  2. 依赖于国内的豌豆荚团队开发,迭代速度较慢
  3. 原版的docker镜像较大,没有根据组件进行分开
  4. 基于redis 3.x,而且很多原生的redis指令被阉割了
  5. 强依赖注册中心(Zookeeper、Etcd、Fs)

我们用了几个月吧,到后期频繁出现

ERR handle response, backend conn reset

此外,日常观察发现pod退出/重启困难.如果某个group节点全部挂掉的话,整个集群将不可读写.

综上,codis已经影响到了严重影响到了我们程序的正确性,决定弃用codis.改为普通的1主N从的模式.

主挂了之后导致服务不可用 #1356

参考链接

  1. 【Redis笔记】 第4篇: redis.conf中Replication配置项说明
  2. Redis 配置文件详解
  3. redis命令参考
  4. redis主从复制常见的一些坑
  5. Redis 的各项功能解决了哪些问题?
  6. 集群教程
相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
15天前
|
存储 NoSQL Redis
Redis 新版本引入多线程的利弊分析
【10月更文挑战第16天】Redis 新版本引入多线程是一个具有挑战性和机遇的改变。虽然多线程带来了一些潜在的问题和挑战,但也为 Redis 提供了进一步提升性能和扩展能力的可能性。在实际应用中,我们需要根据具体的需求和场景,综合评估多线程的利弊,谨慎地选择和使用 Redis 的新版本。同时,Redis 开发者也需要不断努力,优化和完善多线程机制,以提供更加稳定、高效和可靠的 Redis 服务。
28 1
|
7天前
|
缓存 监控 NoSQL
Redis 缓存穿透的检测方法与分析
【10月更文挑战第23天】通过以上对 Redis 缓存穿透检测方法的深入探讨,我们对如何及时发现和处理这一问题有了更全面的认识。在实际应用中,我们需要综合运用多种检测手段,并结合业务场景和实际情况进行分析,以确保能够准确、及时地检测到缓存穿透现象,并采取有效的措施加以解决。同时,要不断优化和改进检测方法,提高检测的准确性和效率,为系统的稳定运行提供有力保障。
33 5
|
5月前
|
存储 NoSQL Redis
Redis系列学习文章分享---第九篇(Redis快速入门之好友关注--关注和取关 -共同关注 -Feed流实现方案分析 -推送到粉丝收件箱 -滚动分页查询)
Redis系列学习文章分享---第九篇(Redis快速入门之好友关注--关注和取关 -共同关注 -Feed流实现方案分析 -推送到粉丝收件箱 -滚动分页查询)
58 0
|
2月前
|
Oracle NoSQL 关系型数据库
主流数据库对比:MySQL、PostgreSQL、Oracle和Redis的优缺点分析
主流数据库对比:MySQL、PostgreSQL、Oracle和Redis的优缺点分析
242 2
|
2月前
|
存储 Prometheus NoSQL
Redis 内存突增时,如何定量分析其内存使用情况
【9月更文挑战第21天】当Redis内存突增时,可采用多种方法分析内存使用情况:1)使用`INFO memory`命令查看详细内存信息;2)借助`redis-cli --bigkeys`和RMA工具定位大键;3)利用Prometheus和Grafana监控内存变化;4)优化数据类型和存储结构;5)检查并调整内存碎片率。通过这些方法,可有效定位并解决内存问题,保障Redis稳定运行。
|
3月前
|
缓存 NoSQL 网络协议
【Azure Redis 缓存】Azure Redis Cluster 在增加分片数时失败分析
【Azure Redis 缓存】Azure Redis Cluster 在增加分片数时失败分析
|
3月前
|
存储 缓存 NoSQL
【Azure Redis 缓存】当使用Azure Redis 集群服务时候,发生了Moved的几点分析
【Azure Redis 缓存】当使用Azure Redis 集群服务时候,发生了Moved的几点分析
|
3月前
|
网络协议 NoSQL 网络安全
【Azure 应用服务】由Web App“无法连接数据库”而逐步分析到解析内网地址的办法(SQL和Redis开启private endpoint,只能通过内网访问,无法从公网访问的情况下)
【Azure 应用服务】由Web App“无法连接数据库”而逐步分析到解析内网地址的办法(SQL和Redis开启private endpoint,只能通过内网访问,无法从公网访问的情况下)
|
5月前
|
存储 缓存 NoSQL
Redis性能测试实操记录与分析
Redis性能测试实操记录与分析
72 3
|
5月前
|
存储 NoSQL Redis
大事件后端项目33_登录优化-redis_思路分析
大事件后端项目33_登录优化-redis_思路分析