<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    放翁(文初)的一畝三分地

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
      210 隨筆 :: 1 文章 :: 320 評論 :: 0 Trackbacks

    #

        下周一應該是我今年最后一次參加內部培訓了,所要講的內容也是我這大半年來都在專注的技術:Open API&SIP。由于文章要在程序員1月刊發表,因此文章暫時不能放在Blog上,不過下周一的培訓PPT還是可以分享一下的。有興趣的集團的同學也可以來阿里軟件聽。同時也很高興的看到在csdn的blog在年底沖過了10w,希望明年有更多的分享能夠貢獻出來^_^



    Uploaded on authorSTREAM by cenwenchu
    posted @ 2008-12-10 10:23 岑文初 閱讀(3966) | 評論 (1)編輯 收藏

        今天,有一個使用我優化的Memcached cache Client給我發了郵件問到一個參數的作用,覺得還是比較重要的一個參數,因此也說一下,同時也在這里說一下,當前優化過的客戶端已經作了幾次小的升級,修復了一些邊界數據的問題,大家如果在使用的話,最好能夠升級。(http://code.google.com/p/memcache-client-forjava/

       郵件如下:

       你好:
    <socketpool name="pool0" failover="true" initConn="5" minConn="5"
      maxConn="250" maintSleep="5000" nagle="false" socketTO="3000"
      aliveCheck="true" >
      <servers>10.0.0.16:11111</servers>
      <weights>10</weights>
     </socketpool>
    能解釋下maintSleep這個意思么?我看有的資料說吧它設置為0性能更好,能給些建議么?謝謝!!我們現在的PV大約每天500萬。

     

        這個參數是對此連接池維護線程的檢查間隔時間的配置,如果配置小于等于0,則將不會有后臺線程維護此連接池,參數單位為毫秒,下面解釋一下維護連接池的含義,其實就和其他的資源池一樣,資源池的目的就是為了解決資源的申請和釋放的開銷增加系統壓力的問題,將資源通過池的方式回收重用,有利于系統性能的提高。memcached cache client 其實是通過socket來和服務端進行通信,建立socket連接也是比較消耗時間的工作,因此配置了池的初始連接數(initConn),最小連接數(minConn),最大連接數(maxConn)。這三者關系如下圖,維護他們之間狀態轉移的就是后臺線程。

     

        后臺進程維護資源池的作用就是將有限資源回收,例如數據庫連接,如果一臺oracle只有500個連接數可以支持,那么如果一個應用都占用了50個閑置,那對于其他需要資源的應用來說無疑是一種浪費。但如果配置了資源管理,但由于應用屬于忙時和閑時交替比較頻繁的情況,那么如果時間配置的不是很合適,就會達不到原來資源池的作用,資源反復回收和申請。所以對于這個參數的配置,個人覺得一定要配,配置的值需要注意,初始化和最小的值可以是自己預估平時平均并發處理的均值,最大的連接數當然依賴于資源的總數,而維護時間間隔則最好是能夠根據閑時和忙時的情況來考慮配置,這樣既不會浪費資源,同時也不會使資源池時效。

        順帶說一句,如果對于數據丟失要求不是很苛刻,然后網絡情況也不錯的時候,可以將aliveCheck設置為false,因為如果是true,在每一次發送任何數據操作之前都會去做心跳檢查,這個未來也會考慮去優化。

    posted @ 2008-11-21 15:28 岑文初 閱讀(1946) | 評論 (0)編輯 收藏

        一句話:“不要為做別人已經作過的事情而沾沾自喜,要做就做別人沒有做或者做不到的”。原話可能不是這句了,但是意思差不多,這是上次架構委員會開會的時候,阿里集團新來的首席架構師王堅和我們說的一句話。原因就是集團內或者公司內部資源重復去做一些工作,包括我在內很多程序員就整天津津樂道的去重復做一些工作,對于別人的成果(國外開源除外),總是有些排斥,特別是一些關鍵性技術,但其實真正的架構師應該關注如何能夠找到合適的方法正確高效的解決問題,如何積累技術,而不是重復建設,這點很多人都很清楚,但是真的遇到一些情況的時候,就忘記了這些準則。

        一個人,我們阿軟的首席架構師趙進。說到對人能力的佩服,我想對于趙進作為首席架構師的能力,我自己真的是很實實在在的佩服。遠了不說,就說最近的關于阿里軟件自己的基礎組件Cache,當前除了SIP以外,其他兩個自主產品的cache都采用的我維護的cache組件,這次做外貿重構,其他的架構師作了一個新的Cache,趙進知道后覺得這個關系到未來的整體基礎架構統一性的問題,因此反復找我們幾個人談了很久,當然我也很理解架構師為了項目需求不愿意切換或者改變現有成型代碼,但是如果作為一種長遠的負責的規劃,的卻是需要統一起來。期間的困難可想而知,趙進最后找了我們的老大來拍板,結果我老大的一句話把趙進打入冷庫,連我們老大都因為擔心項目影響的風險而不是很贊成,我可以看出當時趙進的失落,但是在他棄而不舍的精神下,我真的算是感動了,大家一起在作了分析和討論,最后總算確定了一個不算最滿意,但也算是達到目的的一個解決方案。

        那么回顧一下我對趙進的感受,那么就能夠體現出如果要成為一個架構師,或者是一個首席架構師應該具有的能力,首先就是微笑,其次就是傾聽,再則就是引導,最后就是堅持。微笑可以化解敵意,傾聽可以找出問題,引導可以商討解決方案,堅持可以達到目標。當然雙贏之類的就不說了。其實說到能力,在我看來技術方面的能力是可以培養的,要成為技術上的能人,需要專注,堅持和勤奮,但是要成為一個架構師那么最重要的還是胸懷和眼界,能夠容納別人才會讓別人接受你,這些說起來都很容易,但是做起來卻是很難,因為這和個性也有關系,改變自己的個性需要勇氣和時間。

        我現在MSN的名字叫做海納百川,時時告訴自己有容乃大,整天為了一些細枝末節的重復勞動而沾沾自喜,只會變成井底之蛙,要做就要做別人沒有做或者做不到的,多了解一些,多學習一些,站在不到巨人的肩膀上也站到石頭上,看得更高才會走得更遠。

        一年過去之際,勉勵自己改變自己。

        有架構師的能力,卻沒有寬廣的胸懷,那么永遠只會停留在一個代碼編寫者階段。

        有寬廣的胸懷,卻只有程序員的能力,那么只要努力就會成為架構師甚至首席架構師。
        (打個廣告^_^,年底關于Open API的文章由于要發表在雜志上,因此無法在這里貼了,不過到了一月份應該就可以貼了,這篇關于Open API的文章是自己沉淀自己大半年工作的一份總結,也希望能夠分享給大家)

    posted @ 2008-11-20 08:46 岑文初 閱讀(2510) | 評論 (9)編輯 收藏

        昨天集團架構委員會(虛擬組織)作了第二次交流,各個子公司都說了當前的一些進度,問題和想法,我也大致講了一下阿里軟件的服務集成平臺的一些進展和自己的一些思考,這里先貼一下PPT的圖片,后面想整理以下關于當前Open API的一些想法以及對Open API Framework的一些思路。

     

    幻燈片1

     

    幻燈片2

     

    幻燈片3

     

    幻燈片4

     

    幻燈片5

     

    幻燈片6

     

    幻燈片7

     

    幻燈片8

     

    幻燈片9

     

    幻燈片10

     

    幻燈片11
    posted @ 2008-10-31 09:53 岑文初 閱讀(1972) | 評論 (4)編輯 收藏

           SIP5.0以后服務的請求量爆發性增長,因此也暴露了原來沒有暴露出來的問題。由于過去一般一個新版本發布周期在一個月左右,因此如果是小的內存泄露,在一個月之內重新發布以后也就看不出任何問題。

    因此這陣子除了優化Memcache客戶端和SIP框架邏輯以外其他依賴部分以外,對于內存泄露的壓力測試也開始實實在在的做起來。經過這次問題的定位和解決以后,大致覺得對于一個大用戶量應用要放心的話,那么需要做這么幾步。

    1.       GC輸出的環境下,大壓力下做多天的測試。(可以在 JAVA_OPTS增加-verbose:gc -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError

    2.       檢查GC輸出日志來判斷是否有內存泄露。(這部分后面有詳細的實例說明)

    3.       如果出現內存泄露問題,則使用jprofiler等工具來排查內存泄露點(之所以不一開始使用,因為jprofiler等工具對于壓力測試有影響,使得大壓力無法上去,也使問題不那么容易暴露)

    4.       解決問題,并在重復2步驟。

    這里對SIPjdk1.5jdk1.6下做壓力測試的GC 日志來做一個實際的分析對比,通過對比來大致描述一下如何根據輸出情況能夠了解應用是否存在內存泄露問題。(這里的內存泄露問題就是在以前blog寫過的jdkconcurrent包內LinkedBlockingQueuepoll方法存在比較嚴重的內存泄露,調用頻率越高,內存泄露的越厲害)

    兩次壓力測試都差不多都是兩天,測試方案如下:

    開始50個并發,每個并發每次請求完畢后休息0.1秒,10分鐘后增長50個并發,按此規律增長到500并發。

    舊版本SIP是在JDK1.5環境下完成的壓力測試,

    新版本SIPJDK版本是1.6

    壓力機和以前一樣,是10.2.226.40DELL19508CPU8G內存。

    壓力機模擬發出對一個需要簽名的API不斷的調用請求。

    看看兩個Log的具體內容(內容很多截取部分做分析)

    先說一下日志輸出的結構:(1.61.5略微有一些不同,只是1.6對于時間統計更加細致)

    [GC [<collector>: <starting occupancy1> -> <ending occupancy1>, <pause time1> secs] <starting occupancy3> -> <ending occupancy3>, <pause time3> secs]

    <collector>GC收集器的名稱

    <starting occupancy1> 新生代在GC前占用的內存

    <ending occupancy1> 新生代在GC后占用的內存

    <pause time1> 新生代局部收集時jvm暫停處理的時間

    <starting occupancy3> JVM Heap GC前占用的內存

    <ending occupancy3> JVM Heap GC后占用的內存

    <pause time3> GC過程中jvm暫停處理的總時間

    Jdk1.5 log

    啟動時GC輸出:

    [GC [DefNew: 209792K->4417K(235968K), 0.0201630 secs] 246722K->41347K(498112K), 0.0204050 secs]

    [GC [DefNew: 214209K->4381K(235968K), 0.0139200 secs] 251139K->41312K(498112K), 0.0141190 secs]

    一句輸出:

    新生代回收前209792K,回收后4417K,回收數量205375KHeap總量回收前246722K回收后41347K,回收總量205375K。這就表示100%的收回,沒有任何新生代的對象被提升到中生代或者永久區(名字說的不一定準確,只是表達意思)。

    第二句輸出:

    按照分析也就只是有1K內容被提升到中生代。

    運行一段時間后:

    [GC [DefNew: 210686K->979K(235968K), 0.0257140 secs] 278070K->68379K(498244K), 0.0261820 secs]

    [GC [DefNew: 210771K->1129K(235968K), 0.0275160 secs] 278171K->68544K(498244K), 0.0280050 secs]

    第一句輸出:

             新生代回收前210686K,回收后979K,回收數量209707KHeap總量回收前278070K回收后68379K,回收總量209691K。這就表示有16k沒有被回收。

    第二句輸出:

             新生代回收前210771K,回收后1129K,回收數量209642KHeap總量回收前278171K回收后68544K,回收總量209627K。這就表示有15k沒有被回收。

    比較一下啟動時與現在的新生代占用內存情況和Heap使用情況發現Heap的使用增長很明顯,新生代沒有增長,而Heap使用總量增長了27M,這就表明可能存在內存泄露,雖然每一次泄露的字節數很少,但是頻率很高,大部分泄露的對象都被升級到了中生代或者持久代。

    又一段時間后:

    [GC [DefNew: 211554K->1913K(235968K), 0.0461130 secs] 350102K->140481K(648160K), 0.0469790 secs]

    [GC [DefNew: 211707K->2327K(235968K), 0.0546170 secs] 350275K->140921K(648160K), 0.0555070 secs]

    第一句輸出:

             新生代回收前211554K,回收后1913K,回收數量209641KHeap總量回收前350102K回收后140481K,回收總量209621K。這就表示有20k沒有被回收。

             分析到這里就可以看出每一次泄露的內存只有10K,但是在大壓力長時間的測試下,內存泄露還是很明顯的,此時Heap已經增長到了140M,較啟動時已經增長了100M。同時GC占用的時間越來越長。

    后續的現象:

             后續觀察日志會發現,Full GC的頻率越來越高,收集所花費時間也是越來越長。(Full GC定期會執行,同時局部回收不能滿足分配需求的情況下也會執行)。

    [Full GC [Tenured: 786431K->786431K(786432K), 3.4882390 secs] 1022399K->1022399K(1022400K), [Perm : 36711K->36711K(98304K)], 3.4887920 secs]

    java.lang.OutOfMemoryError: Java heap space

    Dumping heap to java_pid7720.hprof ...

             出現這個語句表示內存真的被消耗完了。

    Jdk1.6 log

     

    啟動時GC的輸出:

    [GC [PSYoungGen: 221697K->31960K(229376K)] 225788K->36051K(491520K), 0.0521830 secs] [Times: user=0.26 sys=0.05, real=0.05 secs]

    [GC [PSYoungGen: 228568K->32752K(229376K)] 232659K->37036K(491520K), 0.0408620 secs] [Times: user=0.21 sys=0.02, real=0.04 secs]

    第一句輸出:

             新生代回收前221697K,回收后31960K,回收數量189737KHeap總量回收前225788K回收后36051K,回收總量189737K100%被回收。

    運行一段時間后輸出:

    [GC [PSYoungGen: 258944K->2536K(259328K)] 853863K->598135K(997888K), 0.0471620 secs] [Times: user=0.15 sys=0.00, real=0.05 secs]

    [GC [PSYoungGen: 259048K->2624K(259328K)] 854647K->598907K(997888K), 0.0462980 secs] [Times: user=0.16 sys=0.02, real=0.04 secs]

    第一句輸出:

             新生代回收前258944K,回收后2536K,回收數量256408KHeap總量回收前853863K回收后598135K,回收總量255728K680K沒有被回收,但這并不意味著就會產生內存泄露。同時可以看出GC回收時間并沒有增加。

    在運行一段時間后輸出:

    [GC [PSYoungGen: 258904K->2488K(259264K)] 969663K->713923K(1045696K), 0.0485140 secs] [Times: user=0.16 sys=0.01, real=0.04 secs]

    [GC [PSYoungGen: 258872K->2448K(259328K)] 970307K->714563K(1045760K), 0.0473770 secs] [Times: user=0.16 sys=0.01, real=0.05 secs]

    第一句輸出:

             新生代回收前258904K,回收后2488K,回收數量256416KHeap總量回收前969663K回收后713923K,回收總量255740K676K沒有被回收,同時總的Heap也有所增加。

             此時看起來好像和1.5的狀況一樣。但是查看了一下Full GC的執行還是400-500GC執行一次,因此繼續觀察。

    運行一天多以后輸出:

    [GC [PSYoungGen: 257016K->3304K(257984K)] 1019358K->766310K(1044416K), 0.0567120 secs] [Times: user=0.18 sys=0.01, real=0.06 secs]

    [GC [PSYoungGen: 257128K->2920K(258112K)] 1020134K->766622K(1044544K), 0.0549570 secs] [Times: user=0.19 sys=0.00, real=0.05 secs]

    可以發現Heap增長趨緩。

    運行兩天以后輸出:

    [GC [PSYoungGen: 256936K->3584K(257792K)] 859561K->606969K(1044224K), 0.0565910 secs] [Times: user=0.18 sys=0.01, real=0.06 secs]

    [GC [PSYoungGen: 256960K->3368K(257728K)] 860345K->607445K(1044160K), 0.0553780 secs] [Times: user=0.18 sys=0.01, real=0.06 secs]

    發現Heap反而減少了,此時可以對內存泄露問題作初步排除了。(其實在jdk1.6環境下用jprofiler來觀察,對于concurrent那個內存泄露點的跟蹤發現,內存的確還是會不斷增長的,不過在一段時間后還是有回收,因此也就可以部分解釋前面出現的情況)

    總結:

             對于GC輸出的觀察需要分兩個維度來看。一個是縱向比較,也就是一次回收對于內存變化的觀察。一個是橫向比較,對于長時間內存分配占用情況的比較,這部分比較需要較長時間的觀察,不能僅僅憑短時間的幾個抽樣比較,因為對于抽樣來說,Full GC前后的區別,運行時長的區別,資源瞬時占用的區別都會影響判斷。同時要結合Full GC發生的時間周期,每一次GC收集所耗費的時間作為輔助判斷標準。

             順便說一下,Heap YoungGen,OldGen,PermGen的設置也是需要注意的,并不是越大越好,越大執行收集的時間越久,但是可能執行Full GC的頻率會比較低,因此需要權衡。這些仔細的去了解一下GC的基礎設計思想會更有幫助,不過一般用默認的也不錯。還有就是可以配置一些特殊的GC,并行,同步等等,充分利用多CPU的資源。

             對于GC的優化可以通過現在很多圖形工具來做,也可以類似于我這樣采用最原始的分析方式,好處就是任何時間任何地點只要知道原理就可以分析無需借助外部工具。原始的總是最好的^_^

    posted @ 2008-10-22 16:36 岑文初 閱讀(4843) | 評論 (5)編輯 收藏

             從去年到今年,開放這個詞也在互聯網上炒得火熱,自己一年多的工作也讓自己對開放這個詞有了自己的一些理解和認識。

    開放的平臺

             去年到今年自己的工作也隨著公司的戰略改變不斷的發生著變化。最早公司定位致力于為中小企業提供商務管理軟件,讓中小企業能夠通過使用在線軟件輕松搞定電子商務貿易管理。隨后公司又致力于提供開放的在線軟件運營平臺,為眾多ISV和中小企業建立一個軟件交易平臺,中小企業可以隨需定制管理軟件。到今年年初,提出了服務集成平臺,ISV的應用開發不再是封閉的開發模式,可以基于ISP提供的服務定制出更加豐富的應用。其實這種轉變也是對平臺的開放的思想不斷成熟的一個過程。

             獨自實現在線管理軟件和傳統軟件其實沒有太大的差別,唯一的差別就是把應用由客戶的機器拉到了軟件提供商的服務器上,對于維護,更新和商業模式可能有部分的變化,但是根本上來說軟件的封閉性還是和傳統軟件一樣。互聯網軟件的最大特點就是個性化需求強烈以及需求變更周期短,要適應行業客戶的需求,僅僅靠一個公司的幾桿槍幾號人的創意遠遠不夠。Web2.0的熱潮其實能夠給開發人員最大的啟示就是參與才是力量的源泉,其實軟件開發也是一樣,如果能夠集合互聯網上眾多ISV的思想和創意,那么滿足用戶需求并不是一件難事,同時及時響應用戶需求也不再是火燒屁股的事情。同時,看看互聯網應用開發的今天,國外Open API前幾年就已經興起,Amazon,Google,Yahoo,FaceBook,MySpace等等,將自己的數據,存儲,計算通過API的方式提供給第三方,讓第三方開發者能夠通過使用這些服務有機會實踐自己的創新和創意,互聯網應用的開發也有了新的開放式開發模式。服務集成平臺其實就是為ISV提供了創建應用的一個資源平臺,ISV可以通過服務集成平臺獲取到各個ISP(例如淘寶)API,在其基礎上開發出在線應用,然后直接掛接到應用運營平臺為終端用戶提供應用服務。這很類似于傳統行業的產業鏈,服務集成平臺就好比原料交易市場,應用運營平臺就好比商品交易市場。回過頭來看,阿里系的各個子公司,其實都是在以這種思路做事,從加入公司到現在,給我印象最深刻的一句話就是:“凡事不要先想著如何賺到別人的錢,讓別人先賺到錢,別人自然很樂意的和你分享”,這種雙贏的思想在開放中能夠得到最好的實踐。

    開放的框架

             一個公司技術是需要積累的,如果純粹讓每一個開發人員根據自己的能力去合作開發企業的產品和平臺,對于企業,對于產品都是不利的。Java吸引人就在于它的開源世界,每一個開發人員可以去獲得自己想要的,或者去貢獻給他人自己創造的。現在很多公司應聘的過程就是一個開源知識問答,其實是否用過能說明什么問題呢,關鍵是沒用過如何去學習和了解并且快速上手,如果能力再強一點,那就知道如何定制和擴展,我想這樣的才可以叫做企業需要的人才。

             從公司成立那時起,內部就有一個應用開發框架,作用就是為了快速開發應用,盡最大可能降低開發者對于開發技術的學習,集中精力致力于業務開發。(當然看到這里估計98%的開發人員都會皺起眉頭)。我也為此貢獻了自己2Q的工作時間,當時我主要負責后臺重構,需要建立起一個服務框架,開始參考了OSGI(因為它的模塊化和動態載入機制),發現并不是很合適,然后接觸了SCA框架(可擴展,模塊化,SOA的支持),最后決定在開源項目Tuscany0.91版本的基礎上再次開發和封裝,實現了內部的ASF(應用服務框架)ASF作為我們開發框架的后臺基礎框架被廣泛使用在了我們的多條產品線以及基礎平臺上,但是ASF的質疑就一直沒有停過,性能,學習成本,調試困難度等等。雖然自己竭力去寫了厚厚的一套文檔,一組單元測試工具,一系列的問題查找工具,作了多次的壓力測試,學習普及,但是還是得不到一些架構師的支持。

             其實,自己在后面也做過一些思考,其實對于ASF來說,它的可擴展性沒有什么好懷疑,他不像其他開源項目,我可以封裝Hessian組件,REST組件等等,隨需載入,開發者只需要配置一下標簽,即可使用,因此這樣的框架下,不會隨著技術的發展和自己的封閉而腐爛。但是,有一點就導致推廣產生了那么多問題,那就是參與。我記憶很深的就是我們的首席架構師在今年招開會議評估ASF的問題時地郵件中說的:“ASF不是岑文初一個人的ASF,也不是平臺一部的ASF,而是大家的ASF”。其實那時候我已經不再專職負責ASF,當今年因為一個項目進度由于開發受到影響時再次提出ASF的質疑地時候,我自己真的覺得比較沮喪,很多架構師和開發者從來就沒有看過文檔,沒有用過調試工具,沒有看過Q&A,一出問題就覺得無所適從,要找人解決框架問題,我曾經說是否Spring用的時候出現問題,第一想法就是去找Spring的開發者,還是先會看看文檔,調試一下。我想這應該是兩方面的原因,但如果能夠讓每個人都參與進來,那么就不會是今天一人獨擋的局面。

             因此未來自己的工作中,不論是內部的基礎組件還是基礎平臺都會多邀請一些參與者,畢竟自己的肩膀有限,螞蟻就算在大力也需要有伙伴的支持。

    開放的心態

             這點其實是做人的基本要素,有一個寬闊的胸懷才會有更多的機會,才會成長的更快。但是自己這點的卻做得很不夠。開發人員都有一個相同的特點就是熱衷于技術鉆研,今天搞一個東西比你快一點,明天做一個東西比他功能多一點,總是在技術方面去尋找滿足。其實老大一直和我們也在說,現在公司內部的架構師并不是一個“全專”,也不一定是一個寫代碼高手,但是在某一個領域會有深入的研究,同時接觸其他領域也能夠勝任。沒有什么技術人員是絕對的高手,其實隨著工作重心的不斷變化,所接觸的領域也會不斷發生變化,因此不可能有所謂的“全才”。

             有時候自己也會用技術的眼光去看待人或者事,其實這樣只會讓自己看不到自己的不足,也忽略了別人的優點,更重要的就是失去了一次進步的機會。其實經常給自己換換思路會對自己有很大的幫助,就好比最近忙于寫了一陣子代碼,那么就給自己一個機會去看看一些關于搜索領域的知識。開發了一個階段的服務集成平臺,去了解一下所有的國外網站Open API的風格,結構,流程。用慣了Java后,去學習學習Php,Ruby等等。這樣換換腦子對自己來說會有新的收獲。

             開放的心態理解容易,但是要讓他不僅僅寫在MSNtitle中,而寫在心里卻需要不斷地督促和付出。不過知道自己有問題好過覺得自己沒有問題。

             寫了那么些,其實思路比較亂,我想從隨筆里面也看得出來,但是還是想記錄一下自己的一些思考,起碼以后回過頭來可以看到自己成長的過程。

    posted @ 2008-10-07 13:24 岑文初 閱讀(1718) | 評論 (5)編輯 收藏

        昨天貼了這個帖子以后,有同學說我是不是寫錯了,Memcached Cache應該是分布式的Cache,怎么變成集中式了。

        這里把我另外一部分的內容貼出來。

        Memcached是一種集中式Cache,支持分布式橫向擴展。這里需要有點說明,很多開發者覺得Memcached是一種分布式Cache,但是其實Memcached服務端本身是單實例的,只是在客戶端實現過程中可以根據存儲的主鍵作分區存儲,而這個區就是Memcached服務端的一個或者多個實例,如果將客戶端也囊括到Memcached中,那么可以部分概念上說是集中式的。其實回顧一下集中式的構架,無非兩種情況:1.節點均衡的網狀(JBoss Tree Cache),利用JGroup的多播通信機制來同步數據。2.Master-Slaves模式(分布式文件系統),由Master來管理Slave,如何選擇Slave,如何遷移數據,都是由Master來完成,但是Master本身也存在單點問題。

    總結幾個它的特點來理解一下它的優點和限制。

             Memory:內存存儲,不言而喻,速度快,對于內存的要求高,不指出的話所緩存的內容非持久化。對于CPU要求很低,所以常常采用將Memcached服務端和一些CPU高消耗Memory低消耗應用部屬在一起。(作為我們AEP正好有這樣的環境,我們的接口服務器有多臺,接口服務器對于CPU要求很高(由于WS-Security),但是對于Memory要求很低,因此可以用作Memcached的服務端部屬機器)

             集中式Cache:避開了分布式Cache的傳播問題,但是需要非單點保證其可靠性,這個就是后面集成中所作的cluster的工作,可以將多個Memcached作為一個虛擬的cluster,同時對于cluster的讀寫和普通的memcached的讀寫性能沒有差別。

             分布式擴展:Memcached的很突出一個優點,就是采用了可分布式擴展的模式。可以將部屬在一臺機器上的多個Memcached服務端或者部署在多個機器上的Memcached服務端組成一個虛擬的服務端,對于調用者來說完全屏蔽和透明。提高的單機器的內存利用率,也提供了scale out的方式。

             Socket通信:傳輸內容的大小以及序列化的問題需要注意,雖然Memcached通常會被放置到內網作為Cache,Socket傳輸速率應該比較高(當前支持Tcp和udp兩種模式,同時根據客戶端的不同可以選擇使用nio的同步或者異步調用方式),但是序列化成本和帶寬成本還是需要注意。這里也提一下序列化,對于對象序列化的性能往往讓大家頭痛,但是如果對于同一類的Class對象序列化傳輸,第一次序列化時間比較長,后續就會優化,其實也就是說序列化最大的消耗不是對象序列化,而是類的序列化。如果穿過去的只是字符串,那么是最好的,省去了序列化的操作,因此在Memcached中保存的往往是較小的內容。

             特殊的內存分配機制:首先要說明的是Memcached支持最大的存儲對象為1M。它的內存分配比較特殊,但是這樣的分配方式其實也是對于性能考慮的,簡單的分配機制可以更容易回收再分配,節省對于CPU的使用。這里用一個酒窖比喻來說明這種內存分配機制,首先在Memcached起來的時候可以通過參數設置使用的總共的Memory,這個就是建造一個酒窖,然后在有酒進入的時候,首先申請(通常是1M)的空間,用來建酒架,酒架根據這個酒瓶的大小分割酒架為多個小格子安放酒瓶,將同樣大小范圍內的酒瓶都放置在一類酒架上面。例如20cm半徑的酒瓶放置在可以容納20-25cm的酒架A上,30cm半徑的酒瓶就放置在容納25-30cm的酒架B上。回收機制也很簡單,首先新酒入庫,看看酒架是否有可以回收的地方,如果有直接使用,如果沒有申請新的地方,如果申請不到,采用配置的過期策略。這個特點來看,如果要放的內容大小十分離散,同時大小比例相差梯度很明顯,那么可能對于使用空間來說不好,可能在酒架A上就放了一瓶酒,但占用掉了一個酒架的位置。

             Cache機制簡單:有時候很多開源的項目做的面面俱到,但是最后也就是因為過于注重一些非必要性的功能而拖累了性能,這里要提到的就是Memcached的簡單性。首先它沒有什么同步,消息分發,兩階段提交等等,它就是一個很簡單的Cache,把東西放進去,然后可以取出來,如果發現所提供的Key沒有命中,那么就很直白的告訴你,你這個key沒有任何對應的東西在緩存里,去數據庫或者其他地方取,當你在外部數據源取到的時候,可以直接將內容置入到Cache中,這樣下次就可以命中了。這里會提到怎么去同步這些數據,兩種方式,一種就是在你修改了以后立刻更新Cache內容,這樣就會即時生效。另一種是說容許有失效時間,到了失效時間,自然就會將內容刪除,此時再去去的時候就會命中不了,然后再次將內容置入Cache,用來更新內容。后者用在一些時時性要求不高,寫入不頻繁的情況。

             客戶端的重要性:Memcached是用C寫的一個服務端,客戶端沒有規定,反正是Socket傳輸,只要語言支持Socket通信,通過Command的簡單協議就可以通信,但是客戶端設計的合理十分重要,同時也給使用者提供了很大的空間去擴展和設計客戶端來滿足各種場景的需要,包括容錯,權重,效率,特殊的功能性需求,嵌入框架等等。

             幾個應用點:小對象的緩存(用戶的token,權限信息,資源信息)。小的靜態資源緩存。Sql結果的緩存(這部分用的好,性能提高相當大,同時由于Memcached自身提供scale out,那么對于db scale out的老大難問題無疑是一劑好藥)。ESB消息緩存。

    posted @ 2008-09-26 11:45 岑文初 閱讀(3286) | 評論 (2)編輯 收藏

         摘要:   Author:文初 Email: wenchu.cenwc@alibaba-inc.com Blog: http://blog.csdn.net/cenwenchu79/            MemCached Cache在大型網站被應用得越來越廣泛,不同語言的客戶端也都在官方網站上...  閱讀全文
    posted @ 2008-09-25 16:34 岑文初 閱讀(6790) | 評論 (3)編輯 收藏

    越是忙,雜七雜八的事情越多,最近正在優化Memcache的客戶端代碼,這時候SIP突然出現OOM的問題(Out of Memory),作開發最頭痛就是這種問題,壓力測試都作過,早期的幾個版本都沒有出現這樣的問題,因此懷疑可能是最近一次發布修改引起的。借助JProfiler在測試環境搭了一套系統,開始做壓力測試,來分析Memory到底流到了哪里去了。

    問題一:連接池泄漏

           看到這個問題,我想很多人都說,都什么年代了,使用開源的現成連接池,怎么還會有這樣的問題,又不是那些使用jdbc的年代了。那來看看現象吧。

    場景:測試部用loadRunner往死里壓,發現很多業務對象不斷增長,但是按照業務場景來說,這些業務對象處理以后就自動釋放了。(在本地的開發環境驗證了是會自動釋放的)

    JProfiler截圖:

           上圖中可以看到有很多業務對象已經累積占用了不少內存,在讓測試部同學停掉壓力測試以后,等待了一會兒,然后用JProfiler主動發起垃圾回收,也看到了Jboss后臺有GC回收的記錄輸出以后,發現這些對象依然存在,也就是說這些對象成為了Memory泄漏的誘因之一。但是就如我所說的,在本地測試以及白盒測試來看,這些對象在一次請求以后,處理完畢一定會被釋放,沒有被其他MapReference,然后通過JProfiler看了看這些對象的Allocation Call Tree,就是我們處理請求的Servlet作為源頭的,但為什么Servlet沒有被清理掉呢?接著來看看后面二張圖

           既然知道對象存在并且被Hold了,那么就去看看線程運行的狀況,這一看發現有很多線程都處于Wait的狀態(其實在serverdump也可以看到),這張圖上就可以看到,我選擇了其中一個wait的線程它處于等待狀態的原因就是在ibatisThrottleincrement的時候處于等待狀態,看了看ibatis的代碼,這部分代碼其實是ibatis連接池的一段代碼,在連接池被占滿以后,處于等待釋放的狀態,也就是說程序把連接池耗盡了。

           為了驗證是否是耗盡了,讓DBA老大光輝給我看了看MySql(這部分當天的日志數據都保存在MySql中)的連接情況,發現只有8個連接,看來不是真的耗盡,應該是連接池泄露了。光輝告訴我,這八個連接都在做同一個查詢,就是統計某一個API的訪問記錄次數和流量。在當前的業務流程中對于MySql主要做了兩類操作:

           1.訪問控制計數器創建的統計查詢。

    由于要對Open API訪問控制,采用了Memcache計數器方式來實現。當發現此類API沒有創建過計數器,那么就分析MySql中的數據,創建計數器,后續的訪問記錄除了插入數據庫以外還需要累加計數器,這樣訪問控制可以高效使用集中式計數器而不需要查詢數據庫。

    2.日志批量異步寫入。

    對于Open API的記錄采用了線程池中每一個線程維護一個內存分頁,當頁滿或者到了刷新間隔時,一次性批量寫入數據庫,緩解數據庫寫入壓力,這里采用了事務來批量提交。

           對于第一種操作,由于設計中MySql就只會保留當天的數據量,因此只有系統啟動的時候做一次統計,對于數據庫壓力和Sql執行來說應該沒有太大的壓力,但是由于壓力測試是從昨天下午就開始做的,里面的數據已經有上千萬,因此這次重新啟動開始做壓力測試,導致了這個創建計數器的Sql執行很慢。同時日志的批量寫入采用的是事務方式來提交,對于MySql其實自己還不是很深入,但是感覺上來說,問題應該出現在這里,由于查詢的緩慢在加上事務批量的提交,可能會造成事務失敗,同時沒有正確的將釋放資源的信號傳遞給ibatis,導致了看起來的連接資源耗盡。

           我將數據庫中的記錄全部刪除,然后重新啟動,開始壓力測試,問題不存在了,對象都及時得到回收。后續還會去跟進這個問題,在ibatis早期版本,同樣是這個類出現了死鎖的問題,后來升級得到了解決,但是也看到很多國外的朋友說道2.22.3其實還是有死鎖的問題,不過我個人覺得可能還是和數據庫也有一定關系。

    疑問:

           這個問題的背后我還有一點疑問,對于我們來說,如果一個普通的http請求,當超時以后肯定就會自動中斷,但是在這個場景中,我足足等了1個小時還是沒有釋放,也就是說客戶端其實已經斷開了,但是JBoss好像并不會釋放這些處理請求的事務,導致資源被卡。

    問題二:LinkedBlockingQueue惹禍

           自從Jdk1.5以后concurrent包為大家提供了很多便利高效的開發新模式,我在不少地方用到了LinkedBlockingQueue,作為消費者和生產者之間的數據通道,消費者們等待在LinkedBlockingQueue門口守候生產者提供數據,獲取數據后就開始并行處理。這里我會采用queue.poll(100,TimeUnit.MILLISECONDS)這種方式來半阻塞的獲取數據。其實在昨天已經聽說LinkedBlockingQueue可能存在著內存泄露的問題,看了看很多網上的人也都提到了這個問題,在1.5種沒有得到解決,在1.6中會去fix這個問題,但是沒有證據,也不好亂加斷定。在問題一搞好以后,然后繼續查找潛在bug,這時候不經意的發現有一個對象隨著時間的推移始終在增加,但是由于單個對象占的內存不大,因此沒有很明顯的體現出來,但是對象實例的增加卻是很明顯的,看看下面兩張圖:

          

    這兩張圖的間隔時間2小時左右,可以發現這個對象的instance已經有了很大的增長,同時內存也吃了不少,看了看創建這個對象的Tree,發現就是poll這個方法,也就是我線程池中線程周期性掃描的結果。這期間沒有任何訪問,僅僅就是放著不動,就有如此大量的增長。我嘗試將poll(100,TimeUnit.MILLISECONDS)換成poll()全阻塞方式,對象增長依舊。因此可以看出來服務器的Memory Leak很大程度上由這部分引起,早先沒有發現,因為是SIP上線不久,沒有太多用戶,而這陣子用戶越來越多,加上API中的更新類請求比較吃內存,就容易發現此類問題。

           那么是否1.6就解決了這個問題呢,開始使用機器上1.6_01的版本,發現問題依舊,去sun下載了最新的1.6_07,發現的卻會回收,但是回收和增長都存在,具體數據描述舉例如下:

    1.       1000 instance   31k

    2.       200 instance    6k (回收了一部分)

    3.       1500 instance   46k(發現增長的比以前還多)

    4.       300 instance    9k (回收了一部分)

    5.       2000 instance   62k (發現增長的比以前還多)

    也就是說,回收時有發生,但是總體趨勢還是在上升,這個真的還需要好好測試,有興趣的同學也可以試驗一下我的測試方式,就僅僅只需要使用一個LinkedBlockingQueue,然后定時的去pool1.5絕對增長的不小。

           對于這個問題,我只能再去驗證,如果發現真的暫時不可避免,那么只有考慮替代方案了。

    這是今天作了Memory Leak的一些分享,希望也能給其他遇到或者將會遇到問題的同學一個分享,說一句,如果有條件的話用JProfiler去分析性能絕對是不錯的,沒有條件么就dump,gc輸出來查找問題。
       剛剛作了測試現在的場景可以用take來替換poll,原來是看中了poll的timeout方式,take完全沒有問題,看來如果要在1.5版本用,還是老老實實用take。

    posted @ 2008-09-18 22:14 岑文初 閱讀(3931) | 評論 (4)編輯 收藏

     

           集團內部很多團隊都使用Memcache來提高應用性能,最近的一次工作匯報中提及了MemcacheHash算法需要研究來滿足一些需求,同時提高Memcache的利用效率。討論了一下最后自己總結了這么幾點是對Hash算法需要著重考慮的。

    問題:

    1.       存儲數據如何均勻分散。如何把數據盡可能的散開存儲,這樣對于Memcache的可擴展性才會有充分利用,試想如果算法每次都會把數據定向到某幾臺機器,那么就會導致集群機器之間利用率的不均衡,無法發揮出集群效應。

    2.       增減機器減小對原有數據存取的影響。由于業務量的增長勢必需要對后端的服務器有所擴容,但是增加或者減少機器如何盡可能小的影響已有的緩存數據,這點直接影響業務處理以及應用的效率。

    3.       提高Memcache效率。Memcache在壓力測試下也會暴露出對于網絡資源的消耗問題,畢竟也是網絡間的Socket數據交互。

    解決的一些思路和方法:

    1.       Consistent Hashing是一種比較好的解決思路。可以參看一下:http://tech.idv2.com/2008/07/24/memcached-004/ 其中主要兩個亮點就是稀釋節點以及環狀分區段管理。稀釋節點就是將原來的節點再復制幾十倍,使得離散度更高,數據更加分散。環狀分區段管理,就能夠將數據分區管理,在加入和減少節點時對數據產生影響最低,最好的類比就是解放前的地下工作者單線聯系,如果被捕不會涉及到所有的地下黨同志。

    2.       集群的機器使用Memcache最好結合本地Cache,這里我們自己寫了一個本地的類似于Memcache有超時時間Cache,兩者結合一起使用緩存信息,在壓力測試下提高了20%左右的性能。這里和我們的系統也有關系,我們對于Memcache有比較大的依賴,雖然已經對于每一個請求處理都防止重復獲取信息,將必要信息放在線程上下文中,但是在運行期間還是會有不少的請求。

    存儲到Memcache中的數據類型:

    1. 一次寫入多次讀,很少更新。這種數據系統啟動以后構建,在非命中情況下不采用從后備數據源中獲取數據來填充Memcache。(也是提高效率,同時防止一些攻擊性的請求)

    2. 多次寫入多次讀取。這類數據往往是在運行期被構建,非命中下會從后備數據源中獲取,或者是某一種計算結果的緩存。

    對于第一類數據來說,增加機器需要重新構建,如果采用分區分段,那么只需要構建某一部分的數據,或者是移動數據。對于第二類數據,增加機器如果采用簡單的Hash算法也問題不大,最多存儲多份,命中率降低,但是如果采用分區,也可以降低命中率下降的情況。

           這里只是拋出問題,后續如何解決請各位看官各抒己見了。當然這里自己也會考慮這方面的實現和設計。
    posted @ 2008-08-14 10:36 岑文初 閱讀(3435) | 評論 (1)編輯 收藏

    僅列出標題
    共12頁: First 上一頁 4 5 6 7 8 9 10 11 12 下一頁 
    主站蜘蛛池模板: 亚洲天堂免费在线视频| 国产亚洲精品欧洲在线观看| 国产日韩AV免费无码一区二区 | 国产在线观看免费完整版中文版 | 伊在人亚洲香蕉精品区麻豆| 国产中文在线亚洲精品官网| 亚洲Av无码乱码在线观看性色| 亚洲亚洲人成综合网络| 成年女人A毛片免费视频| 亚洲精品蜜桃久久久久久| 你懂得的在线观看免费视频| 日韩高清在线免费观看| 亚洲电影国产一区| 看成年女人免费午夜视频| 成人亚洲综合天堂| 精品国产免费一区二区三区| 午夜免费福利在线| 免费无码午夜福利片| 在线A亚洲老鸭窝天堂| 四虎影视成人永久免费观看视频| 亚洲黄色免费网址| 精品久久久久久久免费加勒比| 青青久久精品国产免费看 | 亚洲午夜电影在线观看高清| 一个人晚上在线观看的免费视频| 成熟女人牲交片免费观看视频 | 在线亚洲午夜理论AV大片| 嫩草在线视频www免费观看| 亚洲 综合 国产 欧洲 丝袜| 成人A毛片免费观看网站| 亚洲国产理论片在线播放| 日本无卡码免费一区二区三区| 精品一区二区三区高清免费观看| 亚洲成人激情在线| 永久中文字幕免费视频网站| 中国黄色免费网站| 亚洲1区1区3区4区产品乱码芒果| 日韩免费无码一区二区三区| 亚洲精品无码久久| 亚洲国产美国国产综合一区二区| 两性色午夜免费视频|