zoukankan      html  css  js  c++  java
  • 遍历memcached缓存对象(C#)

    STATS命令

    出于性能考虑,memcached没有提供遍历功能,不过我们可以通过以下两个stats命令得到所有的缓存对象。

    1、stats items

         显示各个slab中item的数目。

    2、stats cachedump slab_id limit_num
         显示某个slab中的前limit_num个key列表,显示格式:ITEM key_name [ value_length b; expire_time|access_time s]

    除了上面两个,memcached还提供了以下命令:

    3、stats  
    4、 stats reset  
    5、 stats malloc  
    6、 stats maps  
    7、 stats sizes 
    8、 stats slabs 
    9、 stats detail [on|off|dump] 

    命令的用法就不一一说了,请自行google。 关于memcached的数据存储和内存分配以后有机会再写。

    添加缓存

    在本地添加几个key,如下:

    程序实现

    因为要用c#调用,所以需要客户端执行 STATS 命令,这个可以直接参考DiscuzNT3.0中的实现。

    DiscuzNT下载地址:http://download.comsenz.com/DiscuzNT/src/

    下载完程序以后,在Discuz.Cache项目中找到这两个类:MemCached.cs和MemCachedClient.cs。

     我们要用到的方法有:

    MemCached.GetStats

    代码
            /// <summary>
            
    /// 获取服务器端缓存的数据信息
            
    /// </summary>
            
    /// <param name="serverArrayList">要访问的服务列表</param>
            
    /// <returns>返回信息</returns>
            public static ArrayList GetStats(ArrayList serverArrayList, Stats statsCommand, string param)
            {
                ArrayList statsArray = new ArrayList();
                param =  Utils.StrIsNullOrEmpty(param) ? "" : param.Trim().ToLower();

                
    string commandstr = "stats";
                
    //转换stats命令参数
                switch (statsCommand)
                {
                    
    case Stats.Reset: { commandstr = "stats reset"break; }
                    
    case Stats.Malloc: { commandstr = "stats malloc"break; }
                    
    case Stats.Maps: { commandstr = "stats maps"break; }
                    
    case Stats.Sizes: { commandstr = "stats sizes"break; }
                    
    case Stats.Slabs: { commandstr = "stats slabs"break; }
                    
    case Stats.Items: { commandstr = "stats"break; }
                    
    case Stats.CachedDump: 
                    {
                        
    string[] statsparams = Utils.SplitString(param, " ");
                        
    if(statsparams.Length == 2)
                            
    if(Utils.IsNumericArray(statsparams))
                                commandstr = "stats cachedump  " + param; 

                        
    break;                     
                    }
                    
    case Stats.Detail: 
                        { 
                            
    if(string.Equals(param, "on"|| string.Equals(param, "off"|| string.Equals(param, "dump"))
                                commandstr = "stats detail " + param.Trim(); 

                            
    break
                        }
                    
    default: { commandstr = "stats"break; }
                }
                
    //加载返回值
                Hashtable stats = MemCachedManager.CacheClient.Stats(serverArrayList, commandstr);
                
    foreach (string key in stats.Keys)
                {
                    statsArray.Add(key);
                    Hashtable values = (Hashtable)stats[key];
                    
    foreach (string key2 in values.Keys)
                    {
                        statsArray.Add(key2 + ":" + values[key2]);
                    }
                }
                
    return statsArray;
            }

    MemCachedClient.Stats

    代码
    public Hashtable Stats(ArrayList servers, string command) 
            {

                
    // get SockIOPool instance
                SockIOPool pool = SockIOPool.GetInstance(_poolName);

                
    // return false if unable to get SockIO obj
                if(pool == null
                {
                    
    //if(log.IsErrorEnabled)
                    
    //{
                    
    //    log.Error(GetLocalizedString("unable to get socket pool"));
                    
    //}
                    return null;
                }

                
    // get all servers and iterate over them
                if (servers == null)
                    servers = pool.Servers;

                
    // if no servers, then return early
                if(servers == null || servers.Count <= 0
                {
                    
    //if(log.IsErrorEnabled)
                    
    //{
                    
    //    log.Error(GetLocalizedString("stats no servers"));
                    
    //}
                    return null;
                }

                
    // array of stats Hashtables
                Hashtable statsMaps = new Hashtable();

                
    for(int i = 0; i < servers.Count; i++
                {

                    SockIO sock = pool.GetConnection((string)servers[i]);
                    
    if(sock == null
                    {
                        
    //if(log.IsErrorEnabled)
                        
    //{
                        
    //    log.Error(GetLocalizedString("unable to connect").Replace("$$Server$$", servers[i].ToString()));
                        
    //}
                        continue;
                    }

                    
    // build command
                    command = Discuz.Common.Utils.StrIsNullOrEmpty(command) ?  "stats\r\n": command + "\r\n";

                    
    try 
                    {
                        sock.Write(UTF8Encoding.UTF8.GetBytes(command));
                        sock.Flush();

                        
    // map to hold key value pairs
                        Hashtable stats = new Hashtable();

                        
    // loop over results
                        while(true
                        {
                            
    string line = sock.ReadLine();
                            
    //if(log.IsDebugEnabled)
                            
    //{
                            
    //    log.Debug(GetLocalizedString("stats line").Replace("$$Line$$", line));
                            
    //}

                            
    if(line.StartsWith(STATS)) 
                            {
                                
    string[] info = line.Split(' ');
                                
    string key    = info[1];
                                
    string val  = info[2];

                                
    //if(log.IsDebugEnabled)
                                
    //{
                                
    //    log.Debug(GetLocalizedString("stats success").Replace("$$Key$$", key).Replace("$$Value$$", val));
                                
    //}

                                stats[ key ] = val;

                            }
                            
    else if(END == line) 
                            {
                                
    // finish when we get end from server
                                
    //if(log.IsDebugEnabled)
                                
    //{
                                
    //    log.Debug(GetLocalizedString("stats finished"));
                                
    //}
                                break;
                            }

                            statsMaps[ servers[i] ] = stats;
                        }
                    }
                    
    catch//(IOException e) 
                    {
                        
    //if(log.IsErrorEnabled)
                        
    //{
                        
    //    log.Error(GetLocalizedString("stats IOException"), e);
                        
    //}

                        
    try 
                        {
                            sock.TrueClose();
                        }
                        
    catch//(IOException) 
                        {
                            
    //if(log.IsErrorEnabled)
                            
    //{
                            
    //    log.Error(GetLocalizedString("failed to close some socket").Replace("$$Socket$$", sock.ToString()));
                            
    //}
                        }

                        sock = null;
                    }

                    
    if(sock != null)
                        sock.Close();
                }

                
    return statsMaps;
            }

    有了这两个方法我们就可以得到memcached中的缓存项了。

    基本思路是,先得到cache中所有的item(stats items),再通过itemid 取出cachekey和cachevalue(stats cachedump)

    程序实现如下:

        private  void GetItems()
        {
            ArrayList itemarr = new ArrayList();

            ArrayList arrayList = new ArrayList();
            StringBuilder sb = new StringBuilder();

            
    foreach (string server in MemCachedManager.ServerList)
            {
                arrayList.Add(server);
            }
            ArrayList arr = MemCachedManager.GetStats(arrayList, MemCachedManager.Stats.Items, null);
            
    foreach (string a in arr)
            {
                
    string[] tmparr = a.Split(':');
                
    if (tmparr.Length > 1)
                {
                    
    int item_id = 0;
                    
    int.TryParse(tmparr[1], out item_id);

                    
    bool find = false;
                    
    foreach (int item in itemarr)
                    {
                        
    if (item == item_id)
                            find = true;
                    }
                    
    if (!find && item_id > 0 && item_id != 11211)
                        itemarr.Add(item_id);
                }
            }
            
    foreach (int item in itemarr)
            {
                sb.Append("item " + item + "<br />");
                ArrayList cachearr = MemCachedManager.GetStats(arrayList, MemCachedManager.Stats.CachedDump, "" + item + " 10");
                
    foreach (string cache in cachearr)
                {
                    sb.Append(cache);
                    sb.Append("<br />");
                }
            }
            Response.Write(sb.ToString());
        }

    运行程序:


    为什么没有输出缓存项呢?

    DiscuzNT3.0中的bug

    于是我找啊找,发现是DiscuzNT3.0中的一个bug导致。

    在MemCachedClient.Stats中,有这样的一段代码:

    if(line.StartsWith(STATS)) 
    {
        
    string[] info = line.Split(' ');
        
    string key    = info[1];
        
    string val  = info[2];
        stats[ key ] = val;

    }
    else if(END == line) 
    {
        
    break;
    }

    原来是忽略了stats cachedump 的结果是以ITEM开头的,所以什么都没有输出。简单修改一下:

    if(line.StartsWith(STATS) ) 
    {
        
    string[] info = line.Split(' ');
        
    string key    = info[1];
        
    string val  = info[2];
        stats[ key ] = val;

    }
    else if (line.StartsWith("ITEM"))
    {
        
    string[] info = line.Split('[');
        
    string key = info[0].Split(' ')[1];
        
    string val = "[" + info[1];

        stats[key] = val;
    }
    else if (END == line)
    {
        
    break;
    }

    再看一下输出结果,显示正常。


  • 相关阅读:
    团队项目第二阶段——第一天
    团队项目第一阶段绩效评估
    铁大树洞与市面上现有APP对比
    第一阶段其他组评价汇总
    第一阶段对其他组的评价
    铁大树洞app功能演示和使用说明
    团队冲刺——第十天
    团队冲刺——第九天
    团队冲刺——第八天
    梦断代码读后感04--毁灭即拯救
  • 原文地址:https://www.cnblogs.com/tenghoo/p/traverse_memcached.html
Copyright © 2011-2022 走看看