在測試Adhesive的時候發現,使用過一段時間後台之後,就會不能串連到資料庫,查看日誌發現報的錯誤大致是
connection refused because too many open connections: 819
通過mongostat查看串連數的確很誇張有近819個串連,嘗試在啟動的時候指定最大串連數到10000,重新啟動Mongodb這個問題似乎解決了
但是在重新整理幾下頁面之後串連數串到了4000,以前在使用的過程中即使線上上非常大的壓力情況下串連數也在50之內,幾千的串連數還是第一次見到
首先想是不是程式問題引起的,因為在程式中我們的折線圖一次需要進行100次左右的Count操作來得到每一個點的總數:
雖然在程式中使用了並行庫但是在只有一條折線的情況下是單線程的,因此排除並行庫問題
而且發現每一次刷頁面串連數都會大幅上漲,根本沒有回落的時候
這想到了是串連沒有釋放,經過查看官方文檔知道並不需要在每次調用之後顯式釋放串連
寫了一個最簡單的程式來測試:
static MongoServer server = MongoDB.Driver.MongoServer.Create("mongodb://192.168.129.172:20000/?slaveok=true"); static void Main(string[] args) { while (true) { Console.ReadLine(); var db = server.GetDatabase("qqtest"); var col = db.GetCollection("test"); try { Console.WriteLine(col.Count()); } catch (Exception ex) { Console.WriteLine(ex.Message); } } }
很明顯,按一次斷行符號,串連數漲1!但是奇怪的是,寫入資料的Master卻不會有這個問題,於是把連接字串修改為Master的地址
mongodb://192.168.129.142:20000/
居然正常了,不管怎麼按斷行符號,或是迴圈幾百次串連始終只增加了一個,說明串連複用了
至此,肯定是串連Slave的時候才會有這個問題,這問題也算是隱蔽。
當時的這個版本是直接從NuGet引用的,沒有原始碼,於是下載到1.1.0.4184的原始碼調試
在調試後發現MongoServer.cs其中有一個方法:
private void InstanceStateChanged( object sender, object args ) { lock (instances) { if (instances.Any(i => i.State == MongoServerState.Connected && i.IsPrimary)) { // Console.WriteLine("Server state: Connected"); state = MongoServerState.Connected; return; } if (settings.SlaveOk) { if (instances.Any(i => i.State == MongoServerState.Connected && (i.IsSecondary || i.IsPassive))) { // Console.WriteLine("Server state: Connected"); state = MongoServerState.Connected; return; } } if (instances.Any(i => i.State == MongoServerState.Connecting)) { // Console.WriteLine("Server state: Connecting"); state = MongoServerState.Connecting; return; } // Console.WriteLine("Server state: Disconnected"); state = MongoServerState.Disconnected; } }
把備註陳述式去掉,看看啟動並執行情況:
這個方法中會根據串連狀態改變來改變伺服器的狀態,在串連上資料庫之後,由於SlaveOk進入了黑體的語句,instances其中已經有一個狀態是Connected的項了,但是由於i又不是IsSecondary也不是IsPassive,因此不能滿足條件,直接變為了state = MongoServerState.Disconnected。也就是對於SlaveOk每次都是不能認為資料庫已串連,每次都是重新串連!可以看到,每次最後都轉到了state = MongoServerState.Disconnected,其實應該是運行state = MongoServerState.Connected。我想這裡作者的意思大概是為了增加一個SlaveOk的判斷吧,而對於Slave的情況,IsSecondary和IsPassive都為false的,那麼我把黑體代碼改為如下:
if (instances.Any(i => i.State == MongoServerState.Connected && (!i.IsPrimary))) {
再運行程式,發現這個問題解決了。。。再來看看運行情況:
這次就對了,在進行一次串連之後,後面的請求都沒有再初始化一個串連
想到是否可以更新下用戶端看看最新的用戶端版本是否解決了這個問題,去官網下載了最新的1.3版本,發現沒有了這個問題。那麼我想看看作者是怎麼修改的,查看這個檔案的曆史,在某一個曆史中看到了這段代碼的改動記錄:
可以看到原先的這段判斷被刪除了,這下思路清晰很多了!直接進行對應狀態的設定,SlaveOk的判斷和狀態的設定不在有關係。
分享此次排查問題的過程,拋磚引玉,提醒下大家在使用開源組件的時候需要小心測試。