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% 這是比任何優化方案都有效的解決方法。是從業務本身去思考並優化,這個需要集思廣益。)