当前位置:首页 > 问答 > 正文

Ruby里用Redis集群搞高可用,怎么搭建和注意点聊聊

想在Ruby里用Redis集群实现高可用,说白了就是让Redis服务更“抗造”,即使某台机器或者某个Redis实例挂了,你的Ruby应用还能继续读写数据,不至于整个网站或服务瘫痪,下面就直接聊聊怎么搭以及要注意的那些事儿。

第一部分:搭建Redis集群

你得明白,Redis集群本身是一个去中心化的、多个Redis实例共同工作的模式,它把数据分片存储在多个节点上,并且每个分片都有备份,以此来达到高可用,搭建过程大概分这么几步:

  1. 准备至少6个Redis实例:这是最低要求,为什么是6个?因为Redis集群要求至少要有3个主节点来存放数据分片,而为了高可用,每个主节点至少需要1个从节点做备份,3主 + 3从 = 6个,你可以把这6个实例放在3台、4台甚至6台物理机或虚拟机上,目的是避免单个机器宕机导致多个节点同时失效。
  2. 配置每个Redis实例:在每个Redis的配置文件里(通常是 redis.conf),你需要开启集群模式,找到并修改这几行:
    • cluster-enabled yes:这是最关键的一步,告诉Redis这个实例以集群模式启动。
    • cluster-config-file nodes-6379.conf:这个是集群自动生成的配置文件,用来记录集群的状态,你不用管它内容,但要把路径设置好。
    • cluster-node-timeout 15000:节点失联的超时时间,单位是毫秒,如果某个节点超过这个时间没响应,集群就认为它挂了,会启动故障转移,这个值可以根据网络情况调整。
  3. 启动所有实例:把上面配置好的6个Redis服务全部启动起来。
  4. 创建集群:实例都跑起来后,它们还是一个个独立的“光杆司令”,需要用Redis自带的命令行工具 redis-cli 把它们“撮合”到一起,命令长这样: redis-cli --cluster create 192.168.1.101:6379 192.168.1.102:6379 192.168.1.103:6379 192.168.1.104:6379 192.168.1.105:6379 192.168.1.106:6379 --cluster-replicas 1 这个命令的意思是,用这6个地址来创建集群,--cluster-replicas 1 表示每个主节点配1个从节点,执行这个命令后,它会给你一个分片方案,你输入 yes 确认,集群就初始化好了。

第二部分:Ruby应用如何连接集群

你的Ruby程序不能像连接单个Redis那样直接连一个地址了,你需要使用支持Redis集群的客户端,最常用的就是 redis 这个gem。

在Gemfile里: gem 'redis'

在代码里,连接方式变了: cluster = Redis.new(cluster: ['redis://192.168.1.101:6379', 'redis://192.168.1.102:6379'])

注意,你不需要把集群所有节点的地址都写上,只需要写一部分(比如两三个)就行,客户端连接上其中一个后,会自动获取整个集群的拓扑结构,知道数据分布在哪些节点上。

Ruby里用Redis集群搞高可用,怎么搭建和注意点聊聊

第三部分:最重要的注意点(坑点)

这才是关键,很多问题都出在这里。

  1. 键的哈希标签(Key Hash Tags):这是集群模式下最大的不同点!Redis集群是把所有的键通过一个算法映射到不同的分片(也就是不同的主节点)上,如果你有一组相关的键,user:1000:profileuser:1000:orders,你希望它们存放在同一个分片上,以便进行事务操作或者跨键查询,但默认情况下,它们可能会因为哈希计算不同而被分配到不同的节点,怎么办?用哈希标签,你把键写成 user:{1000}:profileuser:{1000}:orders,集群只会用大括号 里面的内容(即 1000)来计算分片,这样这两个键就能保证落在同一个节点上了。(这个特性非常重要,很多人在用集群时因为没注意这个导致操作失败)

  2. 不是所有命令都支持:在集群模式下,有些命令是被限制的,尤其是那些需要同时操作多个键,且这些键可能不在同一个分片上的命令。mgetmset 这种批量操作,如果键没有使用相同的哈希标签,导致它们不在一个节点上,命令就会报错,类似的还有事务 multi,也要求所有参与的键在同一个分片上,设计数据模型时要特别注意。

    Ruby里用Redis集群搞高可用,怎么搭建和注意点聊聊

  3. 客户端智能与重定向:好的集群客户端(比如上面提到的 redis gem)是“智能”的,当你尝试操作一个键时,客户端可能会收到一个“MOVED”错误响应,意思是“这个键不在我这儿,你去XXX节点操作”,智能客户端会捕捉这个错误,然后自动更新自己的集群映射表,并重定向到正确的节点执行操作,这对你是透明的,但你要知道有这个机制存在,这意味着偶尔会有一次请求的延迟稍高一点。

  4. 故障转移是自动的,但需要时间:当集群发现一个主节点宕机了,它会自动提升其对应的从节点为新的主节点,这个过程是自动的,但需要时间,也就是前面配置里说的 cluster-node-timeout 的时间,在这段时间内,对这个分片的写操作会失败,你的Ruby应用代码必须能处理这种暂时的错误,比如进行重试。

  5. 网络分区(脑裂)风险:虽然集群很健壮,但极端网络情况下也可能出问题,网络断成两半,每一半里的节点都以为另一半挂了,可能会各自选主,导致数据不一致,Redis集群通过“大多数”原则来避免这个问题,要求故障转移必须得到大多数主节点的同意,这就要求你的集群节点数量规划要合理,确保任何网络分区下,至少有一方是拥有大多数主节点的。

  6. 运维复杂度增加:相比单机或简单主从,集群的运维复杂多了,你要监控每一个节点的状态,磁盘空间、内存使用、网络延迟等,扩容(增加新分片)和缩容虽然也有工具支持,但毕竟是手动操作,有风险。

总结一下

在Ruby里用Redis集群,核心是选对客户端,并在设计业务数据时严格遵守哈希标签的规则来保证相关数据的局部性,要意识到集群不是银弹,它带来了可扩展性和可用性,但也牺牲了一些命令的便利性,增加了系统的复杂性,你的应用代码要有容错和重试机制,以应对临时的节点故障或网络闪断,先把这些要点搞明白,再上生产环境,能避免很多头疼的问题。