引入一个大家都用的到的需求来说吧。

需求:要在三主三从的redis集群,存入数据,会对数据进行批量删除操作,数据要求要在redis集群负载均衡。

思路:

1.存入数据好办

1 var connect = ConnectionMultiplexer.Connect(redisConn);
2 var redisDb = connect.GetDatabase();
3 var res1 = redisDb.StringSet("1", DateTime.Now.ToString(), TimeSpan.FromSeconds(600));
4 var res2 = redisDb.StringSet("1111", DateTime.Now.ToString(), TimeSpan.FromSeconds(600));

2.批量删除直接异常

1 redisDb.KeyDelete(new RedisKey[] { "1", "1111" });

Ex:"Multi-key operations must involve a single slot; keys can use 'hash tags' to help this, i.e. '{/users/12345}/account' and '{/users/12345}/contacts' will always be in the same slot"

3.查到异常是因为redis hash slot 机制导致的,什么是 hash slot?
hash slot 介绍:https://redis.io/topics/cluster-tutorial

4.加上hash slot 字符串,让key进入同一个slot
var res1 = redisDb.StringSet("{myslot}key1", DateTime.Now.ToString(), TimeSpan.FromSeconds(600));
var res2 = redisDb.StringSet("{myslot}key2", DateTime.Now.ToString(), TimeSpan.FromSeconds(600));
redisDb.KeyDelete(new RedisKey[] { "{myslot}key1", "{myslot}key2" });
能进行批量操作,但是都被分配到了同一台服务器上的同一个槽点,不负载均衡。

5.如何负载均衡, 让Key分布到各个服务器,并且可以批量操作?
如果知道每个槽点对应的字符串,key可以按照算法计算出自己对应的字符串,加上后,就可以进行分组批量增删改操作。

6.hash slot 计算方法
HASH_SLOT = CRC16(key) mod 16384 (crc16-XMODEM)
介绍 :https://redis.io/topics/cluster-spec

7.net core 计算出16384个slot 字符串 算法例子和 结果模板

 1         static void Main(string[] args)
2 {
3 var data = new Dictionary<int, string>();
4 var i = 0;
5 while (data.Keys.Count < 16384)
6 {
7 var temp = i.ToString("X");
8 var value = Crc16(Encoding.UTF8.GetBytes(temp)) % 16384;
9 data[int.Parse(value.ToString())] = temp;
10 i++;
11
12 }
13 var sb = new StringBuilder();
14 foreach (var item in data.OrderBy(s => s.Key))
15 {
16 var temp = $"slot num:{item.Key} str:{item.Value} \r\n";
17 Console.WriteLine(temp);
18 sb.Append(temp);
19 }
20 File.WriteAllText("data.txt", sb.ToString());
21 Console.ReadLine();
22 }
23 private static ushort Crc16(byte[] bytes)
24 {
25 ushort poly = 0x1021;
26 ushort[] table = new ushort[256];
27 ushort initialValue = 0x0;
28 ushort temp, a;
29 ushort crc = initialValue;
30 for (int i = 0; i < table.Length; ++i)
31 {
32 temp = 0;
33 a = (ushort)(i << 8);
34 for (int j = 0; j < 8; ++j)
35 {
36 if (((temp ^ a) & 0x8000) != 0)
37 temp = (ushort)((temp << 1) ^ poly);
38 else
39 temp <<= 1;
40 a <<= 1;
41 }
42 table[i] = temp;
43 }
44 for (int i = 0; i < bytes.Length; ++i)
45 {
46 crc = (ushort)((crc << 8) ^ table[((crc >> 8) ^ (0xff & bytes[i]))]);
47 }
48 return crc;
49 }

  data.txt 文件下载

8.校验算出来的字符串 对应 的slot位置 是否正确

9.批量设置和批量删除方法
假定三主三从,那么三台服务器,取九个slot字符串,这九个是均分的位置(均分利于集群扩展)。即16384/10=1638 1638是第一位,1638*2是第二位,以此类推取字符串
共九个["1A73F","18B13","1AAD3","184FF","143BF","18413","17B8D","18BFF","1B1C4"]
先分组,再批量插入,再批量删除

 1 try
2 {
3 var redisConn = "{集群地址}";
4 var connect = ConnectionMultiplexer.Connect(redisConn);
5 var redisDb = connect.GetDatabase();
6 var res1 = redisDb.StringSet("1", DateTime.Now.ToString(), TimeSpan.FromSeconds(600));
7 var res2 = redisDb.StringSet("1111", DateTime.Now.ToString(), TimeSpan.FromSeconds(600));
8 redisDb.KeyDelete(new RedisKey[] { "1", "1111" });
9
10
11 var redisSlotKeyList = new string[] { "1A73F", "18B13", "1AAD3", "184FF", "143BF", "18413", "17B8D", "18BFF", "1B1C4" };
12 var userIdArray = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 };
13 //group
14 var dic = new Dictionary<int, Dictionary<RedisKey,RedisValue>>();
15 foreach (var userId in userIdArray)
16 {
17 var index = userId % redisSlotKeyList.Length;
18 var slotKey = redisSlotKeyList[index];
19 var redisKey = $"{{{slotKey}}}test_{userId}";
20 Console.WriteLine($"{ redisKey} {userId}");
21 if (dic.ContainsKey(index))
22 {
23 dic[index].Add(redisKey, DateTime.Now.ToLongTimeString());
24 }
25 else
26 {
27 dic[index] = new Dictionary<RedisKey, RedisValue> { { new RedisKey(redisKey), new RedisValue("values") } };
28 }
29 }
30
31 //set
32 foreach (var item in dic)
33 {
34 var addRes = redisDb.StringSet(item.Value.ToArray());
35 Console.WriteLine(addRes);
36 }
37
38
39 //delete
40 foreach (var item in dic)
41 {
42 var deleteRes = redisDb.KeyDelete(item.Value.Keys.ToArray());
43 Console.WriteLine(deleteRes);
44 }
45
46
47
48 }
49 catch (Exception ex)
50 {
51 throw ex;
52 }

10.注意点
集群的分割slot配置不一定的均分的,提前先查看,命令:cluster nodes。 查看之后再根据实际情况取slot string

C# redis集群批量操作之slot计算出16384个字符串的更多相关文章

  1. Redis集群批量操作

    Redis在3.0版正式引入了集群这个特性,扩展变得非常简单.然而当你开心的升级到3.0后,却发现有些很好用的功能现在工作不了了, 比如我们今天要聊的pipeline功能等批量操作. Redis集群是 ...

  2. 深入浅出—Redis集群的相关详解

    前言: 这篇文章主要介绍了Redis集群的相关,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值. 注意!要求使用的都是redis3.0以上的版本,因为3.0以上增加了red ...

  3. redis集群报错:(error) CLUSTERDOWN Hash slot not served

    百度上坑太多,如果你遇到搭建redis集群的时候出现这个错误在百度上找到解决办法基本上都是坑. 首先集群搭建完成后,你肯定去登陆redis进行测试 1.redis01/redis-cli -h &qu ...

  4. .NET使用Task动态创建多任务多线程并行程序计算Redis集群keys计算

    Task是一个很好用的多任务处理类,并且通过Task可以对任务进行很好的控制. 下面将通过代码实现Redis集群在使用IServer.keys时通过多任务对多个服务器示例进行并行计算,并对返回key做 ...

  5. redis集群错误解决:/usr/lib/ruby/gems/1.8/gems/redis-3.0.0/lib/redis/client.rb:79:in `call': ERR Slot 15495 is already busy (Redis::CommandError)

    错误信息: /usr/lib/ruby/gems/1.8/gems/redis-3.0.0/lib/redis/client.rb:79:in `call': ERR Slot 15495 is al ...

  6. Redis集群环境各节点无法互相发现与Hash槽分配异常 CLUSTERDOWN Hash slot not served的解决方式

    总结/朱季谦 在搭建Redis5.x版本的集群环境曾出现各节点无法互相发现与Hash槽分配异常 CLUSTERDOWN Hash slot not served的情况,故而把解决方式记录下来. 在以下 ...

  7. Redis集群最佳实践

    今天我们来聊一聊Redis集群.先看看集群的特点,我对它的理解是要需要同时满足高可用性以及可扩展性,即任何时候对外的接口都要是基本可用的并具备一定的灾备能力,同时节点的数量能够根据业务量级的大小动态的 ...

  8. redis 集群配置实战

    文章转载自:http://hot66hot.iteye.com/blog/2050676 最近研究Redis-cluster,正好搭建了一个环境,遇到了很多坑,系统的总结下,等到redis3 rele ...

  9. redis集群讨论

    一.生产应用场景 二.存储架构演变 三.应用最佳实践 四.运维经验总结 第1.2节:介绍redis cluster在唯品会的生产应用场景,以及存储架构的演变.第3节:redis cluster的稳定性 ...

随机推荐

  1. find for /f 分割字符串 bat

    @Echo off::总用例数For /f "tokens=2" %%i in ('Type bat.txt^|Find "Ran"') do (Echo %% ...

  2. 关于c++ string类的一些使用

    主要最近要用的上 才整理一下 用string类别忘了导入头文件 #include <string> 注意这个细节:cout 可直接输出 string 类的对象的内容 但是printf不可以 ...

  3. Python作业1

    name = " aleX" # 1 移除 name 变量对应的值两边的空格,并输出处理结果 print(name.strip()) # 2 判断 name 变量对应的值是否以 & ...

  4. Sysbench测试神器:一条命令生成百万级测试数据

    1. 基准测试 基准测试(benchmarking)是性能测试的一种类型,强调的是对一类测试对象的某些性能指标进行定量的.可复现.可对比的测试. 进一步来理解,基准测试是在某个时候通过基准测试建立一个 ...

  5. vue-router入门随笔

    下面整理根据官方文档以及自我理解整理,如有不足,请指教. 下面是来自一段官方的原话. Vue Router 是 Vue.js 官方的路由管理器.它和 Vue.js 的核心深度集成,让构建单页面应用变得 ...

  6. src/plugins/Export2Excel.js(目录没有可以重建)

    第一步Install cnpm install file-saver 或者 yarn add file-saver cnpm install xlsx 或者 yarn add xlsx cnpm in ...

  7. mysql 事务的日志

    事务的日志 1.redo log redo:"重做",记录的是,内存数据页的变化过程 1)作用 在事务ACID过程中,实现的是 "D" 持久化的作用. 2)工作 ...

  8. 记录电子竞技游戏jesp中的传输过程公式

    1.json数据转换成字典 dict1 = json.load(load_f1) dict2 = json.load(load_f2) 2.将两个字典按key排好序,然后使用zip()函数将两个字典对 ...

  9. RabbitMQ的简单封装

    一般在工作中,都是直接使用已经封装好的mq的程序集进行功能开发.所以很多时候都没有去了解rabbitmq到底是如何封装(实现使用的).所以心血来潮,简单记录下自己对rabbitmq的简单封装 整体的思 ...

  10. 1_Two Sum

    1.Two Sum Given an array of integers, return indices of the two numbers such that they add up to a s ...