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

[经验分享] 遍历memcached缓存对象(C#)

[复制链接]

尚未签到

发表于 2015-8-31 12:08:17 | 显示全部楼层 |阅读模式
  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,如下:
DSC0000.jpg
  程序实现
  因为要用c#调用,所以需要客户端执行 STATS 命令,这个可以直接参考DiscuzNT3.0中的实现。
  DiscuzNT下载地址:http://download.comsenz.com/DiscuzNT/src/

  下载完程序以后,在Discuz.Cache项目中找到这两个类:MemCached.cs和MemCachedClient.cs。
  我们要用到的方法有:
  MemCached.GetStats

DSC0001.gif DSC0002.gif 代码

        /// <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);
                if(sock == null)
                {
                    //if(log.IsErrorEnabled)
                    //{
                    //    log.Error(GetLocalizedString("unable to connect").Replace("$$Server$$", servers.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 ] = 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());
    }  运行程序:

DSC0003.jpg

  为什么没有输出缓存项呢?
  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;
}  再看一下输出结果,显示正常。

DSC0004.jpg

  
  
  
  

运维网声明 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-106791-1-1.html 上篇帖子: Memcached 使用 及.NET客户端调用 (资料整理) 下篇帖子: 我在试验Memcached,你的项目怎么处理缓存?
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

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

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

扫描微信二维码查看详情

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


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


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


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



合作伙伴: 青云cloud

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