memCached分布式缓存造成cup过高的讨论1

  

 

公司网站使用了memCached来做分布式缓存,最近有人反映memCached客户端占用CPU过高,怀疑是第三方客户端性能不佳,进而怀疑是文本协议的问题,要求部门自己开发memCached的客户端,使其支持二进制协议。因为重新开发客户端工作量比较大,同时在日常开发中,没有听说过memCached客户端遇到瓶颈。因此对此问题进行了排查。结果发现主要是由于客户端反序列化,类设计不合理造成的。把排查过程分享下,希望对其他人有所帮助。 

  首先想到是:memCached服务器端内存占满,在清理内存中,造成客户端socket连接不上,不断发生异常。随上服务器查看了memCached的内存占用率,连接数等,发现利用率均很低。暂时先排除服务器端问题。 

  其次想到可能是第三方在使用socket连接池时,造成资源没有关闭,或者死锁。随对第三方客户端代码粗略读了一遍,并搜索相关文档。未发现异常代码。暂时先排除第三方客户端问题。 

  最后想到会不会是开发人员在代码编写中出现了问题。随对反映问题的两个产品进行了排查。发现了以下代码。

 

代码片段1 

代码
<!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--> static  Serializer ser  =   new  Serializer( typeof (List < UserModule > ));  // using JsonExSerializer;
public   static  List < UserModule >  GetAllUserModule( int  userId)
{
    
string  cache  =  CacheManager.Current.Get < string > (GetCacheKey(userId));
    
if  ( ! string .IsNullOrEmpty(cache))
    {
        
return  ser.Deserialize(cache)  as  List < UserModule > ;
    }
    
else
    {
        
return   null ;
    }
}

public   static  List < UserModule >  SetAllUserModule( int  userId, List < UserModule >  modules)
{
    
if  (modules  !=   null )
    {
        
string  cache  =  ser.Serialize(modules);
        CacheManager.Current.Add(GetCacheKey(userId), cache);
    }
    
else
    {
        CacheManager.Current.Remove(GetCacheKey(userId));
    }
    
return  modules;
}

 

代码片段2 

代码
<!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--> ///   <summary>
///  聊天室房间
///   </summary>
[Serializable]
public   class  Room
{
    
// 房间有观看人员数据
    List < Viewer >  _viewers  =   null ;
    List
< string >  _blackips  =   null ;
    List
< Viewer >  _blackviewers  =   null ;
    List
< Notice >  _notice  =   null ;
    List
< Speaker  >  _speakers  =   null ;
    List
< Content >  _content  =   null ;


    
///   <summary>
    
///  添加新聊天者
    
///   </summary>
    
///   <returns> 返回新添加的聊天人员 </returns>
     public  Viewer AddViewer()
    {
        Viewer vi 
=   new  Viewer();
        
// MaxViewerID += 1;
        
        
// int id = MaxViewerID; 
         int  id  =  GetViewerID(); 
        vi.Name 
=  GetViewerName( " 游客 "   +  id);
        
// vi.IP = System.Web.HttpContext.Current.Request.UserHostAddress;
        vi.IP  =   " 127.0.0.1 " ;
        vi.ViewID 
=  id;
        Viewers.Add(vi);
        
return  vi; 
    }

///   <summary>
    
///  添加聊天内容
    
///   </summary>
    
///   <param name="content"> 聊天的内容 </param>
    
///   <param name="viewid"> 发言人的id </param>
    
///   <returns> 返回新添加的对象 </returns>
     public  Content AddContent( string  content,  int  viewid)
    {
        MaxContentID 
+=   1 ;
        Content con 
=   new  Content(DateTime.Now, content, viewid, MaxContentID);
        Contents.Add(con);
        
return  con;
    }
    ......
}

调用代码为:
Room room 
=  LiveSys.Get(key);
lock  (room)
{
    
if  (room.MaxContentID  ==   0 )
    {
        
// ChatContentOp cpo = new ChatContentOp();
        
// room.MaxContentID = cpo.GetMaxContentID();

        room.MaxContentID 
=   300 ;
    }
    
int  viewerID  =   123124123 ;
    room.AddContent(chatContent, viewerID);
    
// 判断内容是否大于100条。如果大于100条,删除最近的100条以外的数据。
    System.IO.File.AppendAllText( @" d:\haha.txt " " 最大数值: "   +  room.LimitContentCount  +   " ###############聊天记录数: "   +  room.Contents.Count  +   " \r\n " );
    
if  (room.Contents.Count  >  room.LimitContentCount)
    {
        room.Contents.RemoveRange(
0 , room.Contents.Count  -  room.LimitContentCount);
    }
}
LiveSys.Set(key, room);

 

 

代码1存在的问题是:

Cache存储的参数类型为object,没有必要先进行一次序列化,然后再进行存储。而序列化是很消耗CPU的。

 

代码2问题:

代码2实现的是一个在线聊天室,聊天室本身含有访客,发言等内容。在发言时,对聊天室内容进行判断,只显示最近30条。新进来访客直接加到访客别表中。表面上是没什么问题的。但是细想之下有两个问题:

1 聊天室类设计的比较复杂,每次从memCached服务端取得数据后,都要进行类型转换。

2 没有访客清理机制。随着访客的不断进入,对象的体积会不断增大。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值