• ASP.NET实现Memcached监控工具


    实现思路
    上一篇文章《使用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">  
          
        <mce: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;  
                    }  JavaScript优化


          
                    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;  
                }  
            }  
        // --></mce:script>  
          
        <html xmlns="http://www.w3.org/1999/xhtml">  
        <head>  
            <title>ASP.NET版Memcached监控工具</title>  
            <mce: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;  
        }  
              
        --></mce:style><style mce_bogus="1">        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" mce_href="http://blog.csdn.net/zhoufoxcn" target="_blank">CSDN博客</a>|<a href="http://zhoufoxcn.blog.51cto.com" mce_href="http://zhoufoxcn.blog.51cto.com" target="_blank">51CTO博客</a>  
        </body>  
        </html> 

  • 相关阅读:
    sql limit 的用法
    浅谈XSS攻击
    python dns 服务器
    简单的文件上传下载服务器
    Linux下pyftplib简单的脚本
    浅谈optparse 解析命令行参数库
    爬虫下载脚本
    python 递归算阶乘 (转载)
    遍历目录及其子目录的文件
    Oracle数据导入导出
  • 原文地址:https://www.cnblogs.com/sky7034/p/2105034.html
Copyright © 2020-2023  润新知