好贷网好贷款

ASP.NET版Memcached监控工具

发布时间:2016-12-4 22:33:47 编辑:www.fx114.net 分享查询网我要评论
本篇文章主要介绍了"ASP.NET版Memcached监控工具",主要涉及到ASP.NET版Memcached监控工具方面的内容,对于ASP.NET版Memcached监控工具感兴趣的同学可以参考一下。

在上一篇文章《使用Memcached提高.NET应用程序的性能》中周公讲述如何在.NET中使用Memcached来提高.NET应用程序的性 能。在实际的使用中有可能出现Memcached因为某些不可预知的原因挂掉,一旦出现这样的情况,就会再次给数据库增加巨大的压力,因此需要监控 Memcached的运行情况。周公在网上找过,在网上有PHP版的Memcached监控工具,打开那个PHP页面就可以看到各个Memcached的 运行情况,一旦不能获取到这些数据,说明Memcached不可访问,不可访问的原因可能是因为网络故障或者Memcached挂掉了,虽然原因不同,但 是结果是一样的。参照了Enyim Memcached和PHP版Memcached监控工具的实现,周公实现了一个.NET版的监控工具。 实现思路 上一篇文章《使用Memcached提高.NET应用程序的性能》中周公讲述了可以通过Telnet来获取Memcached的运行状况,通 过"stats"命令得到Memcached的数据,如果得不到相应的数据就证明Memcached不可访问。 其中向Memcached发送"stats"命令得到的数据的意义如下: pid:32u,服务器进程ID。 uptime:32u, 服务器运行时间,单位秒。 time :32u, 服务器当前的UNIX时间。 version :string, 服务器的版本号。 curr_items :32u, 服务器当前存储的内容数量 Current number of items stored by the server total_items :32u, 服务器启动以来存储过的内容总数。 bytes :64u, 服务器当前存储内容所占用的字节数。 curr_connections :32u, 连接数量。 total_connections :32u, 服务器运行以来接受的连接总数。 connection_structures:32u, 服务器分配的连接结构的数量。 cmd_get :32u, 取回请求总数。 cmd_set :32u, 存储请求总数。 get_hits :32u, 请求成功的总次数。 get_misses :32u, 请求失败的总次数。 bytes_read :64u, 服务器从网络读取到的总字节数。 bytes_written :64u, 服务器向网络发送的总字节数。 limit_maxbytes :32u, 服务器在存储时被允许使用的字节总数。 上面的描述中32u和64u表示32位和64位无符号整数,string表示是string类型数据。 在本篇中我们通过Socket而不是Telnet连接到Memcached,然后解析返回的数据。 程序代码 为了便于管理和维护,在本示例中使用了单页模式,也就是所有的代码都在一个ASPX页面中,没有对应的aspx.cs页面。 程序代码如下:   <%@ Page Language="C#" %> <%@ Import Namespace="System" %> <%@ Import Namespace="System.IO" %> <%@ Import Namespace="System.Net" %> <%@ Import Namespace="System.Net.Sockets" %> <%@ Import Namespace="System.Collections.Generic" %> <%@ Import Namespace="System.Threading" %> <%@ Import Namespace="System.Security" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  <script runat="server"> /*   * 作者:周公   * 日期:2011-03-27   * 原文出处:http://blog.csdn.net/zhoufoxcn 或http://zhoufoxcn.blog.51cto.com   * 版权说明:本文可以在保留原文出处的情况下使用于非商业用途,周公对此不作任何担保或承诺。   * */            /// <summary>     /// Memcached服务器监控类      /// </summary>     public class MemcachedMonitor      {          /// <summary>         /// 连接Memcached的超时时间          /// </summary>         public TimeSpan ConnectionTimeout { get; set; }          /// <summary>         /// 接收Memcached返回数据的超时时间          /// </summary>         public TimeSpan ReceiveTimeout { get; set; }          private List<IPEndPoint> serverList;          public MemcachedMonitor(ICollection<IPEndPoint> list)          {              ConnectionTimeout = TimeSpan.FromSeconds(10);              ReceiveTimeout = TimeSpan.FromSeconds(20);              serverList = new List<IPEndPoint>();              serverList.AddRange(list);          }           public List<MemcachedServerStats> GetAllServerStats()          {              List<MemcachedServerStats> resultList = new List<MemcachedServerStats>();              foreach (IPEndPoint endPoint in serverList)              {                  resultList.Add(GetServerStats(endPoint, ConnectionTimeout, ReceiveTimeout));              }              return resultList;          }           public static MemcachedServerStats GetServerStats(IPEndPoint ip, TimeSpan connectionTimeout, TimeSpan receiveTimeout)          {              MemcachedSocket socket = new MemcachedSocket(ip, connectionTimeout, receiveTimeout);              MemcachedServerStats stats = socket.GetStats();              return stats;          }           public static IPEndPoint Parse(string hostName,int port)          {              IPHostEntry host=Dns.GetHostEntry(hostName);              IPEndPoint endPoint = null;              foreach (IPAddress ip in host.AddressList)              {                  if (ip.AddressFamily == AddressFamily.InterNetwork)                  {                      endPoint = new IPEndPoint(ip, port);                      break;                  }              }              return endPoint;          }      }      /// <summary>     /// Memcached服务器运行状态数据类,只有当IsReachable为true时获取的数据才有意义,否则表示不可访问或者Memcached挂了      /// </summary>     public class MemcachedServerStats      {          private Dictionary<string, string> results;          /// <summary>         /// 是否可访问,如果不可访问表示网络故障或者Memcached服务器Down掉了          /// </summary>         public bool IsReachable { get; set; }          /// <summary>         /// 服务器运行时间,单位秒(32u)          /// </summary>         public UInt32 Uptime { get; set; }          /// <summary>         /// 服务器当前的UNIX时间(32u)          /// </summary>         public UInt32 Time { get; set; }          /// <summary>         /// 服务器的版本号(string)          /// </summary>         public string Version { get; set; }          /// <summary>         /// 服务器当前存储的内容数量(32u)          /// </summary>         public UInt32 Curr_Items { get; set; }          /// <summary>         /// 服务器启动以来存储过的内容总数(32u)          /// </summary>         public UInt32 Total_Items { get; set; }          /// <summary>         /// 连接数量(32u)          /// </summary>         public UInt32 Curr_Connections { get; set; }          /// <summary>         /// 服务器运行以来接受的连接总数(32u)          /// </summary>         public UInt32 Total_Connections { get; set; }          /// <summary>         /// 服务器分配的连接结构的数量(32u)          /// </summary>         public UInt32 Connection_Structures { get; set; }          /// <summary>         /// 取回请求总数(32u)          /// </summary>         public UInt32 Cmd_Get { get; set; }          /// <summary>         /// 存储请求总数(32u)          /// </summary>         public UInt32 Cmd_Set { get; set; }          /// <summary>         /// 请求成功的总次数(32u)          /// </summary>         public UInt32 Get_Hits { get; set; }          /// <summary>         /// 请求失败的总次数(32u)          /// </summary>         public UInt32 Get_Misses { get; set; }          /// <summary>         /// 服务器当前存储内容所占用的字节数(64u)          /// </summary>         public UInt64 Bytes { get; set; }          /// <summary>         /// 服务器从网络读取到的总字节数(64u)          /// </summary>         public UInt64 Bytes_Read { get; set; }          /// <summary>         /// 服务器向网络发送的总字节数(64u)          /// </summary>         public UInt64 Bytes_Written { get; set; }          /// <summary>         /// 服务器在存储时被允许使用的字节总数(32u)          /// </summary>         public UInt32 Limit_Maxbytes { get; set; }          public IPEndPoint IPEndPoint { get; set; }           public MemcachedServerStats(IPEndPoint endpoint)          {              if (endpoint == null)              {                  throw new ArgumentNullException("endpoint can't be null");              }              IPEndPoint = endpoint;          }           public MemcachedServerStats(IPEndPoint endpoint, Dictionary<string, string> results)          {              if (endpoint == null || results == null)              {                  throw new ArgumentNullException("point and result can't be null");              }              IPEndPoint = endpoint;           }           public void InitializeData(Dictionary<string, string> results)          {              if (results == null)              {                  throw new ArgumentNullException("result can't be null");              }              this.results = results;              Uptime = GetUInt32("uptime");              Time = GetUInt32("time");              Version = GetRaw("version");              Curr_Items = GetUInt32("curr_items");              Total_Items = GetUInt32("total_items");              Curr_Connections = GetUInt32("curr_connections");              Total_Connections = GetUInt32("total_connections");              Connection_Structures = GetUInt32("connection_structures");              Cmd_Get = GetUInt32("cmd_get");              Cmd_Set = GetUInt32("cmd_set");              Get_Hits = GetUInt32("get_hits");              Get_Misses = GetUInt32("get_misses");              Bytes = GetUInt64("bytes");              Bytes_Read = GetUInt64("bytes_read");              Bytes_Written = GetUInt64("bytes_written");              Limit_Maxbytes = GetUInt32("limit_maxbytes");          }           private string GetRaw(string key)          {              string value = string.Empty;              results.TryGetValue(key, out value);              return value;          }           private UInt32 GetUInt32(string key)          {              string value = GetRaw(key);              UInt32 uptime;              UInt32.TryParse(value, out uptime);              return uptime;          }           private UInt64 GetUInt64(string key)          {              string value = GetRaw(key);              UInt64 uptime;              UInt64.TryParse(value, out uptime);              return uptime;          }      }      /// <summary>     /// 与Memcached服务器通讯的Socket封装      /// </summary>     internal class MemcachedSocket : IDisposable      {          private const string CommandString = "stats\r\n";//发送查询Memcached状态的指令,以"\r\n"作为命令的结束          private const int ErrorResponseLength = 13;          private const string GenericErrorResponse = "ERROR";          private const string ClientErrorResponse = "CLIENT_ERROR ";          private const string ServerErrorResponse = "SERVER_ERROR ";          private Socket socket;          private IPEndPoint endpoint;          private BufferedStream bufferedStream;          private NetworkStream networkStream;           public MemcachedSocket(IPEndPoint ip, TimeSpan connectionTimeout, TimeSpan receiveTimeout)          {              if (ip == null)              {                  throw new ArgumentNullException("ip", "不能为空!");              }              endpoint = ip;               socket = new Socket(endpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);               socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, connectionTimeout == TimeSpan.MaxValue ? Timeout.Infinite : (int)connectionTimeout.TotalMilliseconds);              socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, receiveTimeout == TimeSpan.MaxValue ? Timeout.Infinite : (int)receiveTimeout.TotalMilliseconds);               // all operations are "atomic", we do not send small chunks of data              socket.NoDelay = true;          }          /// <summary>         /// 获取Memcached的运行状态          /// </summary>         /// <returns></returns>         public MemcachedServerStats GetStats()          {              MemcachedServerStats stats = new MemcachedServerStats(endpoint);              try              {                  socket.Connect(endpoint);                  networkStream = new NetworkStream(socket);                  bufferedStream = new BufferedStream(networkStream);                  byte[] buffer = Encoding.ASCII.GetBytes(CommandString);                   SocketError socketError;                  socket.Send(buffer, 0, buffer.Length, SocketFlags.None, out socketError);                  if (socketError != SocketError.Success)                  {                      stats.IsReachable = false;                  }                  else                  {                      stats.IsReachable = true;                      string result = ReadLine();                      Dictionary<string, string> serverData = new Dictionary<string, string>(StringComparer.Ordinal);                      while (!string.IsNullOrEmpty(result))                      {                          // 返回的数据信息以"END"作为结束标记                          if (String.Compare(result, "END", StringComparison.Ordinal) == 0)                              break;                           //期望的响应格式是:"STAT 名称 值"(注意"STAT 名称 值"之间有空格)                          if (result.Length < 6 || String.Compare(result, 0, "STAT ", 0, 5, StringComparison.Ordinal) != 0)                          {                              continue;                          }                           //获取以空格作为分隔符的键值对                          string[] parts = result.Remove(0, 5).Split(' ');                          if (parts.Length != 2)                          {                              continue;                          }                          serverData[parts[0]] = parts[1];                          result = ReadLine();                      }                      stats.InitializeData(serverData);                  }              }              catch (Exception exception)              {                  stats.IsReachable = false;                  //Debug.WriteLine("Exception Message:" + exception.Message);              }              finally              {              }              return stats;           }          /// <summary>         /// 从远程主机的响应流中读取一行数据          /// </summary>         /// <returns></returns>         private string ReadLine()          {              MemoryStream ms = new MemoryStream(50);               bool gotR = false;              byte[] buffer = new byte[1];              int data;               try              {                  while (true)                  {                      data = bufferedStream.ReadByte();                       if (data == 13)                      {                          gotR = true;                          continue;                      }                       if (gotR)                      {                          if (data == 10)                              break;                           ms.WriteByte(13);                           gotR = false;                      }                       ms.WriteByte((byte)data);                  }              }              catch (IOException)              {                   throw;              }               string retureValue = Encoding.ASCII.GetString(ms.GetBuffer(), 0, (int)ms.Length);                if (String.IsNullOrEmpty(retureValue))                  throw new Exception("接收到空响应。");               if (String.Compare(retureValue, GenericErrorResponse, StringComparison.Ordinal) == 0)                  throw new NotSupportedException("无效的指令。");               if (retureValue.Length >= ErrorResponseLength)              {                  if (String.Compare(retureValue, 0, ClientErrorResponse, 0, ErrorResponseLength, StringComparison.Ordinal) == 0)                  {                      throw new Exception(retureValue.Remove(0, ErrorResponseLength));                  }                  else if (String.Compare(retureValue, 0, ServerErrorResponse, 0, ErrorResponseLength, StringComparison.Ordinal) == 0)                  {                      throw new Exception(retureValue.Remove(0, ErrorResponseLength));                  }              }               return retureValue;          }           public void Dispose()          {              if (socket != null)              {                  socket.Shutdown(SocketShutdown.Both);              }              socket = null;              networkStream.Dispose();              networkStream = null;              bufferedStream.Dispose();              bufferedStream = null;          }      }  </script>  <html xmlns="http://www.w3.org/1999/xhtml"> <head>     <title>ASP.NET版Memcached监控工具</title>     <style>         a {      color:#000000;      text-decoration:none;  }  a.current {      color:#0000FF;  }  a:hover {      text-decoration: none;  }  body {      font-family: verdana, geneva,tahoma, helvetica, arial, sans-serif;      font-size: 100%;      background-color:#FFFFFF;      margin: 0em;  }  ul {      font-size:80%;      color:#666666;      line-height: 1.5em;      list-style: none;  }      </style> </head> <body> <table border="0"> <tr><th>IP</th><th>Version</th><th>IsReachable</th><th>Bytes</th><th>Bytes_Read</th><th>Bytes_Written</th><th>Cmd_Get</th><th>Cmd_Set</th><th>Curr_Connections</th><th>Curr_Items</th><th>Get_Hits</th><th>Get_Misses</th><th>Limit_Maxbytes</th><th>Total_Items</th></tr> <%      String format = "<tr><td>{0}</td><td>{1}</th><th>{2}</th><th>{3}</th><th>{4}</th><th>{5}</th><th>{6}</th><th>{7}</th><th>{8}</th><th>{9}</th><th>{10}</th><th>{11}</th><th>{12}</th><th>{13}</th></tr>";      List<IPEndPoint> list = new List<IPEndPoint> { new IPEndPoint(IPAddress.Parse("127.0.0.1"), 11121), MemcachedMonitor.Parse("localhost",11131) };      MemcachedMonitor monitor = new MemcachedMonitor(list);      List<MemcachedServerStats> resultList = monitor.GetAllServerStats();      string result=string.Empty;      foreach (MemcachedServerStats stats in resultList)      {          result = string.Format(format, stats.IPEndPoint, stats.Version,stats.IsReachable, stats.Bytes, stats.Bytes_Read, stats.Bytes_Written, stats.Cmd_Get, stats.Cmd_Set, stats.Curr_Connections, stats.Curr_Items, stats.Get_Hits, stats.Get_Misses, stats.Limit_Maxbytes, stats.Total_Items);          Response.Write(result);      }  %> </table> 这些数据所代表的意义如下:  <ul> <li>pid:32u,服务器进程ID。</li>   <li>uptime:32u, 服务器运行时间,单位秒。</li>   <li>time :32u, 服务器当前的UNIX时间。</li> <li>version :string, 服务器的版本号。 </li> <li>curr_items :32u, 服务器当前存储的内容数量</li>   <li>total_items :32u, 服务器启动以来存储过的内容总数。</li> <li>bytes :64u, 服务器当前存储内容所占用的字节数。</li> <li>curr_connections :32u, 连接数量。 </li> <li>total_connections :32u, 服务器运行以来接受的连接总数。</li> <li>connection_structures:32u, 服务器分配的连接结构的数量。</li>   <li>cmd_get :32u, 取回请求总数。 </li> <li>cmd_set :32u, 存储请求总数。 </li> <li>get_hits :32u, 请求成功的总次数。</li> <li>get_misses :32u, 请求失败的总次数。</li> <li>bytes_read :64u, 服务器从网络读取到的总字节数。</li> <li>bytes_written :64u, 服务器向网络发送的总字节数。</li> <li>limit_maxbytes :32u, 服务器在存储时被允许使用的字节总数。</li> </ul> 上面的描述中32u和64u表示32位和64位无符号整数,string表示是string类型数据。<br /> 作者博客:<a href="http://blog.csdn.net/zhoufoxcn" target="_blank">CSDN博客</a>|<a href="http://zhoufoxcn.blog.51cto.com" target="_blank">51CTO博客</a> </body> </html>    说明:周公对CSS不太熟悉,所以没有好好设计页面的显示效果,以能显示各Memcached的运行状态为准。 总结:Memcached作为一个非常不错的分布式缓存确实能很大程度上提高程序的性能。在上面的例子中有关检测Memcached运行状态数据的代码可 以提取出来应用于WinForm或者Windows Service,一旦检测出Memcached不可访问可以采取更灵活的方式,比如发送邮件到指定的邮箱,关于这一部分的功能相信大家都能轻易实现,所以 在这里就不再赘述了。

上一篇:分布式缓存系统Memcached简介与实践
下一篇:行人检测(总结)

相关文章

相关评论