redis 클러스터
는 기본 클러스터 솔루션으로 현재 고가용성 및 안정성 측면에서 큰 발전을 이루었습니다. 통계 및 관찰에 따르면 점점 더 많은 기업과 커뮤니티가 사실상의 표준이 된 redis 클러스터
아키텍처를 채택하고 있습니다. 주요 특징은 분산되어 있으며 프록시
프록시가 필요하지 않다는 것입니다. 주요 설계 목표 중 하나는 선형 확장성을 달성하는 것입니다. redis cluster
是亲生的集群方案,目前,在高可用和稳定性方面,都有了很大的进步。据统计和观察,采用redis cluster
架构的公司和社区越来越多,已经成为事实的标准。它的主要特点就是去中心化,无需proxy
代理。其中一个主要设计目标就是达到线性可扩展性(linear scalability)。
仅仅靠redis cluster
服务器本身,并不能完成官方承诺的功能。广义上的redis cluster
应该既包含redis
服务器,又包含客户端实现比如jedis
等。它们是一个整体。
分布式存储无非就是处理分片和副本。 对redis cluster
来说,核心概念就是槽(slot),了解了它,基本就了解了集群的管理方式。
当了解这些特性以后,运维上其实是更简单了。我们先看下比较明显的优缺点。
1、不再需要额外的Sentinel
集群,为使用者提供了一致的方案,减少了学习成本。
2、去中心架构,节点对等,集群可支持上千个节点。
3、抽象出了slot
概念,针对slot
进行运维操作。
4、副本功能能够实现自动故障转移,大部分情况下无需人工介入。
1、客户端要缓存部分数据,实现Cluster
协议,相对复杂。
2、数据是通过异步复制的,不能保证数据的强一致性。
3、资源隔离困难,经常流量不均衡,尤其是多个业务共用集群的时候。数据不知道在哪里,针对热点数据,也无法通过专项优化
完成。
4、从库是完全的冷备,无法分担读操作,真是太太浪费了。需要做额外工作。
5、MultiOp
和Pipeline
支持有限,老代码要是进行架构升级,要小心了。
6、数据迁移是基于key
而不是基于slot
的,过程较慢。
从槽到key
,定位过程明显就是一个双层的路由。
redis cluster
和常用的一致性hash
没什么关系,它主要采用了哈希槽的概念。当需要在其中存取一个key
时,redis
客户端会首先对这个key
采用crc16
算法算出一个值,然后对这个值进行mod
操作。
crc16(key)mod 16384
所以,每个key
都会落在其中的一个hash
槽上。16384 等同于 2^14(16k),redis
节点发送心跳包时,需要把所有的槽信息放在这个心跳包里,所以要竭尽全力的优化,感兴趣的可以看下为什么默认的槽数量是 16384 。
上面谈到,redis cluster
共定义了 16384 个槽,所有的集群操作都是围绕着这个槽数据进行编码。服务端使用一个简单的数组存储这些信息。
对于判断有无的操作,使用bitmap
来存储是最节省空间的。redis cluster
就是使用一个叫做slot
的数组来保存当前节点是否持有了这个槽。
数组的长度为 16384/8=2048 Byte
,那么就可以使用 0 或者 1 来标识本节点对某个槽是否拥有。
其实,只需要第一份数据ClusterState
也能完成操作,保存另外一个维度的Slot
数组,能够方便编码和存储。一个节点除了会将自己负责处理的槽记录在两个地方(clusterNode结构的slots和numslots),它还会将自己的slots
数组通过消息发送给集群中的其他节点,以此来告诉其他节点自己目前拥有的槽。
当数据库中的 16384 个槽都有节点在处理时,集群处于上线状态(ok);相反地,如果数据库中有任何一个槽没有得到处理,那么集群处于下线状态(fail)。
当客户端向节点发送相关命令时,接收命令的节点会计算出命令要处理的key
属于哪个槽,并检查这个槽是否指派给了自己。如果不是自己的,会指引客户端到正确的节点。
所以,客户端连接集群中的任意一台机器,都能够完成操作。
假如我们要组装一个3分片的集群,每个分片有一个副本。那么总共需要的node
实例就有 3*2=6 个。redis
redis 클러스터
서버만으로는 공식적으로 약속된 기능을 완료할 수 없습니다. 넓은 의미에서 redis 클러스터
에는 redis
서버와 jedis
등과 같은 클라이언트 구현이 모두 포함되어야 합니다. 그것들은 전체입니다.
분산 스토리지는 샤딩과 복제본을 처리하는 것에 지나지 않습니다. redis 클러스터
의 핵심 개념은 슬롯입니다. 이를 이해하면 기본적으로 클러스터의 관리 방법을 이해하게 됩니다. 🎜🎜장점과 단점🎜🎜이러한 기능을 이해하고 나면 작동 및 유지 관리가 실제로 더 간단해집니다. 먼저 보다 확실한 장점과 단점을 살펴보겠습니다. 🎜Sentinel
클러스터가 필요하지 않아 사용자에게 일관된 솔루션을 제공하고 학습 비용을 절감합니다. 🎜🎜2. 분산형 아키텍처, 노드는 P2P이며 클러스터는 수천 개의 노드를 지원할 수 있습니다. 🎜🎜3. 슬롯
의 개념을 추상화하고, 운영 및 유지관리 작업을 슬롯
에서 수행합니다. 🎜🎜4. 복제 기능은 대부분의 경우 수동 개입 없이 자동 장애 조치를 실현할 수 있습니다. 🎜클러스터
프로토콜을 구현해야 하는데 이는 상대적으로 복잡합니다. 🎜🎜2. 데이터는 비동기식으로 복사되므로 데이터의 강력한 일관성을 보장할 수 없습니다. 🎜🎜3. 특히 여러 기업이 클러스터를 공유하는 경우 리소스 격리가 어렵고 트래픽이 불균형해지는 경우가 많습니다. 우리는 데이터가 어디에 있는지 모르고, 특별한 최적화
를 통해서는 핫 데이터를 얻을 수 없습니다. 🎜🎜4. 슬레이브 데이터베이스는 완전히 콜드 대기 상태이며 읽기 작업을 공유할 수 없습니다. 추가 작업이 필요합니다. 🎜🎜5. MultiOp
및 Pipeline
은 지원이 제한되어 있습니다. 이전 코드의 아키텍처를 업그레이드하려면 주의하세요. 🎜🎜6. 데이터 마이그레이션은 슬롯
대신 키
를 기반으로 하며 프로세스가 느립니다. 🎜🎜기본 원리🎜🎜슬롯에서 키
까지 위치 지정 프로세스는 분명히 2계층 라우팅입니다. 🎜redis 클러스터
는 일반적으로 사용되는 일관성 해시
와 관련이 없습니다. 주로 해시 슬롯 개념을 사용합니다. key
에 액세스해야 할 때 redis
클라이언트는 먼저 crc16
알고리즘을 사용하여 key
A를 계산합니다. 값을 지정한 다음 이 값에 대해 mod
작업을 수행합니다. 🎜for i in {0..5} do cp redis.conf redis-700$i.conf done🎜따라서 각
키
는 해시
슬롯 중 하나에 속하게 됩니다. 16384는 2^14(16k)에 해당합니다. redis
노드가 하트비트 패킷을 보낼 때 모든 슬롯 정보를 이 하트비트 패킷에 넣어야 하므로 최선을 다해 최적화해야 합니다. 관심이 있으시면 기본 슬롯 수가 16384인 이유를 읽어보실 수 있습니다. 🎜redis 클러스터
는 총 16384개의 슬롯을 정의하며 모든 클러스터 작업은 이 슬롯 데이터를 중심으로 인코딩됩니다. 서버는 간단한 배열을 사용하여 이 정보를 저장합니다. 🎜🎜존재 여부를 확인하는 작업에서는 비트맵
을 사용하여 저장하는 것이 가장 공간을 절약합니다. redis 클러스터
는 슬롯
이라는 배열을 사용하여 현재 노드가 이 슬롯을 보유하는지 여부를 저장합니다. 🎜🎜배열의 길이는 16384/8=2048바이트
이며, 0 또는 1을 사용하여 이 노드가 특정 슬롯을 소유하는지 식별할 수 있습니다. 🎜🎜실제로 작업을 완료하려면 첫 번째 데이터 ClusterState
만 필요하며 다른 차원의 Slot
배열이 저장되므로 인코딩 및 저장이 용이할 수 있습니다. 두 위치(clusterNode 구조의 슬롯 및 numslots)에서 처리를 담당하는 슬롯을 기록하는 것 외에도 노드는 메시지를 통해 클러스터의 다른 노드에 자체 slots
배열을 보냅니다. 다른 노드에게 현재 소유하고 있는 슬롯을 알려줍니다. 🎜🎜데이터베이스의 16384개 슬롯이 모두 노드에서 처리되면 클러스터는 온라인 상태(ok)가 되고, 반대로 데이터베이스의 슬롯 중 하나라도 처리되지 않으면 클러스터는 오프라인 상태(실패)가 됩니다. 🎜🎜클라이언트가 노드에 관련 명령을 보내면 명령을 받은 노드는 해당 명령을 처리할 키
가 어느 슬롯에 속하는지 계산하고, 이 슬롯이 자신에게 할당되어 있는지 확인합니다. 자신의 노드가 아닌 경우 클라이언트를 올바른 노드로 연결합니다. 🎜🎜따라서 클라이언트는 클러스터의 모든 머신에 연결하여 작업을 완료할 수 있습니다. 🎜🎜6노드 클러스터 설치🎜node
인스턴스는 3*2=6입니다. redis
는 구성 파일을 지정하여 시작할 수 있습니다. 우리가 하는 일은 구성 파일을 수정하는 것입니다. 🎜🎜6개의 기본 구성 파일을 복사하세요. 🎜for i in {0..5} do cp redis.conf redis-700$i.conf done
修改其中的配置文件内容,拿redis-7000.conf
来说,我们要启用它的cluster
模式。
cluster-enabled yes port 7000 cluster-config-file nodes-7000.conf
nodes-7000.conf
会保存一些集群信息到当前节点,所以需要独立。
同样的,我们使用脚本来启动它。
for i in {0..5} do nohup ./redis-server redis-700$i.conf & done
为了演示,我们暴力把它关闭。
ps -ef| grep redis | awk '{print $2}' | xargs kill -9
我们使用redis-cli
进行集群的组合。redis
将自动完成这个过程。这一系列的过程,是通过发送指令给每个节点进行组合的。
./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
集群中的每个节点都会定期地向集群中的其他节点发送ping消息,以此来检测对方是否在线,如果接收ping
消息的节点没有在规定的时间内返回pong
消息,那么发送ping
消息的节点就会将接收ping
消息的节点标记为疑似下线(PFAIL)。
如果在一个集群里面,半数以上节点都将某个主节点 x 报告为疑似下线,那么这个主节点x将被标记为已下线(FAIL),将x标记为FAIL
的节点会向集群广播一条关于 x 的FAIL
消息,所有收到这条FAIL
消息的节点都会立即将 x 标记为FAIL
。
大家可以注意到这个过程,与 es 和 zk 的节点判断类似,都是半数以上才进行判断,所以主节点的数量一般都是奇数。由于没有最小组群配置,理论上会有脑裂(暂时并未遇到过)。
当一个节点发现自己的主节点进入fail
状态,将会从这个节点的从节点当中,选出一台,执行slaveof no one
命令,变身为主节点。
新的节点完成自己的槽指派以后,会向集群广播一条pong
消息,以便让其他节点立即知道自己的这些变化。它告诉别人:我已经是主节点了,我已经接管了有问题的节点,成为了它的替身。
redis
内部对集群的这些管理,大量使用了已经定义好的这些指令。所以这些指令不仅仅供我们从命令行使用,redis
自己内部也用。
当一台从机连接到master
之后,会发送一个sync
指令。master
在收到这个指令后,会在后台启动存盘进程。执行完毕后,master
将整个数据库文件传输到slave
,这样就完成了第一次全量同步。
接下来,master
会把自己收到的变更指令,依次传送给slave
,从而达到数据的最终同步。从redis 2.8
开始,就支持主从复制的断点续传,如果主从复制过程中,网络连接断掉了,那么可以接着上次复制的地方,继续复制下去,而不是从头开始复制一份。
redis cluster
中节点之间使用异步复制,并没有类似kafka
这种ack
的概念。节点之间通过gossip
协议交换状态信息,用投票机制完成Slave
到Master
的角色提升,完成这个过程注定了需要时间。在发生故障的过程中就容易存在窗口,导致丢失写入的数据。比如以下两种情况。
一、命令已经到到master
,此时数据并没有同步到slave
,master
会对客户端回复ok。如果这个时候主节点宕机,那么这条数据将会丢失。redis
这样做会避免很多问题,但对一个对数据可靠性要求较高的系统,是不可忍受的。
二、由于路由表是在客户端存放的,存在一个时效问题。如果分区导致一个节点不可达,提升了某个从节点,但原来的主节点在这个时候又可以用了(并未完成failover)。如果客户端的路由表没有及时更新,那么写入错误的节点可能导致数据丢失。
所以redis cluster
在通常情况下运行的很好,在极端情况下某些值丢失问题,目前无解。
redis cluster
的运维非常的繁杂,虽然已经进行了抽象,但这个过程依然不简单。有些指令,必须在详细了解它的实现原理之后,才能真正放心的去用。
扩容会用到的一些命令。在实际使用的过程中,可能需要多次频繁地输入这些命令,且输入的过程中还要监视它的状态,所以基本上是不可能人工跑这些命令的。
运维的入口有两个。一个是使用redis-cli连接任意一台,然后发送cluster
打头的命令,这部分命令大多数是对槽进行操作。 在开始组合集群时,就是反复调用这些命令进行的具体逻辑执行。
另外一个入口是使用redis-cli命令,加上--cluster
参数和指令。这种形式主要是用来管控集群节点信息 ,比如增删节点等。所以推荐使用这种方式。
redis cluster
提供了非常复杂的命令,难于操作和记忆。推荐使用类似CacheCloud
的工具进行管理。
下面是几个例子。
通过向节点 A 发送 CLUSTER MEET
命令,客户端可以让接收命令的节点 A 将另一个节点 B 添加到节点 A 当前所在的集群里面:
CLUSTER MEET 127.0.0.1 7006
通过cluster addslots
命令,可以将一个或者多个槽指派给某个节点负责。
127.0.0.1:7000> CLUSTER ADDSLOTS 0 1 2 3 4 . . . 5000
设置从节点。
CLUSTER REPLICATE <node_id>
redis-trib.rb
是官方提供的Redis Cluster
的管理工具,但最新版本已经推荐使用redis-cli
进行操作。
向集群中添加新节点
redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7007 --cluster-replicas 1
从集群中删除节点
redis-cli --cluster del-node 127.0.0.1:7006 54abb85ea9874af495057b6f95e0af5776b35a52
迁移槽到新的节点
redis-cli --cluster reshard 127.0.0.1:7006 --cluster-from 54abb85ea9874af495057b6f95e0af5776b35a52 --cluster-to 895e1d1f589dfdac34f8bdf149360fe9ca8a24eb --cluster-slots 108
类似的命令还有很多。
create:创建集群 check:检查集群 info:查看集群信息 fix:修复集群 reshard:在线迁移slot rebalance:平衡集群节点slot数量 add-node:添加新节点 del-node:删除节点 set-timeout:设置节点的超时时间 call:在集群所有节点上执行命令 import:将外部redis数据导入集群
redis
最早支持的,就是M-S
模式,也就是一主多从。redis
单机qps
可达到 10w+,但是在某些高访问量场景下,依然不太够用。一般通过读写分离来增加slave
,减少主机的压力。
既然是主从架构,就面临着同步问题,redis
主从模式的同步分为全同步和部分同步。当刚创建一个从机的时候,不可避免的要进行一次全量同步。等全量同步结束之后,进入增量同步阶段。这个和redis cluster
是没什么区别的。
这种模式还是比较稳定的,但要额外做一些工作。用户需要自行开发主从切换的功能,也就是使用哨兵去探测每个实例的健康状况,然后通过指令进行集群状态的改变。
当集群规模增大,主从模式会很快遇到瓶颈。所以一般会采用客户端hash
的方法进行扩展,包括类似于memcached
的一致性哈希。
客户端hash
的路由可能会很复杂,通常会通过发布jar
包或者配置的方式维护这些meta
信息,这也给线上环境增加了很多不确定性。
不过,通过加入类似ZK
主动通知的功能,将配置维护在云端,可以显著降低风险。笔者曾经维护过的几千个redis
节点,就是用这种方式进行管理的。
代码模式在redis cluster
出现之前,非常流行,比如codis
。代理层通过把自己模拟成一个redis
,接收来自客户端的请求,然后按照自定义的路由逻辑进行数据分片以及迁移,而业务方不需要改动任何代码。除了能够平滑的进行扩容,一些主从切换、FailOver
的功能也在代理层完成,客户端甚至可以没有任何感知。这类程序又称为分布式中间件。
一个典型的实现如下图,背后的redis
集群甚至可以是混合的。
但这种方式的缺点也是显而易见的。首先,它引入了一个新的代理层,在结构上、运维上都显复杂。需要进行大量的编码,比如failover
、读写分离、数据迁移等。另外,proxy
层的加入,对性能也有相应的损耗。
多个proxy
一般使用lvs
等前置进行负载均衡的设计,如果proxy
层的机器很少而后端redis
的流量很高,那么网卡会成为主要的瓶颈。
Nginx
也可以作为redis
的代理层,比较专业的说法叫做Smart Proxy
。这种方式较为偏门,如果你对nginx
比较熟悉,不失为一种优雅的做法。
redis
的速度特别的快。一般越快的东西,出问题的时候造成的后果越大。
얼마 전 저는 redis
에 대한 사양을 작성했습니다. "Redis 사양, 이것이 가장 적절할 수 있습니다." 사양은 아키텍처와 동일하지만 회사 환경에 가장 적합한 것이 가장 좋지만 몇 가지 기본 아이디어를 제공합니다. redis
的规范:《Redis规范,这可能是最中肯的了》。规范和架构一样,适合自己公司环境的,才是最好的,但会提供一些起码的思路。
严格禁止的东西,一般都是前人踩坑的地方。除了这篇规范的内容,对于redis-cluster
,补充以下几点。
1、redis cluster
号称能够支持1k个节点,但你最好不要这么做。当节点数量增加到10,就能够感受到集群的一些抖动。这么大的集群证明你的业务已经很牛x了,考虑一下客户端分片吧。
2、一定要避免产生热点,如果流量全部打到了某个节点,后果一般很严重。
3、大key
不要放redis
,它会产生大量的慢查询,影响正常的查询。
4、如果你不是作为存储,缓存一定要设置过期时间。占着茅坑不拉屎的感觉是非常讨厌的。
5、大流量,不要开aof
,开rdb
即可。
6、redis cluster
的操作,少用pipeline
,少用multi-key
redis-cluster
에 대해 다음 사항이 추가됩니다. 🎜🎜1. redis 클러스터
는 1,000개의 노드를 지원할 수 있다고 주장하지만 이렇게 하지 않는 것이 좋습니다. 노드 수가 10개로 증가하면 클러스터에 약간의 지터가 느껴질 수 있습니다. 이러한 대규모 클러스터는 귀하의 비즈니스가 이미 매우 훌륭하다는 것을 증명합니다. 클라이언트 샤딩을 고려하십시오. 🎜🎜2. 모든 트래픽이 특정 노드에 도달하면 일반적으로 결과가 심각해집니다. 🎜🎜3. redis
를 큰 키
에 넣지 마세요. 이렇게 하면 느린 쿼리가 많이 생성되어 일반 쿼리에 영향을 줍니다. 🎜🎜4. 저장소로 사용하지 않는 경우 캐시에 만료 시간을 설정해야 합니다. 화장실을 차지하고 똥을 싸지 않는 느낌은 매우 짜증납니다. 🎜🎜5. 대규모 트래픽의 경우 aof
를 활성화하지 말고 rdb
만 활성화하세요. 🎜🎜6. redis 클러스터
를 운영할 때 파이프라인
과 다중 키
를 적게 사용하면 예측할 수 없는 결과가 많이 발생합니다. 🎜위 내용은 Redis에 6노드 클러스터를 설치하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!