1。RedisCluster的基本概念Redis的集群版本听上去很宏大,它确实比单实例一主一从或者一主多从模式要复杂得多。互联网业务的架构总是随着业务的发展而演进。单实例Redis架构一主N从加上读写分离。Redis作为缓存单实例似乎还不错,它有Sentinel哨兵机制,可以实现主从故障迁移。单实例一主二从+读写分离结构:注:图片来自网络。由于本质上只有一个Master作为存储,即使机器有128GB内存,一般建议使用率不要超过70%-80%。因此,使用高达100GB的数据已经很多了。实际上,50%也不错。我认为数据过多也会降低服务的稳定性,因为数据过多意味着持久化成本高,可能会严重阻塞服务,甚至最终砍掉master。如果单实例只作为缓存,除了服务失败或阻塞时的缓存击穿问题外,很多请求可能一起干掉MySQL。如果使用单实例作为主存,那么问题就比较大了,因为涉及到持久化问题,不管是bgsave还是aof,都会导致磁盘阻塞。这时候服务请求的成功率就会下降。这不是一个例子就能解决的。因为作为主存储,持久化是必须的。所以我们期待一个多主多从的Redis系统,这样不管是作为主存还是作为缓存,压力和稳定性都会有所提升。尽管如此,笔者还是建议:如果一意孤行,要么欺骗自己,要么欺骗别人。Clusteringandsharding要支持集群,首先要克服的就是sharding问题,即一致性哈希问题。常见的解决方案有以下三种:Clientsharding:这种情况主要类似于hash取模的方法,当client完全掌握并控制server的数量时,可以很方便的使用。中间层分片:在这种情况下,在客户端和服务器之间添加一个中间层,作为管理器和调度器。客户端的请求被发送到中间层,中间层实现请求的转发和回收。当然,中间层最重要的作用就是多台服务器的动态管理。Server-sidesharding:在不使用中间层的情况下实现去中心化的管理模式。客户端直接请求服务器中的任意一个节点。如果被请求的Node没有需要的数据,它会回复MOVED给客户端,告诉客户端该怎么做。数据的存储位置是必需的。这个过程实际上是由客户端和服务端通过请求重定向共同完成的。前面提到的Redis中层分片集群版本,改成N-Master和N-Slave可以有效提升处理能力和稳定性,但是这样会面临一致性哈希的问题,即动态扩缩容时的数据问题.在Redis集群版正式发布之前,业界一些解决方案就迫不及待的使用自研版本的Redis集群,包括国内豌豆荚的Codis和国外推特的twemproxy。核心思想是在多个Redis服务器和client客户端之间增加一个sharding层,由sharding层完成数据的一致性哈希和分片。每个公司的做法不尽相同,但核心要解决的问题是多Redis场景下的扩缩容、故障转移、数据完整性、数据一致性、请求处理延迟等问题。在业界,Codis配合LVS等方式实现Redis集群。很多方案应用到生产环境,性能还不错。主要原因是官方的集群版本是在Redis3.0才出现的。做个小白鼠,但其实经过迭代,已经到了Redis5.x版本,官方集群版还是很不错的,至少笔者是这么认为的。server-sidesharding正式集群版正式版区别于上面的Codis和Twemproxy,在server层实现了Sharding分片技术。也就是说,没有官方的中间层,而是多个服务节点自己实现分片。当然也可以认为这部分实现sharding的功能是集成在Redis服务本身,没有单独的sharding模块。之前的文章也提到官方集群引入了槽的概念进行数据分片,然后将数据槽分配给多个主节点,主节点再配置N个从节点,这样就形成了一个多主节点的官方集群。实例分片版本架构。RedisCluster是一个分布式集群,可以在多个Redis节点之间共享数据。在服务器端,节点之间通过特殊的协议进行通信。这种特殊的协议作为中间层管理部分的通信协议。该协议称为Gossip八卦协议。分布式系统一致性协议的目的是解决集群中多节点状态通知的问题,这是管理集群的基础。图为官方基于Gossip协议的集群架构图:注:图片来源于网络2.RedisCluster节点状态信息结构的基本运行原理Cluster中的每个节点都在其自身维护着整个集群的一个当前状态ownview,主要包括:当前集群状态,集群中各节点负责的slots信息,migrate状态各节点master-slave状态下集群中各节点的存活状态和不可达票数簇。也就是说,以上信息是集群中的Node,八卦八卦的内容主题比较全面,有自己的,也有别人的。这样,大家互相传播,最终的信息是全面准确的。与拜占庭帝国问题不同,信息可信。很高。基于Gossip协议,当集群状态发生变化时,比如新节点加入、slot迁移、节点宕机、slave被提升为新的Master,我们希望这些变化能尽快被发现,传播到所有节点在整个集群中,并达成共识。节点之间的相互心跳(PING、PONG、MEET)及其携带的数据是传播集群状态的最重要方式。Gossip协议的概念八卦协议(gossipprotocol),也称为流行病协议(epidemicprotocol),是一种基于流行病传播方式在节点或进程之间进行信息交换的协议。它广泛应用于分布式系统中。例如,我们可以使用八卦协议来保证网络中所有节点的数据是相同的。八卦协议最初由AlanDemers于1987年创建,他是Xerox帕洛阿尔托研究中心的研究员。https://www.iteblog.com/archives/2505.htmlGossip协议在P2P网络中已经是比较成熟的协议了。Gossip协议最大的优点是即使集群节点数量增加,每个节点的负载也不会增加太多,几乎是恒定的。这允许Consul管理的集群扩展到数千个节点。八卦算法也称为反熵(Anti-Entropy)。熵是物理学中的概念,代表混沌,而反熵则是在混沌中寻求一致性,充分说明了Gossip的特点:在有界网络中,每个节点随机地与其他节点通信,经过一些随意通信??后,状态所有节点最终会达成共识。每个节点可能知道所有其他节点,或者可能只知道几个邻居节点。只要这些节点能够通过网络连接起来,最终它们的状态就会保持一致。当然,这也是疫情传播的一个特点。https://www.backendcloud.cn/2017/11/12/raft-gossip/上面的描述比较学术。其实Gossip协议对于我们吃瓜群众来说并不陌生。Gossip协议也变成了谣言协议。说白了就是八卦协议。这种交流的规模和速度都非常快。你可以体验一下。所以,计算机中的很多算法都是源于生活,高于生活。使用八卦协议。Redis集群是去中心化的,彼此之间的状态同步依赖于gossip协议通信。集群消息有几种类型:Meet通过“clustermeetipport”命令,现有集群的节点将与新节点通信,发送加入现有集群的邀请。Ping节点每秒向集群中的其他节点发送一个ping报文,报文中包含其已知的两个节点的地址、槽位、状态信息、上次通信时间等。Pong节点收到ping报文后会回复pong报文,其中也包含两个已知节点的信息。Fail节点ping某个节点失败后,会向集群内的所有节点广播该节点宕机的消息。其他节点收到消息后,将其标记为离线。由于去中心化和通信机制,RedisCluster选择了最终一致性和基本可用性。例如,当有新节点加入(meet)时,只有邀请节点和被邀请节点知道,其余节点必须等待ping报文逐层传播。除了Fail是全网第一时间通知外,其他的比如新增节点、节点重新上线、从节点选举成为主节点、slot变化等,都需要等待通知,即也就是说,Gossip协议是一个最终一致性协议。因为gossip协议对服务器时间要求很高,否则不准确的时间戳会影响节点判断消息的有效性。另外,节点数量增加后的网络开销也会对服务器造成压力。同时,节点过多意味着实现最终一致性的时间会相对较长。因此,官方推荐节点数量上限为1000个左右。图为新增节点服务器时的通信交互图:注:图片来源于网络。一般来说,官方的Redis集群是一个去中心化的类P2P网络。P2P早年很流行,比如eMule、BT。它是一个P2P网络。在Redis集群中,Gossip协议作为一种去中心化的通信协议,根据既定的通信规则实现整个集群的非中心管理节点的自治行为。基于Gossip协议的故障检测集群中的每个节点都会周期性地向集群中的其他节点发送PING报文来交换各个节点的状态信息,检测各个节点的状态:在线状态、疑似离线状态PFAIL、离线状态FAIL。自己保存信息:当主节点A通过消息得知主节点B认为主节点D已经进入疑似离线(PFAIL)状态时,主节点A会在自己的clusterState中找到主节点D对应的clusterNode结构。nodes字典,并将主节点B的离线报告添加到clusterNode结构体的fail_reports列表中,然后通过Gossip协议将节点D的疑似离线状态通知给其他节点。共同判断:如果集群中有超过半数的主节点报告主节点D疑似下线,则将主节点D标记为下线(FAIL),将主节点D标记为已下线的节点goneoffline主节点D的FAIL消息会广播到集群中,所有收到FAIL消息的节点都会立即更新节点中主节点D的状态,将其标记为离线。最终结论:将节点标记为FAIL需要满足以下两个条件:超过一半的主节点将节点标记为PFAIL。当前节点也将节点标记为PFAIL状态。即当前节点发现其他节点疑似宕机,就写在自己的notebook中,等通知其他好朋友,让他们自己看看。最后超过半数的小伙伴认为,如果节点宕机了,节点自己也认为宕机了,那就真的宕机了,流程比较严谨。
