您现在的位置是:网站首页> 学习资源

大型项目研发技术收集

摘要

大型项目研发技术收集


集群使用





集群使用

redis集群

redis的集群并给出详细的例子包括用C#如何操作集群的读写






redis集群

单个Master复制集难以承担,因此需要对多个复制集进行集群,形成水平扩展每个复制集只负责存储整个数据集的一部分,这就是Redis的集群,其作用是提供在多个Redis节点间共享数据的程序集

1.png

Redis集群支持多个Master,每个Master又可以挂载多个Slave

读写分离

支持海量数据的高可用

支持海量数据的读写存储操作

由于Cluster自带Sentinel的故障转移机制,内置了高可用的支持,无需再去使用哨兵功能

客户端和Redis的节点连接,不再需要连接集群中所有节点,只需连接集群中的任意一个可用节点即可

槽位slot负责分配到各个物理服务节点,由对应的集群来负责维护节点、插槽和数据之间的关系

redis集群不保证强一致性,这意味着在特定的条件下,Redis集群可能会丢掉一些被系统收到的写入请求命令


Redis集群分布式存储

槽位

集群的密钥空间被分成16384个槽,有效地设置了16384个主节点的集群大小上限(但是,建议的最大节点大小约为1000个节点)。

Redis集群投有使用一致性hash,而是引入了哈希槽的概念.

Redis集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽。

集群的每个节点(master)负责一部分hash槽。


比如,有一个集群有三个节点:

1.png


分片

使用Redis集群时我们会将存储的数据分散到多台redis机器上,这称为分片。简言之,集群中的每个Redis实例都被认为是整个数据的一个分片。


如何找到给定key的分片:为了找到给定key的分片,我们对key进行CRC16(key)算法处理并通过对总分片数量取模。然后,使用确定性哈希函数,这意味着给定的key将多次始终映射到同一个分片,我们可以推断将来读取特定key的位置。


Redis集群分布式存储有大概有3种解决方法


哈希取余分区

1.png

hash(key) % N个机器台数,计算出哈希值,用来决定数据映射到哪一个节点上。

优点:

简单粗暴,直接有效,只需要预估好数据规划节点例如3台、8台、10台,就能保证一段时间的数据支撑。使用Hash算法让固定的一部分请求落到同一台服务器上,这样每台服务器固定处理一部分请求(并维护这些请求的信息),起到负载均衡+分而治之的作用。


缺点:

直接规划好节点,进行扩容或者缩容会很麻烦,不管扩还是缩,每次数据变动会导致节点有变动,映射关系都要重新计算,在服务器个数固定不变时没有问题。

如果需要弹性扩容或故障停机的情况下,原来的取模公式就会发生变化,Hash(key)/3会变成Hash(key) 

此时地址经过取余运算的结果将发生很大变化,根据公式获取的服务器也会变得不可控。


一致性哈希算法分区

为了解决分布式缓存数据变动和映射问题,某个机器宕机了,分母数量改变了,自然取余数不行了。

目的是当服务器个数发生变动时,尽量减少影响客户端到服务器的映射关系


配置集群(三主三从)

Redis集群为什么至少需要三个master节点?

因为新master的选举需要大于半数的集群master节点同意才能选举成功,如果只有两个master节点,当其中一个挂了,是达不到选举新master的条件的。


Redis集群为什么推荐节点数为奇数?

奇数个master节点可以在满足选举该条件的基础上节省一个节点,比如三个master节点和四个master节点的集群相比,大家如果都挂了一个master节点都能选举新master节点,如果都挂了两个master节点都没法选举新master节点了,所以奇数的master节点更多的是从节省机器资源角度出发说的。



哈希槽分区

一个集群只能有16384个槽,编号0-16383(0-2^14-1)。这些槽会分配给集群中的所有主节点,分配策略没有要求。

接下来就需要对key求哈希值,然后对16384取模,余数是几key就落入对应的槽里。集群会记录节点和槽的对应关系。

HASH_SLOT = CRC16(key) mod 16384。

以槽为单位移动数据,因为槽的数目是固定的,处理起来比较容易,这样数据移动问题就解决了。


写入的总体流程:当需要在 Redis 集群中放置一个 key-value时,redis先对key使用crc16算法算出一个结果然后用结果对16384求余数[ CRC16(key) % 16384],这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,也就是映射到某个节点上。



为什么redis集群的最大槽数是16384(不太懂)

Redis集群并没有使用一致性hash而是引入了哈希槽的概念。Redis 集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽,集群的每个节点负责一部分hash槽。

正常的心跳数据包带有节点的完整配置,可以用幂等方式用旧的节点替换旧节点,以便更新旧的配置。这意味着它们包含原始节点的插槽配置,该节点使用2k的空间和16k的插槽,但是会使用8k的空间(使用65k的插槽)。同时,由于其他设计折衷,Redis集群不太可能扩展到1000个以上的主节点。因此16k处于正确的范围内,以确保每个主机具有足够的插槽,最多可容纳1000个矩阵,但数量足够少,可以轻松地将插槽配置作为原始位图传播。请注意,在小型群集中,位图将难以压缩,因为当N较小时,位图将设置的slot / N位占设置位的很大百分比。


redis的集群主节点数量基本不可能超过1000个

集群节点越多,心跳包的消息体内携带的数据越多。如果节点过1000个,也会导致网络拥堵。因此redis作者不建议redis cluster节点数量超过1000个。 那么,对于节点数在1000以内的redis cluster集群,16384个槽位够用了。没有必要拓展到65536个。




配置config文件

本案例的配置是在一台虚拟机的6个端口分别配置了6个redis服务器

1.png

端口 6381

vim /myredis/cluster/redisCluster6381.conf

bind 0.0.0.0

daemonize yes

protected-mode no

port 6381

logfile "/myredis/cluster/cluster6381.log"

pidfile /myredis/cluster6381.pid

dir /myredis/cluster

dbfilename dump6381.rdb

appendonly yes

appendfilename "appendonly6381.aof"

requirepass 123456

masterauth 123456

 

cluster-enabled yes

cluster-config-file nodes-6381.conf

cluster-node-timeout 5000


端口 6382

vim /myredis/cluster/redisCluster6382.conf

bind 0.0.0.0

daemonize yes

protected-mode no

port 6382

logfile "/myredis/cluster/cluster6382.log"

pidfile /myredis/cluster6382.pid

dir /myredis/cluster

dbfilename dump6382.rdb

appendonly yes

appendfilename "appendonly6382.aof"

requirepass 123456

masterauth 123456

 

cluster-enabled yes

cluster-config-file nodes-6382.conf

cluster-node-timeout 5000



端口 6383

vim /myredis/cluster/redisCluster6383.conf

bind 0.0.0.0

daemonize yes

protected-mode no

port 6383

logfile "/myredis/cluster/cluster6383.log"

pidfile /myredis/cluster6383.pid

dir /myredis/cluster

dbfilename dump6383.rdb

appendonly yes

appendfilename "appendonly6383.aof"

requirepass 123456

masterauth 123456


cluster-enabled yes

cluster-config-file nodes-6383.conf

cluster-node-timeout 5000



端口 6384

vim /myredis/cluster/redisCluster6384.conf

bind 0.0.0.0

daemonize yes

protected-mode no

port 6384

logfile "/myredis/cluster/cluster6384.log"

pidfile /myredis/cluster6384.pid

dir /myredis/cluster

dbfilename dump6384.rdb

appendonly yes

appendfilename "appendonly6384.aof"

requirepass 123456

masterauth 123456

 

cluster-enabled yes

cluster-config-file nodes-6384.conf

cluster-node-timeout 5000



端口 6385

vim /myredis/cluster/redisCluster6385.conf

bind 0.0.0.0

daemonize yes

protected-mode no

port 6385

logfile "/myredis/cluster/cluster6385.log"

pidfile /myredis/cluster6385.pid

dir /myredis/cluster

dbfilename dump6385.rdb

appendonly yes

appendfilename "appendonly6385.aof"

requirepass 123456

masterauth 123456

 

cluster-enabled yes

cluster-config-file nodes-6385.conf

cluster-node-timeout 5000



端口 6386

vim /myredis/cluster/redisCluster6386.conf

bind 0.0.0.0

daemonize yes

protected-mode no

port 6386

logfile "/myredis/cluster/cluster6386.log"

pidfile /myredis/cluster6386.pid

dir /myredis/cluster

dbfilename dump6386.rdb

appendonly yes

appendfilename "appendonly6386.aof"

requirepass 123456

masterauth 123456

 

cluster-enabled yes

cluster-config-file nodes-6386.conf

cluster-node-timeout 5000



启动六台redis

redis-server /myredis/cluster/redisCluter6381.conf 

..........

redis-server /myredis/cluster/redisCluter6386.conf 


通过redis-cli命令为6台机器构建集群关系

redis-cli -a 123456 --cluster create --cluster-replicas 1 192.168.88.130:6381 192.168.88.130:6382 192.168.88.130:6383 192.168.88.130:6384 192.168.88.130:6385 192.168.88.130:6386

-cluster-replicas 1 表示为每个master创建一个slave节点


任意连接一个作为切入点(集群只需要连一个),并检验集群状态

连接6381端口

redis-cli -a 123456 -p 6381 -c     // -c表示集群 不加的话不是按照集群启动的,对于在别的机器上的key,会报错


不加 -c 启动 ,在存值时,可能会报错,原因是在计算槽位时,可能是在别的master下管理的槽位

下图中的槽位是在6384端口,所以需要在6384端口的redis进行set操作

1.png

加上-c之后,会进行自动重定向

2.png

查看集群主从关系

cluster nodes       // 查看集群的主从关系


查看集群信息

 cluster info   


查看某个key该属于对应的槽位值

CLUSTER KEYSLOT key  //查询key所在的槽位值


集群是否完整才能对外提供服务

在配置文件中有以下代码


cluster-require-full-coverage


默认YES,现在集群架构是3主3从的redis cluster由3个master平分16384个slot,每个master的小集群负责1/3的slot,对应一部分数据。

cluster-require-full-coverage:默认值 yes,即需要集群完整性,方可对外提供服务通常情况,如果这3个小集群中,任何一个(1主1从)挂了,你这个集群对外可提供的数据只有2/3了,整个集群是不完整的,

redis 默认在这种情况下,是不会对外提供服务的。



redis的集群并给出详细的例子包括用C#如何操作集群的读写

Redis集群及其C#操作方法。Redis集群是Redis提供的分布式解决方案,用于在多个Redis节点之间分片数据。

Redis集群的主要特点

自动分片:数据自动分布到多个节点。

高可用性:支持主从复制和自动故障转移。

线性扩展:可以通过添加节点来增加集群容量。

下面我们将详细介绍Redis集群的工作原理、搭建过程,以及如用C#操作集群。


Redis集群工作原理

Redis集群使用哈希槽(hash slot)的概念来分配数据。集群有16384个哈希槽,每个key通过CRC16算法计算后对16384取模,来决定放置在哪个槽中。集群中的每个节点负责一部分槽。


搭建Redis集群

假设我们要搭建一个包含6个节点(3主3从)的Redis集群。


步骤:

a) 创建6个Redis实例,配置文件如下:

port 7000

cluster-enabled yes

cluster-config-file nodes-7000.conf

cluster-node-timeout 5000

appendonly yes


b) 启动6个Redis实例


c) 使用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


使用C#操作Redis集群

要在C#中操作Redis集群,我们可以使用StackExchange.Redis库。以下是一个详细的例子:

首先,安装StackExchange.Redis NuGet包:

Install-Package StackExchange.Redis

然后,使用以下代码连接并操作Redis集群:

using StackExchange.Redis;

using System;


class Program

{

    static void Main(string[] args)

    {

        // 连接到Redis集群

        ConfigurationOptions config = new ConfigurationOptions

        {

            EndPoints =

            {

                { "localhost", 7000 },

                { "localhost", 7001 },

                { "localhost", 7002 },

                { "localhost", 7003 },

                { "localhost", 7004 },

                { "localhost", 7005 }

            },

            CommandMap = CommandMap.Create(new HashSet<string>

            {

                "SUBSCRIBE", "UNSUBSCRIBE", "CLUSTER"

            }, available: false),

            AllowAdmin = true

        };


        ConnectionMultiplexer redis = ConnectionMultiplexer.Connect(config);


        // 获取数据库实例

        IDatabase db = redis.GetDatabase();


        // 写入数据

        bool setResult = db.StringSet("mykey", "Hello, Redis Cluster!");

        Console.WriteLine($"Set result: {setResult}");


        // 读取数据

        string getValue = db.StringGet("mykey");

        Console.WriteLine($"Get value: {getValue}");


        // 使用哈希表

        HashEntry[] hashFields = new HashEntry[]

        {

            new HashEntry("field1", "value1"),

            new HashEntry("field2", "value2")

        };

        db.HashSet("myhash", hashFields);


        string hashValue = db.HashGet("myhash", "field1");

        Console.WriteLine($"Hash field1 value: {hashValue}");


        // 使用列表

        long listLength = db.ListLeftPush("mylist", new RedisValue[] { "item1", "item2", "item3" });

        Console.WriteLine($"List length: {listLength}");


        RedisValue listItem = db.ListRightPop("mylist");

        Console.WriteLine($"Popped item: {listItem}");


        // 使用集合

        long addedCount = db.SetAdd("myset", new RedisValue[] { "member1", "member2", "member3" });

        Console.WriteLine($"Added set members: {addedCount}");


        bool isMember = db.SetContains("myset", "member2");

        Console.WriteLine($"Is 'member2' in set: {isMember}");


        // 关闭连接

        redis.Close();

    }

}

这个例子展示了如何连接到Redis集群,以及如何执行基本的读写操作,包括字符串、哈希表、列表和集合的操作。


注意事项:

在实际应用中,你应该使用适当的异常处理来处理可能出现的连接错误或其他异常。

ConnectionMultiplexer是线程安全的,应该被重用。通常,你会在应用程序启动时创建一个ConnectionMultiplexer实例,并在整个应用程序生命周期中重用它。

在集群模式下,某些复杂的多键操作(如事务)可能不被支持或需要特殊处理,因为keys可能分布在不同的节点上。

对于大规模应用,你可能需要考虑使用连接池来管理与Redis集群的连接。

通过这种方式,你可以有效地利用Redis集群的分布式特性,实现高可用性和可扩展性。














Top