標籤:node frame ima sage dig result ted nuget size
擁抱變化,如今也走上了.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,核心的就這些了。
C# servicestack.redis 互連 java jedis