日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
關(guān)于Memcached客戶端CPU過高問題的排查

公司網(wǎng)站使用了Memcached來做分布式緩存,最近有人反映Memcached客戶端占用CPU過高,懷疑是第三方客戶端性能不佳,進而懷疑是文本協(xié)議的問題,要求部門自己開發(fā)Memcached的客戶端,使其支持二進制協(xié)議。因為重新開發(fā)客戶端工作量比較大,同時在日常開發(fā)中,沒有聽說過Memcached客戶端遇到瓶頸。因此對此問題進行了排查。結(jié)果發(fā)現(xiàn)主要是由于客戶端反序列化,類設計不合理造成的。把排查過程分享下,希望對其他人有所幫助。 

創(chuàng)新互聯(lián)長期為上千余家客戶提供的網(wǎng)站建設服務,團隊從業(yè)經(jīng)驗10年,關(guān)注不同地域、不同群體,并針對不同對象提供差異化的產(chǎn)品和服務;打造開放共贏平臺,與合作伙伴共同營造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為梁子湖企業(yè)提供專業(yè)的成都網(wǎng)站制作、成都做網(wǎng)站、外貿(mào)營銷網(wǎng)站建設,梁子湖網(wǎng)站改版等技術(shù)服務。擁有十多年豐富建站經(jīng)驗和眾多成功案例,為您定制開發(fā)。

首先想到是:Memcached服務器端內(nèi)存占滿,在清理內(nèi)存中,造成客戶端socket連接不上,不斷發(fā)生異常。隨上服務器查看了Memcached的內(nèi)存占用率,連接數(shù)等,發(fā)現(xiàn)利用率均很低。暫時先排除服務器端問題。 

其次想到可能是第三方在使用socket連接池時,造成資源沒有關(guān)閉,或者死鎖。隨對第三方客戶端代碼粗略讀了一遍,并搜索相關(guān)文檔。未發(fā)現(xiàn)異常代碼。暫時先排除第三方客戶端問題。 

最后想到會不會是開發(fā)人員在代碼編寫中出現(xiàn)了問題。隨對反映問題的兩個產(chǎn)品進行了排查。發(fā)現(xiàn)了以下代碼。

 
 
 
 
  1. static Serializer ser = new Serializer(typeof(List)); 
  2. //using JsonExSerializer;  
  3. public static List GetAllUserModule(int userId)  
  4. {  
  5.     string cache = CacheManager.Current.Get(GetCacheKey(userId));  
  6.     if (!string.IsNullOrEmpty(cache))  
  7.     {  
  8.         return ser.Deserialize(cache) as List;  
  9.     }  
  10.     else 
  11.     {  
  12.         return null;  
  13.     }  
  14. }  
  15.  
  16. public static List SetAllUserModule(int userId, List modules)  
  17. {  
  18.     if (modules != null)  
  19.     {  
  20.         string cache = ser.Serialize(modules);  
  21.         CacheManager.Current.Add(GetCacheKey(userId), cache);  
  22.     }  
  23.     else 
  24.     {  
  25.         CacheManager.Current.Remove(GetCacheKey(userId));  
  26.     }  
  27.     return modules;  

代碼片段2:  

 
 
 
 
  1. ///   
  2. /// 聊天室房間  
  3. ///   
  4. [Serializable]  
  5. public class Room  
  6. {  
  7.     //房間有觀看人員數(shù)據(jù)  
  8.     List _viewers = null;  
  9.     List _blackips = null;  
  10.     List _blackviewers = null;  
  11.     List _notice = null;  
  12.     List _speakers = null;  
  13.     List _content = null;  
  14.  
  15.  
  16.     ///   
  17.     /// 添加新聊天者  
  18.     ///   
  19.     /// 返回新添加的聊天人員  
  20.     public Viewer AddViewer()  
  21.     {  
  22.         Viewer vi = new Viewer();  
  23.         //MaxViewerID += 1;  
  24.           
  25.         //int id = MaxViewerID;   
  26.         int id = GetViewerID();   
  27.         vi.Name = GetViewerName("游客" + id);  
  28.         //vi.IP = System.Web.HttpContext.Current.Request.UserHostAddress;  
  29.         vi.IP = "127.0.0.1";  
  30.         vi.ViewID = id;  
  31.         Viewers.Add(vi);  
  32.         return vi;   
  33.     }  
  34.  
  35. ///   
  36.     /// 添加聊天內(nèi)容  
  37.     ///   
  38.     /// 聊天的內(nèi)容  
  39.     /// 發(fā)言人的id  
  40.     /// 返回新添加的對象  
  41.     public Content AddContent(string content, int viewid)  
  42.     {  
  43.         MaxContentID += 1;  
  44.         Content con = new Content(DateTime.Now, content, viewid, MaxContentID);  
  45.         Contents.Add(con);  
  46.         return con;  
  47.     }  
  48.     ......  

調(diào)用代碼為:

 
 
 
 
  1. Room room = LiveSys.Get(key);  
  2. lock (room)  
  3. {  
  4.     if (room.MaxContentID == 0)  
  5.     {  
  6.         //ChatContentOp cpo = new ChatContentOp();  
  7.         //room.MaxContentID = cpo.GetMaxContentID();  
  8.  
  9.         room.MaxContentID = 300;  
  10.     }  
  11.     int viewerID = 123124123;  
  12.     room.AddContent(chatContent, viewerID);  
  13.     //判斷內(nèi)容是否大于100條。如果大于100條,刪除最近的100條以外的數(shù)據(jù)。  
  14.     System.IO.File.AppendAllText(@"d:\haha.txt", "最大數(shù)值:" + 
  15. room.LimitContentCount + "###############聊天記錄數(shù):" + room.Contents.Count + "\r\n");  
  16.     if (room.Contents.Count > room.LimitContentCount)  
  17.     {  
  18.         room.Contents.RemoveRange(0, room.Contents.Count - room.LimitContentCount);  
  19.     }  
  20. }  
  21. LiveSys.Set(key, room); 

代碼1存在的問題是:

Cache存儲的參數(shù)類型為object,沒有必要先進行一次序列化,然后再進行存儲。而序列化是很消耗CPU的。

代碼2問題:

代碼2實現(xiàn)的是一個在線聊天室,聊天室本身含有訪客,發(fā)言等內(nèi)容。在發(fā)言時,對聊天室內(nèi)容進行判斷,只顯示最近30條。新進來訪客直接加到訪客別表中。表面上是沒什么問題的。但是細想之下有兩個問題:

1 聊天室類設計的比較復雜,每次從Memcached服務端取得數(shù)據(jù)后,都要進行類型轉(zhuǎn)換。

2 沒有訪客清理機制。隨著訪客的不斷進入,對象的體積會不斷增大。

對存疑部分編寫了代碼進行測試。測試結(jié)果果然如推測所想。測試結(jié)果如下:

場景

寫入

讀取

大小

(單位)

CPU

次數(shù)

時間

平均

次數(shù)

時間

平均

本地緩存

10000

0.03125

0

10000

0

0

1k

0

MemClient

10000

19.2656

0.001926

10000

22.75

0.002275

1k

 

Json1k

1000

2.8437

0.002843

1000

5.375

0.005375

1k

 

Json8k

1000

3.8593

0.003859

1000

29.0312

0.029031

8k

 

直播1000人次

1000

38.9375

0.038937

1000

 

 

50k

 

直播8000人次

100

18.25

0.1825

100

 

 

350k

 

500k

100

7.375

0.07375

100

7.09375

0.070937

500k

 

場景

寫入

讀取

大小

(單位)

CPU

次數(shù)

時間

平均

次數(shù)

時間

平均

本地緩存

10000

0.03125

3.125E-06

10000

0.015625

1.5625E-06

1k

0

MemClient

10000

19.78125

0.001978

10000

21.953125

0.002195

1k

 

Json1k

1000

2.03125

0.002031

1000

6.078125

0.006078

1k

 

Json8k

1000

2.765625

0.002765

1000

55.375

0.055375

8k

 

直播1000人次

1000

38.53125

0.038531

1000

  

50k

 

直播8000人次

100

17.96875

0.179687

1000

  

350k

 

500k

100

7.5

0.075

100

6.5625

0.065625

500k

 

場景

寫入

讀取

大小

(單位)

CPU

次數(shù)

時間

平均

次數(shù)

時間

平均

本地緩存

10000

0.015625

1.5625E-06

10000

0.015625

1.5625E-06

1k

0

MemClient

10000

18.015625

0.001801

10000

25.96875

0.002596

1k

6%

Json1k

1000

1.15625

0.001156

1000

3.078125

0.003078

1k

40%

Json8k

1000

1.859375

0.001859

1000

32.484375

0.032484

8k

50%

直播1000人次

1000

45.046875

0.045046

1000

  

50k

30-40%

直播8000人次

100

31.703125

0.317031

100

  

350k

50%

500k

100

7.0625

0.070625

100

6.421875

0.064218

500k

6%

直播1000人次(當天一共有1000人訪問,數(shù)據(jù)來源于運營檢測),留言內(nèi)容為30條時,Room體積大概為:57K  

直播1000人次(當天一共有8000人訪問,數(shù)據(jù)來源于運營檢測),留言內(nèi)容為30條時,Room體積大概為:350k

根據(jù)圖表可以看到以下情況:處理時間、CPU利用率和數(shù)據(jù)量大小,序列化,類復雜性都有關(guān)系。

序列化問題(類型轉(zhuǎn)換)對性能影響最為明顯(可在場景”json1k”、場景直播中看到)。在Json1k中,存儲對象和前幾個場景是相同的,處理時間也相差不大,較大區(qū)別是CPU利用率由5%左右增長到40%左右(反序列化時尤為明顯)。在場景直播系統(tǒng)中,不存在序列化問題,但是其對象屬性中存在”訪客”, ”繁衍”等多個復雜對象,造成其在處理時需要處理過多的類型轉(zhuǎn)換,同時其體積不斷增大。

存儲對象的大小和處理時間存在一定關(guān)系,例如場景”500k”,其處理時間增長,但是其CPU利用率并未提高,其時間增長是由于對象傳輸造成。

本地緩存在內(nèi)存中進行尋址和類型轉(zhuǎn)換,涉及不到Socket連接,網(wǎng)絡傳輸,序列化操作,所以其處理相當快。

就測試結(jié)果看:

本地緩存性能大約是分布式緩存性能的100倍左右。而出問題的聊天室除了CPU增高以外,其性能更比分布式緩存再降低40倍(直播1000人次)到200倍(直播8000人次)。綜合來看,聊天室的分布式緩存比本地緩存降了4000倍,甚至更多。

但是,還沒有完。 

對于第二個問題,更改類設計,清楚無效訪客,即可解決。 

但是第一個問題,為什么用戶在存儲之前,先進行json序列化呢?嗯,這是一個問題。

遂問之。

答曰,有些類直接使用第三方客戶端存儲時,直接存儲報錯,所以先序列化為json類型,取值時再反序列化回來。

嗯,還有這事?

開發(fā)人員說了相關(guān)代碼。 

 
 
 
 
  1. interface IUser  
  2. {  
  3.     String UserId{ get; set;}  
  4.     String UserName{ get; set;}  
  5. }  
  6.  
  7. [Serializable]  
  8. class UserInfo : IUser  
  9. {  
  10.     String UserId{ get; set;}  
  11.     String UserName{ get; set;}  
  12. }  
  13. [Serializable]  
  14. class Game  
  15. {  
  16.     IUser User{ get; set;}  
  17.     String UserName{ get; set;}  

他說:Game對象在直接使用MemcachedClient時,是不能被二進制序列化的,因為其User屬性類型為IUser,為一個接口。因此想了一個解決方法,即先將Game對象進行 json序列化將其變?yōu)樽址缓髮⒆址鎯Φ組emcached。 

原來是這樣。

接著又查看了MemcachedClient源代碼,其需要將對象進行二進制序列化,然后進行存儲。接口屬性不能被序列化,遂又對序列化問題進行了測試(見附件)。測試結(jié)果顯示上述代碼直接進行二進制序列化是可以的,同時直接使用第三方客戶端也是可以可行的。 

問題出在哪?難道是沒有加[Serializable]。

一查果然:一個Serializable引發(fā)的血案。

記得有人說過,慎用分布式,能不用盡量不用。

一方面在性能上確實下降很多,分布式存儲主要性能消耗在以下幾個方面:協(xié)議解析,Socket連接,數(shù)據(jù)傳輸,序列化/類型轉(zhuǎn)換。

一方面在使用場景和類設計上要求也更加嚴格。個人認為Memcached是不太適合存儲特別大的文件的。雖然有人說網(wǎng)上已經(jīng)有用來存儲視頻的。

還有幾個問題希望知道的朋友回答下:

1 有沒有.Net方面的Memcached客戶端支持二進制協(xié)議和一致性的?

2 測試中發(fā)現(xiàn),當Memcached設置緩存過小時(例如64M),當其內(nèi)存使用已經(jīng)到62M時,再進行存儲,新存儲的內(nèi)容再取出來就是空值,不知道是什么原因。


網(wǎng)頁題目:關(guān)于Memcached客戶端CPU過高問題的排查
分享路徑:http://www.dlmjj.cn/article/dhshghe.html