You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

HighAvailabilityStrategy.cs 6.3 kB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. using Shadowsocks.Model;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Text;
  5. namespace Shadowsocks.Controller.Strategy
  6. {
  7. class HighAvailabilityStrategy : IStrategy
  8. {
  9. protected ServerStatus _currentServer;
  10. protected Dictionary<Server, ServerStatus> _serverStatus;
  11. ShadowsocksController _controller;
  12. Random _random;
  13. public class ServerStatus
  14. {
  15. // time interval between SYN and SYN+ACK
  16. public TimeSpan latency;
  17. public DateTime lastTimeDetectLatency;
  18. // last time anything received
  19. public DateTime lastRead;
  20. // last time anything sent
  21. public DateTime lastWrite;
  22. // connection refused or closed before anything received
  23. public DateTime lastFailure;
  24. public Server server;
  25. public double score;
  26. }
  27. public HighAvailabilityStrategy(ShadowsocksController controller)
  28. {
  29. _controller = controller;
  30. _random = new Random();
  31. _serverStatus = new Dictionary<Server, ServerStatus>();
  32. }
  33. public string Name
  34. {
  35. get { return I18N.GetString("High Availability"); }
  36. }
  37. public string ID
  38. {
  39. get { return "com.shadowsocks.strategy.ha"; }
  40. }
  41. public void ReloadServers()
  42. {
  43. // make a copy to avoid locking
  44. var newServerStatus = new Dictionary<Server, ServerStatus>(_serverStatus);
  45. foreach (var server in _controller.GetCurrentConfiguration().configs)
  46. {
  47. if (!newServerStatus.ContainsKey(server))
  48. {
  49. var status = new ServerStatus();
  50. status.server = server;
  51. status.lastFailure = DateTime.MinValue;
  52. status.lastRead = DateTime.Now;
  53. status.lastWrite = DateTime.Now;
  54. status.latency = new TimeSpan(0, 0, 0, 0, 10);
  55. status.lastTimeDetectLatency = DateTime.Now;
  56. newServerStatus[server] = status;
  57. }
  58. else
  59. {
  60. // update settings for existing server
  61. newServerStatus[server].server = server;
  62. }
  63. }
  64. _serverStatus = newServerStatus;
  65. ChooseNewServer();
  66. }
  67. public Server GetAServer(IStrategyCallerType type, System.Net.IPEndPoint localIPEndPoint)
  68. {
  69. if (type == IStrategyCallerType.TCP)
  70. {
  71. ChooseNewServer();
  72. }
  73. if (_currentServer == null)
  74. {
  75. return null;
  76. }
  77. return _currentServer.server;
  78. }
  79. /**
  80. * once failed, try after 5 min
  81. * and (last write - last read) < 5s
  82. * and (now - last read) < 5s // means not stuck
  83. * and latency < 200ms, try after 30s
  84. */
  85. public void ChooseNewServer()
  86. {
  87. ServerStatus oldServer = _currentServer;
  88. List<ServerStatus> servers = new List<ServerStatus>(_serverStatus.Values);
  89. DateTime now = DateTime.Now;
  90. foreach (var status in servers)
  91. {
  92. // all of failure, latency, (lastread - lastwrite) normalized to 1000, then
  93. // 100 * failure - 2 * latency - 0.5 * (lastread - lastwrite)
  94. status.score =
  95. 100 * 1000 * Math.Min(5 * 60, (now - status.lastFailure).TotalSeconds)
  96. -2 * 5 * (Math.Min(2000, status.latency.TotalMilliseconds) / (1 + (now - status.lastTimeDetectLatency).TotalSeconds / 30 / 10) +
  97. -0.5 * 200 * Math.Min(5, (status.lastRead - status.lastWrite).TotalSeconds));
  98. Logging.Debug(String.Format("server: {0} latency:{1} score: {2}", status.server.FriendlyName(), status.latency, status.score));
  99. }
  100. ServerStatus max = null;
  101. foreach (var status in servers)
  102. {
  103. if (max == null)
  104. {
  105. max = status;
  106. }
  107. else
  108. {
  109. if (status.score >= max.score)
  110. {
  111. max = status;
  112. }
  113. }
  114. }
  115. if (max != null)
  116. {
  117. if (_currentServer == null || max.score - _currentServer.score > 200)
  118. {
  119. _currentServer = max;
  120. Logging.Info($"HA switching to server: {_currentServer.server.FriendlyName()}");
  121. }
  122. }
  123. }
  124. public void UpdateLatency(Model.Server server, TimeSpan latency)
  125. {
  126. Logging.Debug($"latency: {server.FriendlyName()} {latency}");
  127. ServerStatus status;
  128. if (_serverStatus.TryGetValue(server, out status))
  129. {
  130. status.latency = latency;
  131. status.lastTimeDetectLatency = DateTime.Now;
  132. }
  133. }
  134. public void UpdateLastRead(Model.Server server)
  135. {
  136. Logging.Debug($"last read: {server.FriendlyName()}");
  137. ServerStatus status;
  138. if (_serverStatus.TryGetValue(server, out status))
  139. {
  140. status.lastRead = DateTime.Now;
  141. }
  142. }
  143. public void UpdateLastWrite(Model.Server server)
  144. {
  145. Logging.Debug($"last write: {server.FriendlyName()}");
  146. ServerStatus status;
  147. if (_serverStatus.TryGetValue(server, out status))
  148. {
  149. status.lastWrite = DateTime.Now;
  150. }
  151. }
  152. public void SetFailure(Model.Server server)
  153. {
  154. Logging.Debug($"failure: {server.FriendlyName()}");
  155. ServerStatus status;
  156. if (_serverStatus.TryGetValue(server, out status))
  157. {
  158. status.lastFailure = DateTime.Now;
  159. }
  160. }
  161. }
  162. }