欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

解決mongo的tickets被耗盡導(dǎo)致卡頓問題

 更新時間:2023年04月08日 15:04:20   作者:泰勒今天不想展開  
這篇文章主要介紹了解決mongo的tickets被耗盡導(dǎo)致卡頓問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

近一年來,項目線上環(huán)境的mongo數(shù)據(jù)庫出現(xiàn)多次tickets被耗盡,導(dǎo)致數(shù)據(jù)庫卡頓,并且都是突然出現(xiàn),等待一段時間后又能自動恢復(fù)。

為了解決這個問題,我們進(jìn)行了長期的探索和研究,先后從多個角度進(jìn)行優(yōu)化,于此記錄和分享一下這一路的歷程。

tickets是什么

為了解決這個問題,我們首先要明白ticktes是什么,其實網(wǎng)上基本都說的一知半解,沒有一個能說明白的,但是有一個查詢tieckts消耗情況的mongo命令:

db.serverStatus().wiredTiger.concurrentTransactions

查詢結(jié)果:

{
	"write" : {
		"out" : 0,
		"available" : 128,
		"totalTickets" : 128
	},
	"read" : {
		"out" : 1,
		"available" : 127,
		"totalTickets" : 128
	}
}

可以看到tickets分為讀寫兩種,那ticktets到底是什么呢,我們根據(jù)這個查詢命令,其實大致可以猜測認(rèn)為是當(dāng)前同時存在的事務(wù)數(shù)量。

也就是mongo限制了同時進(jìn)行的事務(wù)數(shù)。

早期因為不知道tickets到底是什么意思,嘗試過很多思路錯誤的優(yōu)化,所以解決問題,最好還是能弄明白問題本身,才能對癥下藥。

思考?xì)v程

在眾多數(shù)據(jù)庫卡頓的經(jīng)歷中,曾有一次因為rabbitmq導(dǎo)致的數(shù)據(jù)庫卡頓,原因是一小伙伴在請求的過濾層加了一個發(fā)送mq的邏輯,但是沒有進(jìn)行限制,導(dǎo)致每次只有有接口被調(diào),都會去發(fā)布一個mq消息,由于過高的并發(fā)導(dǎo)致rabbitmq不堪重負(fù),倒是讓人想不明到的是mq卡的同時,數(shù)據(jù)庫也卡住了。

一開始以為是因為消息過多,導(dǎo)致消費者瘋狂消費,壓垮了數(shù)據(jù)庫,其實不存在這個問題,因為我們的mq配置單個消費者機器是串行的,也就是同一臺機器同一時間只會消費同一個消息隊列的一條消息,所以并不會因為消息的多給數(shù)據(jù)庫帶來壓力,只會堆積在mq集群里。所以這次其實沒有找到mq卡頓導(dǎo)致mongo卡頓的原因。

我們接入的幾家第三方服務(wù),比如給我們提供IM消息服務(wù)的融云,每次他們出現(xiàn)問題的時候,我們也會出現(xiàn)數(shù)據(jù)庫卡頓,并且每次時間出奇的一直,但也始終找不到原因。

起初經(jīng)過對他們調(diào)用我們接口情況進(jìn)行分析,發(fā)現(xiàn)每次他們出問題時,我們收到的請求會倍增,以為是這個原因?qū)е碌臄?shù)據(jù)庫壓力過大,并且我們基于redis和他們回調(diào)的流水號進(jìn)行了攔截,攔截方式如下:

  • 當(dāng)請求過來時從redis中查詢該筆流水號狀態(tài),如果狀態(tài)為已完結(jié),則直接成功返回
  • 如果查詢到狀態(tài)是進(jìn)行中,則拋異常給第三方,從而讓他繼續(xù)重試
  • 如果查詢不到狀態(tài),則嘗試設(shè)置狀態(tài)為進(jìn)行中并設(shè)置10秒左右的過期時間,如果設(shè)置成功,則放到數(shù)據(jù)庫層面進(jìn)行數(shù)據(jù)處理;如果設(shè)置失敗,也拋異常給第三方,等待下次重試
  • 等數(shù)據(jù)庫曾處理完成后,將redis中的流水號狀態(tài)改為已完結(jié)。

避免重復(fù)請求給我們帶來的數(shù)據(jù)庫的壓力。這其實也算是一部分原因但還是不算主要原因。

引起mongo卡頓的還有發(fā)布版本,有一段時間隔三差五發(fā)布版本,就會出現(xiàn)卡頓,但是查看更新的代碼也都是一些無關(guān)痛癢理論上不會引起問題的內(nèi)容。

后來發(fā)現(xiàn)是發(fā)布版本時每次同時關(guān)閉和啟動的機器從原來的一臺改成了兩臺(一臺一臺發(fā)布太慢,所以運維改成了兩臺兩臺一起發(fā)),感覺原因應(yīng)該就在這里,后來想到會不會和優(yōu)雅關(guān)閉有關(guān),當(dāng)機器關(guān)閉時仍然有mq消費者以及內(nèi)置循環(huán)腳本在執(zhí)行,當(dāng)進(jìn)程殺死時,會產(chǎn)生大量需要立馬回滾的事務(wù),從而導(dǎo)致mongo卡頓。

后來經(jīng)過和運維小伙伴的溝通發(fā)現(xiàn),在優(yōu)雅關(guān)閉方面確實存在問題,他們關(guān)閉容器時會小容器內(nèi)的主進(jìn)程發(fā)一個容器即將關(guān)閉的信號,然后等待幾十秒后,如果主進(jìn)程沒有自己關(guān)閉,則會直接殺死進(jìn)程。

為此我們需要在程序中實現(xiàn)對關(guān)閉信號的監(jiān)聽,并實現(xiàn)優(yōu)雅關(guān)閉的邏輯,在spring中,我們可以通過spring的時間拿到外部即將關(guān)閉的信號:

	@Volatile
	private var consumeSwitch = true

	/**
	* 銷毀邏輯
	*/
	@EventListener
	fun close(event: ContextClosedEvent){
		consumeSwitch = false
		logger.info("----------------------rabbitmq停止消費----------------------")
	}

可以通過如上方式,對系統(tǒng)中的mq消費者或者其他內(nèi)置程序進(jìn)行優(yōu)雅關(guān)??刂?,對優(yōu)雅關(guān)閉問題優(yōu)化后,服務(wù)器關(guān)閉重啟導(dǎo)致的數(shù)據(jù)庫卡頓確實得到了有效解決。

上面的融云問題優(yōu)化過后,后來融云再次卡頓的時候,還是會出現(xiàn)mongo卡頓,由此可見,肯定和第三方有關(guān),但上面說的問題肯定不是主要原因。

后來我看到我們調(diào)用第三方的邏輯很多都在@Transactional代碼塊中間,后來去看了第三方sdk里的邏輯,其實就是封裝了一個http請求,但是http請求的請求超時時間長達(dá)60秒,那就會有一個問題,如果這個時候第三方服務(wù)器卡頓了,這個請求就會不斷地等,知道60s超時,而由于這個操作是在事務(wù)塊中,意味著這個事務(wù)也不會commit掉,那等于這個事務(wù)所占用的tickets也一直不會放掉,至此根本原因似乎找到了,是因為事務(wù)本身被卡住了,導(dǎo)致tickets耗盡,從而后面新的事務(wù)全部都在等待狀態(tài),全部都卡住了。

其實這次找的原因,同樣也可以解釋前面mq卡頓導(dǎo)致的數(shù)據(jù)庫卡頓,因為同樣有大量的發(fā)送mq的操作在事務(wù)塊中,因為短時間瘋狂發(fā)mq,導(dǎo)致mq服務(wù)端卡頓,從而導(dǎo)致發(fā)mq的操作出現(xiàn)卡頓,這就會出現(xiàn)整個事務(wù)被卡住,接著tickets被消耗殆盡,整個數(shù)據(jù)庫卡頓。

找到確定問題后就好對癥下藥了,第三方的問題由于我們不能保證第三方的穩(wěn)定性,所以當(dāng)?shù)谌匠霈F(xiàn)問題時的思路應(yīng)該是進(jìn)行服務(wù)降級,允許部分功能不可用,確定核心業(yè)務(wù)不受影響,我們基于java線程池進(jìn)行了同步改異步處理,并且由于第三方的工作是給用戶推送im消息,所以配置的舍棄策略是當(dāng)阻塞隊列堆積滿之后,將最老的進(jìn)行丟棄。

而如果是mq導(dǎo)致的這種情況,我們這邊沒有進(jìn)行額外的處理,因為這種情況是有自身的bug導(dǎo)致的,這需要做好整理分享工作,避免再次出現(xiàn)這樣的bug。

//自己實現(xiàn)的runnable
abstract class RongCloudRunnable(
	private val taskDesc: String,
	private val params: Map<String, Any?>
	) : Runnable {


	override fun toString(): String {
		return "任務(wù)名稱:${taskDesc};任務(wù)參數(shù):${params}"
	}
}		
//構(gòu)建線程池
private val rongCloudThreadPool = ThreadPoolExecutor(
	externalProps.rongCloud.threadPoolCoreCnt, externalProps.rongCloud.threadPoolMaxCnt, 5,
	TimeUnit.MINUTES, LinkedBlockingQueue<Runnable>(externalProps.rongCloud.threadPoolQueueLength),
	RejectedExecutionHandler { r, executor ->
		if (!executor.isShutdown) {
			val item = executor.queue.poll()
			logger.warn("當(dāng)前融云阻塞任務(wù)過多,舍棄最老的任務(wù):${item}")
			executor.execute(r)
		}
	}
)

//封裝線程池任務(wù)處理方法
fun taskExecute(taskDesc: String, params: Map<String,Any?>, handle: ()-> Unit){
	rongCloudThreadPool.execute(object :RongCloudRunnable(taskDesc, params){
		override fun run() {
			handle()
		}
	})
}

//具體使用
taskExecute("發(fā)送消息", mapOf(
	"from_id" to fromId,
	"target_ids" to targetIds,
	"data" to data,
	"is_include_sender" to isIncludeSender
)){
	sendMessage(BatchSendData(fromId, targetIds, data, isIncludeSender))
}		

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 詳解MongoDB范圍片鍵和哈希片鍵

    詳解MongoDB范圍片鍵和哈希片鍵

    這篇文章主要介紹了MongoDB范圍片鍵和哈希片鍵的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)使用MongoDB,感興趣的朋友可以了解下
    2021-03-03
  • MongoDB的安裝及配置文件選項全解

    MongoDB的安裝及配置文件選項全解

    本文收錄了MongoDB的安裝及配置文件選項全解,介紹了MongoDB安裝的方法以及環(huán)境下的一些重要文件,還有最重要的是詳細(xì)地羅列了配置文件中的選項含義和參數(shù),需要的朋友可以參考下
    2016-07-07
  • mongodb中隨機獲取1條記錄的實現(xiàn)方法

    mongodb中隨機獲取1條記錄的實現(xiàn)方法

    這篇文章運用實例給大家演示了如何在mongodb中隨機獲取1條記錄,文中介紹的很詳細(xì),有需要的朋友們可以參考借鑒。下面來一起看看吧。
    2016-09-09
  • MongoDB數(shù)據(jù)庫條件查詢技巧總結(jié)

    MongoDB數(shù)據(jù)庫條件查詢技巧總結(jié)

    查詢是數(shù)據(jù)庫的基本操作之一,下面這篇文章主要給大家介紹了關(guān)于MongoDB數(shù)據(jù)庫條件查詢技巧的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-06-06
  • MongoDB windows解壓縮版安裝教程詳解

    MongoDB windows解壓縮版安裝教程詳解

    這篇文章主要介紹了MongoDB windows解壓縮版安裝教程詳解的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2016-09-09
  • MongoDB中數(shù)據(jù)的替換方法實現(xiàn)類Replace()函數(shù)功能詳解

    MongoDB中數(shù)據(jù)的替換方法實現(xiàn)類Replace()函數(shù)功能詳解

    這篇文章主要介紹了MongoDB中數(shù)據(jù)的替換方法實現(xiàn)類Replace()函數(shù)功能詳解,需要的朋友可以參考下
    2020-02-02
  • MongoDB日志切割的三種方式總結(jié)

    MongoDB日志切割的三種方式總結(jié)

    mongo默認(rèn)是沒有進(jìn)行日志分割的,所有的日志持續(xù)寫到一個文件中,缺點是很明顯的,日志文件會越來越大,下面這篇文章主要給大家介紹了關(guān)于MongoDB日志切割的三種方式,需要的朋友可以參考下
    2021-09-09
  • MongoDB使用小結(jié) 一些常用操作分享

    MongoDB使用小結(jié) 一些常用操作分享

    本文整理了一年多以來我常用的MongoDB操作,涉及mongo-shell、pymongo,既有運維層面也有應(yīng)用層面,內(nèi)容有淺有深,這也就是我從零到熟練的歷程,需要的朋友可以參考下
    2017-03-03
  • MongoDB添加仲裁節(jié)點報錯:replica set IDs do not match的解決方法

    MongoDB添加仲裁節(jié)點報錯:replica set IDs do not match的解決方法

    這篇文章主要給大家介紹了關(guān)于MongoDB添加仲裁節(jié)點報錯:replica set IDs do not match的解決方法,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-11-11
  • CentOS7.2 安裝 MongoDB 3.4的教程

    CentOS7.2 安裝 MongoDB 3.4的教程

    這篇文章主要介紹了CentOS7.2 安裝 MongoDB 3.4的方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-05-05

最新評論