C# servicestack.redis 互通 java jedis

拥抱变化,如今也走上了.net/java通吃的时代,下面就讲讲如何让.net/java都能正常访问分片的redis吧。

有几个关键点:一致性环哈希、哈希算法、序列化、反序列化

后两个都比较直接,只要选择一种跨语言的序列化方式就行了,如:json, protobuf, ace等,本文全略了

本文是基于jedis的一致性环哈希来修改的,.net选的是servicestack.redis组件来修改

无奈两个组件都有各自的一致性环哈希算法,不兼容,那就选一个作为标准,修改另一个咯。本文选择jedis的一致性环哈希作为标准,进而修改.net来适应jedis

jedis的逻辑是给每个redis节点构造160个虚拟节点,放入一颗二叉树中(key/value:key是一个long值,根据哈希算法算出来的一个long、value是节点id,是个string)。

OK,逻辑清楚了,那就简单了,给c#端写个一模一样的一致性环哈希算法。

public class Sharded
    {
        private object nodes_lock = new object();
        private RedBlackTreeMap<long, string> nodes = new RedBlackTreeMap<long, string>();
        private IHash hashAlgo = new MD5_LongSUM_Multiply_Hash();

        public void AddTarget(int index, string shard)
        {
            lock (nodes_lock)
            {
                for (int n = 0; n < 160; ++n)
                {
                    var hashKey = "SHARD-" + index + "-NODE-" + n;

                    long hashValue = this.hashAlgo.Hash(hashKey);

                    nodes.SetOrAddValue(hashValue, shard);
                }
            }
        }

        public string GetShardInfo(string key)
        {
            long searchHashKey = this.hashAlgo.Hash(key);

            long nearestKey;
            string shard;

            lock (nodes_lock)
            {
                if (this.nodes.NearestGreater(searchHashKey, out nearestKey))
                {
                    shard = this.nodes.GetValue(nearestKey);
                    return shard;
                }

                if (this.nodes.Least(out searchHashKey, out shard))
                    return shard;
            }

            throw new Exception("GetShardInfo exception");
        }
    }

其中RedBlackTreeMap这个是TreeLib中的组件,需要在nuget上引用。

MD5_LongSUM_Multiply_Hash,这是个MD5算法,输入为string,输出为long。此处由于考虑到输出不是string,因此自己又改了改,让他输出long
public class MD5_LongSUM_Multiply_Hash : IHash
    {
        public long Hash(string key)
        {
            var md5= Md5Hash(key);

            if (string.IsNullOrEmpty(md5))
                Log.GetLog().Info("Hash, md5 is null or empty");

            var convertedKeyBytes = Encoding.UTF8.GetBytes(md5);

            long value = 1;

            foreach(var b in convertedKeyBytes)
                value *= b*-1;

            return value;
        }

        private string Md5Hash(string input)
        {
            MD5CryptoServiceProvider md5Hasher = new MD5CryptoServiceProvider();

            if (string.IsNullOrEmpty(input))
                Log.GetLog().Info("Md5Hash, input is null or empty");

            byte[] data = md5Hasher.ComputeHash(Encoding.Default.GetBytes(input));
            StringBuilder sBuilder = new StringBuilder();
            for (int i = 0; i < data.Length; i++)
            {
                sBuilder.Append(data[i].ToString("x2"));
            }
            return sBuilder.ToString();
        }
    }

剩下的就是java端的这个输入string,输出long的算法,需要和.net的输入输出一致了。

那就也写一个哈希算法,让他输入string,输出long,和.net的一致,这里只要java/.net用同一种md5算法,后续的md5变成long就很容易了。

import org.springframework.security.authentication.encoding.MessageDigestPasswordEncoder;
import redis.clients.util.Hashing;
import redis.clients.util.SafeEncoder;

import java.io.UnsupportedEncodingException;

/**
 * Created by z on 2017/4/12.
 */
public class MD5_SUM_Hash implements Hashing {

    MessageDigestPasswordEncoder encoder=new MessageDigestPasswordEncoder("MD5");

    public long hash(String key) {
        return this.hash(SafeEncoder.encode(key));
    }

    public long hash(byte[] bytes) {

        String converted_str= null;
        try {
            converted_str = new String(bytes, "UTF8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        String result=encoder.encodePassword(converted_str, null);

        try {
            bytes=result.getBytes("UTF8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        long value = 1;
        for(byte b : bytes)
            value *= b*-1;
        return value;
    }
}
<dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-core</artifactId>
        </dependency>

OK,核心的就这些了。

时间: 2024-10-12 03:23:59

C# servicestack.redis 互通 java jedis的相关文章

[转载] 使用Redis的Java客户端Jedis

转载自http://aofengblog.blog.163.com/blog/static/631702120147298317919/ 在实际的项目开发中,各种语言是使用Redis的客户端库来与Redis交互.针对Java语言,Redis官方推荐Jedis. Jedis提供了多种操作方式:单机单连接方式.单机连接池方式.多机分布式+连接池方式. 预备 jedis-2.5.2commons-pool2-2.2.jar 使用单连接 此方式仅建议用于开发环境做调试用. // 创建连接String h

使用Redis的Java客户端Jedis

转载自:http://aofengblog.blog.163.com/blog/static/631702120147298317919/ 前一篇文章<Redis命令指南>讲解了通过命令行的方式执行Key=>的存储操作,在实际的项目开发中,各种语言是使用Redis的客户端库来与Redis交互.针对Java语言,Redis官方推荐Jedis. Jedis提供了多种操作方式:单机单连接方式.单机连接池方式.多机分布式+连接池方式. 预备 jedis-2.5.2commons-pool2-2.

redis的java客户端Jedis简单封装

经过我们团队的一番讨论,最终决定使用redis来进行我们的业务缓存.redis会将数据缓存到内存中,运行效率会很快.同时异步将数据写入到磁盘中,进行持久化. 且redis支持主从同步,支持分布式部署,支持N多数据结构,这对于我们有着莫大的吸引力. 参见:http://blog.csdn.net/yichenlian/article/details/27207383 我们团队讨论的焦点是在于redis的灾备恢复问题.由于redis的持久化是异步的,总会有一点时间内存中数据和磁盘数据不同步的情况(当

4. Redis与Java的使用

本文主要讲解java如何操作redis. 使用java连接redis需要引入相应jedis的jar包. java连接单个redis.redis连接池.redis集群(稍后在讲解) //连接单个redis服务器 Jedis jedis= new Jedis("192.168.0.100", 6379); //连接redis线程池 //redis配置对象 JedisPoolConfig config = new JedisPoolConfig(); //可用redis连接实例的最大数目 c

redis学习 java redis应用

学习redis的总结 :  http://www.runoob.com/redis/redis-tutorial.html     http://www.redis.cn/   一个是菜鸟网站,一个是redis中文网可以进行学习 下面是关于学过redis之后的总结,只是浅显的入门用于对只是的记录 : window :    下载redis  ,,通过cmd 命令行进入 :   执行 redis-server  启动服务端,   然后才能执行redis-cli 启动客户端进行操作   具体的命令可

Redis 在 Java 中的使用

转:http://blog.csdn.net/jiangtao_st/article/details/8256610 一.下载jar包 https://github.com/xetorthio/jedis/downloads 学习参考内容 : http://blog.nosqlfan.com/html/3537.html 二.在spring 中的配置 <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisP

Redis与Java - 数据结构

Redis与Java 标签 : Java与NoSQL Redis(REmote DIctionary Server) is an open source (BSD licensed), in-memory data structure store, used as database, cache and message broker. It supports data structures such as strings, hashes, lists, sets, sorted sets wit

redis 在java中的使用

1.首先下载jar包放到你的工程中 2.练习 package com.jianyuan.redisTest; import java.util.Iterator;import java.util.List;import java.util.Set; import redis.clients.jedis.Jedis; public class RedisTest { public static void main(String[] args) { //连接本地的Redis服务 Jedis jedi

Redis之java增删改查

jedis是java的redis客户端实现,要使用jedis需要添加jedis的maven依赖: <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.4.2</version> </dependency>redis最简单的使用:Jedis jedis = new Jedis("l