Apache Commons Pool 故事一則

jopen 8年前發布 | 9K 次閱讀 Apache Commons Pool

最近工作中遇到一個由于對commons-pool的使用不當而引發的問題,習得正確的使用姿勢后,寫下這個簡單的故事,幫助理解Apache Commons Pool的工作原理。

Apache Commons Pool, Java界無人不知無人不曉的對象池技術, 常用于實現各種連接池, 如數據庫連接池, Redis連接池等

下面以租車公司為例子說明這張圖,介紹commons pool的基本工作方式:

 Apache Commons Pool 故事一則

GenericObjectPool(租車公司)

作為租車公司,需要提供租車和收回歸還的車輛的兩個服務,同時它還要管理著所有的那些車輛,隨著業務發展壯大,需要買新車;對于已經不能安全駕駛的車輛,需要將其銷毀;同時還要定期對車輛進行安全檢測等。

PooledObject(租車公司的所有車輛)

租車公司的車輛分為三類:空閑可租用的車輛(Idle Objects),已借出的車輛(Active Objects),認為已丟棄的車輛(Anandoned Objects)

Borrow Object(租車)

  • A1: 世界那么大,一位年輕人想租輛車出去逛逛
  • A2: 老板先看看有沒有空閑的車
  • A3.1: 如果有,則將最近歸還的車借出去,并標記為已借出(Active),如果沒有空閑的車了,就買輛,同時也標記為已借出(這是一家不差錢的公司)
  • A3.2: 老板把標記好的車租給年輕人

Return Object(還車)

  • B1: 世界那么大,年輕人終于逛完了,回來還車
  • B2: 老板把車放回停車場,并把標記改為空閑狀態(Idle),可以再被其他人租用。

TestOnBorrow/TestOnReturn(租出/歸還時進行檢查)

這家公司不僅不差錢,它對車輛的安全還很負責,對于租出去的車,不管是從空閑車輛里取出的,還是新買回的,都會先檢查一遍這車的好壞,總不能坑了年 輕人,如果發現有問題,立馬再換一輛。歸還的時候,也會檢查一遍,如果有問題,就扔掉(真土豪),除此之外,公司還專門請了一位車輛安檢員,定期對閑置了 一段時間的車輛進行安全檢測(Evict Thread),一有問題也扔掉。

有借有還,看上去一切都很美好。

然而現實里總有意外發生:

年輕人借走車后,發現世界越逛越大,久久不愿回家。 安檢員定期檢查時發現這車子都借出去大半年了,還沒還回來,是不是丟了?于是掏出手機,”啪“的按了一下,遠程將車子熄了火,標記為報廢車輛(Abandoned),當作報廢處理了。

Evict Thread(定期檢查的安檢人員)

  • C1: 對于已歸還標記為空閑的車輛,安檢員定期對它們抽查,如果超過一段時間沒有使用,看看是否壞掉,壞了就及時作廢掉(C2).
  • D1: 對于標記為已借出的對象,安檢員定期檢查時發現借出很久都未還,直接作廢(D2)。

好了,故事講完了,希望大家對Commons Pool都理解了。


有興趣的同學可以繼續往下看看我們遇到的那個問題:

我們使用Jedis作為redis客戶端操作,在壓測環境下,時不時發現Jedis報了這個異常: ClassCastException - [B cannot be cast to java.lang.Long

網上各種google百度,發現大部分網友們說是由于pipeline操作,出現異常時連接沒有正確destory掉,而直接放回連接池里,被下個線程拿到后,取到連接中殘留的pipeline的操作結果,從而導致類型轉換錯誤。

這個解釋聽起來很在理,但反復檢查代碼,發現對于異常的封裝都做好了,而且出現問題時也沒有使用pipeline操作,應該不是網友們說的情況。

于是懷疑是不是連接池出了問題,多個線程對同一個連接做了不同的操作,獲取錯了數據導致,但大名鼎鼎的commons-pool出現這樣低級的錯誤,不可能呀?

翻了幾遍commons-pool的代碼后,發現可能是上面說的那個定期檢查的安檢員搗的鬼?

對于借出的對象,我們配置成借出后超過10秒不歸還則作廢,理論上對于redis的操作,10秒確實也足夠了,但是我們對JedisPool做了進 一步的封裝,在一些特殊情況下,確實會出現持有連接超過10秒的情況(這個就不展開了),導致連接還在被程序使用,讀取redis的數據處理時,被清理線 程無辜的銷毀了(調用jedis.quit()),

jedis的quit命令返回值就是一個Byte數組,而我們的操作返回是Long,于是就出現了ClassCastException - [B cannot be cast to java.lang.Long這樣的異常。

最后的解決辦法就是將作廢時間的定義適當加大。

來自:http://neway6655.github.io/commons-pool, java/2015/12/12/ApacheCommonsPool故事一則.html

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!