Openfire 是一個XMPP協議的IM Server。
Openfire使用mysql配合它不知所謂幾乎無效的的Cache機制就註定無法支撐高併發,
所以第一步,將資料庫切換為比較強一點的MongoDB。
但是MongoDB也是有問題的,在高併發時才會發現,MongoDB的鎖表十分嚴重,
經過調查發現,MongoDB也比較坑爹,他是使用“全域性鎖”的,也就是說,你更新A表的時候,會鎖住B表,資料更新後解鎖。
所以作為實時查詢資料庫即使是使用MongoDB的master/slave模式依然不能勝任。
增加解決方案,快取層,使用redis作為MongoDB的資料快取,在訪問時資料時,首先進入Cache層訪問redis,如果沒有,再去訪問MongoDB,然後再回頭填充Redis。
OK,資料來源解決了,接下來確認需要在什麼地方切入。
1,首先是將使用者資訊資料切換到MongoDB中。並停止Openfire自己的Roster服務,在管理控制檯設定 xmpp.client.roster.active = false
2,AuthProvider,這裡是登陸模組,可以繼承介面重寫一個屬於自己的Provider。
重寫authenticate方法,將登陸驗證請求交給cache層。
3,離線資訊的儲存在之後也會成為負擔,那麼繼承OfflineMessageStore類,重寫屬於自己的離線資訊策略,將離線資訊儲存到Redis中。
4,重寫狀態更新的廣播:PresenceUpdateHandler中的broadcastUpdate方法。
好了,這時候Openfire已經被修改的面目全非,但是效率已經不可同日而語了。
這時候還有一個問題,就是Openfire沒有訊息保障機制,也就是說,網路不穩定的時候,客戶端異常斷線,資訊就會傳送到空氣中,
需要再傳送資訊的時候實現“握手機制”來保障資訊的可靠性。不細說了,自己百度。
這時候Openfire的線上使用者可以飈到6W無壓力,但是死活上不去了,又被限制了。
在error.log中會發現類似 “open files too larger” 一類的錯誤,這些是linux系統引數:最大檔案開啟數。
在linux下執行ulimit -a就能觀察最大的檔案開啟數,執行ulimit -n 350000設定為35萬,然後kill掉openfire退出控制檯,重新連線控制檯使其生效,重新啟動Openfire。
好吧,這時候使用者量可以飆6W以上了。
XMPP伺服器的測試工具,比較簡單的可以使用tsung來實現,簡單的配置,模擬成千上萬的使用者登陸,並且可以模擬HTTP等其他請求。
接下來就是單臺伺服器容量的問題了,我們伺服器是Dell R710, 64G記憶體 16核CPU,15000轉硬碟。
伺服器在這種架構下線上使用者資料在29W左右,幾乎已經是單臺Openfire封頂了。
開始考慮叢集,不過Openfire的幾種叢集都測試過,效果不理想,有一個神馬war包的外掛,弄上去時好時壞,放棄。
還有一個oracle的叢集外掛,不過在高壓下多臺Openfire直接脫離叢集,自己玩自己的了。。。日。
如果到了十萬二十萬左右的線上使用者級別,就放棄掉Openfire,可以嘗試使用tigase試試,或者和我們一樣,自己寫通訊伺服器。
以下內容參考文章:http://blog.csdn.net/jinzhencs/article/details/50404574
其他設定以及優化
外掛
- Subscription外掛:自動同意好友請求,新增外掛後在伺服器設定最下面設定方式。
伺服器設定
- 把沒用的一些設定關掉,例如HTTP繫結等等
優化
- 修改開啟最大檔案數目:ulimit –n 65535
- 設定伺服器快取大小,系統屬性加入:
// 注意不能有空格,特別是 size後面
// -1代表無窮大 100000000即是95M
ClientSessionInfoCache: cache.ClientSessionInfoCache.size
Roster: cache.username2roster.size
user: cache.userCache.size
group: cache.group.size
groupMeta: cache.groupMeta.size
offline message: cache.offlinemessage.size
offlinePresence: cache.offlinePresence.size
Last Activity Cache: cache.lastActivity.size
VCard: cache.VCard.size
// 以上都是高壓下容易飄紅的
要重啟openfire服務才能更新過來哦
未來需要優化的幾個點:
1.加大伺服器記憶體 20G變成150G
2.之前原始碼修改的是3.10.2,之後把新版本的原始碼下載下來重新修改,而後打包部署.
以解決3.10.2遺留的BUG(現在4.0beta版本出來了,可能過段時間會開源,改了很多bug)
3.根據需求定製openfire,即去除無用的元件,出去無用的消耗資源的一些cache或hashMap,變數之類
4.移出session,把session存入到redis中。
5.除了session,其他的很多cache(伺服器快取)全部移入redis。
openfire不使用mysql,使用redis作為資料庫儲存資料,再做個mysql持久化及主從就行了。
論壇有牛人說過:openfire使用了它那不知所謂的cache(其實就是HashMap),就註定無法支撐數十萬連線。
(強哥說了:HashMap儲存超過幾萬後,會有問題,好像是jdk自帶的問題)
另外一個最重要的優化的方面,就是保證連上伺服器的是 有用 的使用者。
譬如我們伺服器之前連了10W,但是其實真正使用者繫結並使用XX系統的只有1W,但是10W個客戶端卻是連著的。 (舉例子,之前我們的系統就好比進入淘寶後臺自動登入旺旺,那麼進淘寶多少人就有多少人登入了旺旺,但是其實真正使用旺旺的只有十分之一甚至更少,我們只需要讓使用者在需要旺旺對話的時候才連線伺服器的話,那麼瞬間伺服器壓力能減少 90% 這是比任何優化方案都有效的解決方法。是從業務本身去思考並優化,這個需要集思廣益。)