设为首页 收藏本站
查看: 1192|回复: 0

[经验分享] ASP.NET版Memcached监控工具

[复制链接]

尚未签到

发表于 2018-12-24 11:59:42 | 显示全部楼层 |阅读模式
  在上一篇文章《使用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页面。
程序代码如下:














  • /*  
  • * 作者:周公  
  • * 日期:2011-03-27  
  • * 原文出处:http://blog.csdn.net/zhoufoxcn 或http://zhoufoxcn.blog.运维网.com  
  • * 版权说明:本文可以在保留原文出处的情况下使用于非商业用途,周公对此不作任何担保或承诺。  
  • * */  
  •       
  •     ///  
  •     /// Memcached服务器监控类  
  •     ///  
  •     public class MemcachedMonitor  
  •     {  
  •         ///  
  •         /// 连接Memcached的超时时间  
  •         ///  
  •         public TimeSpan ConnectionTimeout { get; set; }  
  •         ///  
  •         /// 接收Memcached返回数据的超时时间  
  •         ///  
  •         public TimeSpan ReceiveTimeout { get; set; }  
  •         private List serverList;  
  •         public MemcachedMonitor(ICollection list)  
  •         {  
  •             ConnectionTimeout = TimeSpan.FromSeconds(10);  
  •             ReceiveTimeout = TimeSpan.FromSeconds(20);  
  •             serverList = new List();  
  •             serverList.AddRange(list);  
  •         }  

  •         public List GetAllServerStats()  
  •         {  
  •             List resultList = new List();  
  •             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;  
  •         }  
  •     }  
  •     ///  
  •     /// Memcached服务器运行状态数据类,只有当IsReachable为true时获取的数据才有意义,否则表示不可访问或者Memcached挂了  
  •     ///  
  •     public class MemcachedServerStats  
  •     {  
  •         private Dictionary results;  
  •         ///  
  •         /// 是否可访问,如果不可访问表示网络故障或者Memcached服务器Down掉了  
  •         ///  
  •         public bool IsReachable { get; set; }  
  •         ///  
  •         /// 服务器运行时间,单位秒(32u)  
  •         ///  
  •         public UInt32 Uptime { get; set; }  
  •         ///  
  •         /// 服务器当前的UNIX时间(32u)  
  •         ///  
  •         public UInt32 Time { get; set; }  
  •         ///  
  •         /// 服务器的版本号(string)  
  •         ///  
  •         public string Version { get; set; }  
  •         ///  
  •         /// 服务器当前存储的内容数量(32u)  
  •         ///  
  •         public UInt32 Curr_Items { get; set; }  
  •         ///  
  •         /// 服务器启动以来存储过的内容总数(32u)  
  •         ///  
  •         public UInt32 Total_Items { get; set; }  
  •         ///  
  •         /// 连接数量(32u)  
  •         ///  
  •         public UInt32 Curr_Connections { get; set; }  
  •         ///  
  •         /// 服务器运行以来接受的连接总数(32u)  
  •         ///  
  •         public UInt32 Total_Connections { get; set; }  
  •         ///  
  •         /// 服务器分配的连接结构的数量(32u)  
  •         ///  
  •         public UInt32 Connection_Structures { get; set; }  
  •         ///  
  •         /// 取回请求总数(32u)  
  •         ///  
  •         public UInt32 Cmd_Get { get; set; }  
  •         ///  
  •         /// 存储请求总数(32u)  
  •         ///  
  •         public UInt32 Cmd_Set { get; set; }  
  •         ///  
  •         /// 请求成功的总次数(32u)  
  •         ///  
  •         public UInt32 Get_Hits { get; set; }  
  •         ///  
  •         /// 请求失败的总次数(32u)  
  •         ///  
  •         public UInt32 Get_Misses { get; set; }  
  •         ///  
  •         /// 服务器当前存储内容所占用的字节数(64u)  
  •         ///  
  •         public UInt64 Bytes { get; set; }  
  •         ///  
  •         /// 服务器从网络读取到的总字节数(64u)  
  •         ///  
  •         public UInt64 Bytes_Read { get; set; }  
  •         ///  
  •         /// 服务器向网络发送的总字节数(64u)  
  •         ///  
  •         public UInt64 Bytes_Written { get; set; }  
  •         ///  
  •         /// 服务器在存储时被允许使用的字节总数(32u)  
  •         ///  
  •         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 results)  
  •         {  
  •             if (endpoint == null || results == null)  
  •             {  
  •                 throw new ArgumentNullException("point and result can't be null");  
  •             }  
  •             IPEndPoint = endpoint;  

  •         }  

  •         public void InitializeData(Dictionary 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;  
  •         }  
  •     }  
  •     ///  
  •     /// 与Memcached服务器通讯的Socket封装  
  •     ///  
  •     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;  
  •         }  
  •         ///  
  •         /// 获取Memcached的运行状态  
  •         ///  
  •         ///  
  •         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 serverData = new Dictionary(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, &quot;STAT &quot;, 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(&quot;Exception Message:&quot; + exception.Message);  
  •             }  
  •             finally  
  •             {  
  •             }  
  •             return stats;  

  •         }  
  •         ///  
  •         /// 从远程主机的响应流中读取一行数据  
  •         ///  
  •         ///  
  •         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(&quot;接收到空响应。&quot;);  

  •             if (String.Compare(retureValue, GenericErrorResponse, StringComparison.Ordinal) == 0)  
  •                 throw new NotSupportedException(&quot;无效的指令。&quot;);  

  •             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;  
  •         }  
  •     }  




  •     ASP.NET版Memcached监控工具
  •      
  •         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;  
  • }  
  •      



  • IPVersionIsReachableBytesBytes_ReadBytes_WrittenCmd_GetCmd_SetCurr_ConnectionsCurr_ItemsGet_HitsGet_MissesLimit_MaxbytesTotal_Items


  • 这些数据所代表的意义如下:  

  • pid:32u,服务器进程ID。   
  • uptime:32u, 服务器运行时间,单位秒。   
  • time :32u, 服务器当前的UNIX时间。
  • version :string, 服务器的版本号。  
  • curr_items :32u, 服务器当前存储的内容数量   
  • 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类型数据。
  • 作者博客:CSDN博客|运维网博客




  说明:周公对CSS不太熟悉,所以没有好好设计页面的显示效果,以能显示各Memcached的运行状态为准。
总结:Memcached作为一个非常不错的分布式缓存确实能很大程度上提高程序的性能。在上面的例子中有关检测Memcached运行状态数据的代码可以提取出来应用于WinForm或者Windows Service,一旦检测出Memcached不可访问可以采取更灵活的方式,比如发送邮件到指定的邮箱,关于这一部分的功能相信大家都能轻易实现,所以在这里就不再赘述了。
周公
2011-03-28




运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-655274-1-1.html 上篇帖子: NOSQL系列 下篇帖子: Memcached服务安装
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表