• C# redis集群批量操作之slot计算出16384个字符串


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


    需求:要在三主三从的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} 
    ";
    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             }
    View Code

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

  • 相关阅读:
    ArrayList类(转)
    通过XmlDocument读写Xml文档(转)
    js的一些常用方法
    和我一起恶补pl/sql(第三讲)
    js的跑步算法
    细说 Form (表单)(转)
    C#反射设置和读取类的属性
    显示最近30天的记录vs显示这个月的记录(pl\sql)
    nyist 637 我和你
    nyist 子串和
  • 原文地址:https://www.cnblogs.com/TeemoHQ/p/14035055.html
Copyright © 2020-2023  润新知