常用负载均衡算法及实现
1.轮询负载均衡算法
1 /// <summary> 2 /// 轮询负载均衡算法 3 /// </summary> 4 public static class RoundRobin 5 { 6 private static object obj = new object(); 7 8 static Dictionary<string, int> dic = new Dictionary<string, int> 9 { 10 { "192.168.1.12", 1}, 11 {"192.168.1.13", 1 }, 12 { "192.168.1.14", 3}, 13 { "192.168.1.15", 1}, 14 {"192.168.1.16", 1}, 15 {"192.168.1.17", 1 }, 16 { "192.168.1.18", 1}, 17 { "192.168.1.19", 1} 18 }; 19 20 static int pos = 0; 21 public static string roundRobin() 22 { 23 var keyList = dic.Keys.ToList(); 24 25 26 string server = null; 27 28 lock (obj) 29 { 30 if (pos >= keyList.Count) 31 { 32 pos = 0; 33 } 34 server = keyList[pos]; 35 pos++; 36 } 37 return server; 38 } 39 } 40 41 优点: 42 请求分配平均 43 缺点: 44 不能根据机器配置的好坏进行分配
1 /// <summary> 2 /// 加权轮询算法 3 /// </summary> 4 public static class WeightRoundRobin 5 { 6 private static object obj = new object(); 7 private static int pos = 0; 8 9 static Dictionary<string, int> dic = new Dictionary<string, int> 10 { 11 { "192.168.1.12", 1}, 12 {"192.168.1.13", 1 }, 13 { "192.168.1.14", 3}, 14 { "192.168.1.15", 1}, 15 {"192.168.1.16", 1}, 16 {"192.168.1.17", 1 }, 17 { "192.168.1.18", 1}, 18 { "192.168.1.19", 1} 19 }; 20 21 public static string roundRobin() 22 { 23 //獲取ip列表list 24 List<string> it = dic.Keys.ToList(); 25 26 List<String> serverList = new List<string>(); 27 28 foreach (var item in it) 29 { 30 int weight = 0; 31 dic.TryGetValue(item, out weight); 32 33 for (int i = 0; i < weight; i++) 34 { 35 serverList.Add(item); 36 } 37 } 38 39 string server = null; 40 41 lock (obj) 42 { 43 if (pos >= serverList.Count) 44 { 45 pos = 0; 46 } 47 server = serverList[pos]; 48 pos++; 49 } 50 return server; 51 } 52 53 }
3.加权随机负载均衡算法
1 /// <summary> 2 /// 加权随机负载均衡算法 3 /// </summary> 4 public static class WeightRandom 5 { 6 7 static Dictionary<string, int> dic = new Dictionary<string, int> 8 { 9 { "192.168.1.12", 1}, 10 {"192.168.1.13", 1 }, 11 { "192.168.1.14", 3}, 12 { "192.168.1.15", 1}, 13 {"192.168.1.16", 1}, 14 {"192.168.1.17", 1 }, 15 { "192.168.1.18", 1}, 16 { "192.168.1.19", 1} 17 }; 18 19 public static string weightRandom() 20 { 21 //獲取ip列表list 22 List<string> it = dic.Keys.ToList(); 23 24 List<String> serverList = new List<string>(); 25 26 foreach (var item in it) 27 { 28 int weight = 0; 29 dic.TryGetValue(item, out weight); 30 31 for (int i = 0; i < weight; i++) 32 { 33 serverList.Add(item); 34 } 35 } 36 Random random = new Random(); 37 int randomPos = random.Next(serverList.Count); 38 string server = serverList[randomPos]; 39 return server; 40 } 41 }
1 /// <summary> 2 /// IP Hash负载均衡算法 3 /// </summary> 4 public static class IpHash 5 { 6 static Dictionary<string, int> dic = new Dictionary<string, int> 7 { 8 { "192.168.1.12", 1}, 9 {"192.168.1.13", 1 }, 10 { "192.168.1.14", 3}, 11 { "192.168.1.15", 1}, 12 {"192.168.1.16", 1}, 13 {"192.168.1.17", 1 }, 14 { "192.168.1.18", 1}, 15 { "192.168.1.19", 1} 16 }; 17 18 public static string ipHash(string remoteIp) 19 { 20 List<string> keys = dic.Keys.ToList(); 21 22 int hashCode = Math.Abs(remoteIp.GetHashCode()); 23 int serverListSize = keys.Count; 24 int serverPos = hashCode % serverListSize; 25 26 return keys[serverPos]; 27 } 28 29 }
1 测试:private static void TestIdWorker() 2 { 3 HashSet<long> set = new HashSet<long>(); 4 IdWorker idWorker1 = new IdWorker(0, 0); 5 IdWorker idWorker2 = new IdWorker(1, 0); 6 //762884413578018816 7 //762884520121729024 8 Stopwatch sw = new Stopwatch(); 9 sw.Start(); 10 for (int i = 0; i < 1; i++) 11 { 12 long id = idWorker1.nextId(); 13 set.Add(id); 14 //if (!set.Add(id)) 15 //{ 16 //Console.WriteLine("duplicate:" + id); 17 //} 18 } 19 sw.Stop(); 20 foreach (var item in set) 21 { 22 Console.WriteLine("结果:" + item); 23 } 24 Console.WriteLine("时间:" + sw.ElapsedTicks); 25 return; 26 } 27 28 29 算法: 30 31 /// <summary> 32 /// From: https://github.com/twitter/snowflake 33 /// An object that generates IDs. 34 /// This is broken into a separate class in case 35 /// we ever want to support multiple worker threads 36 /// per process 37 /// </summary> 38 public class IdWorker 39 { 40 private long workerId; 41 private long datacenterId; 42 private long sequence = 0L; 43 44 private static long twepoch = 1288834974657L; 45 46 private static long workerIdBits = 5L; 47 private static long datacenterIdBits = 5L; 48 private static long maxWorkerId = -1L ^ (-1L << (int)workerIdBits); 49 private static long maxDatacenterId = -1L ^ (-1L << (int)datacenterIdBits); 50 private static long sequenceBits = 12L; 51 52 private long workerIdShift = sequenceBits; 53 private long datacenterIdShift = sequenceBits + workerIdBits; 54 private long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits; 55 private long sequenceMask = -1L ^ (-1L << (int)sequenceBits); 56 57 private long lastTimestamp = -1L; 58 private static object syncRoot = new object(); 59 60 public IdWorker(long workerId, long datacenterId) 61 { 62 63 // sanity check for workerId 64 if (workerId > maxWorkerId || workerId < 0) 65 { 66 throw new ArgumentException(string.Format("worker Id can't be greater than %d or less than 0", maxWorkerId)); 67 } 68 if (datacenterId > maxDatacenterId || datacenterId < 0) 69 { 70 throw new ArgumentException(string.Format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId)); 71 } 72 this.workerId = workerId; 73 this.datacenterId = datacenterId; 74 } 75 76 public long nextId() 77 { 78 lock (syncRoot) 79 { 80 long timestamp = timeGen(); 81 82 if (timestamp < lastTimestamp) 83 { 84 throw new ApplicationException(string.Format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp)); 85 } 86 87 if (lastTimestamp == timestamp) 88 { 89 sequence = (sequence + 1) & sequenceMask; 90 if (sequence == 0) 91 { 92 timestamp = tilNextMillis(lastTimestamp); 93 } 94 } 95 else 96 { 97 sequence = 0L; 98 } 99 100 lastTimestamp = timestamp; 101 102 return ((timestamp - twepoch) << (int)timestampLeftShift) | (datacenterId << (int)datacenterIdShift) | (workerId << (int)workerIdShift) | sequence; 103 } 104 } 105 106 protected long tilNextMillis(long lastTimestamp) 107 { 108 long timestamp = timeGen(); 109 while (timestamp <= lastTimestamp) 110 { 111 timestamp = timeGen(); 112 } 113 return timestamp; 114 } 115 116 protected long timeGen() 117 { 118 return (long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds; 119 } 120 }