億級數(shù)據(jù)毫秒級響應(yīng)?
作為一名深陷在增刪改查泥潭中練習(xí)時(shí)長三年的夾娃練習(xí)生,偶爾會因?yàn)闆]有開發(fā)任務(wù)不知道周報(bào)寫什么而苦惱。
正愁這周寫啥呢,組長過來交代了個(gè)跟進(jìn)第三方公司性能測試報(bào)告的工作,我一尋思這活不最好干了嗎,正愁不知道周報(bào)咋寫呢,又能提現(xiàn)工作量又不累,本以為輕松拿捏的結(jié)果差點(diǎn)讓老弟翻車。
由于我們組主要做數(shù)倉管理這塊的業(yè)務(wù),這次的性能測試上有一些數(shù)據(jù)服務(wù)并發(fā)相關(guān)的指標(biāo)需要后端配合測試,讓一天搞定,我尋思半天搞完還能去掘金狠狠的摸半天魚,豈不美哉。拿到測試指標(biāo)之后直接手心出汗了。
啥意思,億級數(shù)據(jù)查詢毫秒級響應(yīng)還要100并發(fā)持續(xù)5分鐘,家人們誰懂啊。。。關(guān)鍵我們負(fù)責(zé)的業(yè)務(wù)是tob的場景啊,哪有這么高并發(fā)。數(shù)據(jù)查詢還在舊的python服務(wù)里,給提供的測試環(huán)境全是單機(jī)服務(wù)。
加緩存
既然是做性能測試那管數(shù)據(jù)對不對什么事,給你返回不就行了,在服務(wù)加個(gè)臨時(shí)緩存,先把數(shù)據(jù)查詢的耗時(shí)降下來再考慮其他的。
身為一個(gè)Javaboy,寫python的代碼10行代碼得5行問chatGPT,好在是用redis加上了緩存。用jmeter淺試一下,
效果上看加上緩存查詢速度的確變快了,但是平均耗時(shí)離預(yù)期還是差距較大,最大耗時(shí)要接近5s多,看來只加緩存是扛不住,耗時(shí)應(yīng)該是服務(wù)扛不住并發(fā),線程阻塞了。。。
nginx橫向擴(kuò)展
不得不吐槽下,服務(wù)真垃圾吶,時(shí)間緊任務(wù)重,趕緊想辦法,直接把問題當(dāng)成面試題,腦袋里直接開始翻閱八股文,什么高內(nèi)聚、低耦合、高吞吐、月薪3000包吃住,第一個(gè)沖出來的想法就是擴(kuò)展服務(wù)做負(fù)載。
怎么負(fù)載呢,部署三份數(shù)據(jù)查詢服務(wù),nginx做upstream負(fù)載,效果應(yīng)該頂?shù)米?,開搞開搞。結(jié)果python代碼不太熟,多進(jìn)程的方式啟動torando就是報(bào)錯(cuò)。整的我滿頭大汗,下午就得給人提供接口了這咋整啊,不行問問組長去吧。
結(jié)果組長直接說浪費(fèi)那時(shí)間干啥啊,反正都是做做樣子,在nginx里寫個(gè)lua腳本,讀一下本地文件返回?cái)?shù)據(jù)不就可以了,第三方又不會管你咋實(shí)現(xiàn)的...都得都懂。
lua腳本
我仔細(xì)一想也是,整那么緊張干啥,先實(shí)現(xiàn)了再說,由于環(huán)境里的nginx已經(jīng)安裝了lua插件可以直接使用。
先提前把請求的返回?cái)?shù)據(jù)保存到txt里,然后用lua實(shí)現(xiàn)一個(gè)讀取本地文件的方法,請求打過來之后判斷body里的數(shù)據(jù)是否是指定的數(shù)據(jù)id,如果是直接讀取數(shù)據(jù)返回。
nginx和lua的性能別說100并發(fā)了1w并發(fā)也輕松拿捏。
lua讀取本地文件內(nèi)容
lua復(fù)制代碼 ? ?function getFile(file_name) ?? ? ? ?local f = assert(io.open(file_name, 'r')) ?? ? ? ?local string = f:read("*all") ?? ? ? ?f:close() ?? ? ? ?return string ?? ?end ?
找到nginx配置對應(yīng)的請求url,添加access_by_lua_block代碼塊,將getFile方法聲明在這里,并且寫一下匹配邏輯,如果body中包含file_id,直接調(diào)用getFile方法返回,不包含還是走正常的查詢邏輯。
php復(fù)制代碼 ?? ?location = /api/data/preview { ?? ? ? ? ? ?set $upstream 'fe_full_long'; ?? ? ? ? ? ?access_by_lua_block { ?? ? ? ? ? ? ? ? ? ?function getFile(file_name) ?? ? ? ? ? ? ? ? ? ? ? ? ? ?local f = assert(io.open(file_name, 'r')) ?? ? ? ? ? ? ? ? ? ? ? ? ? ?local string = f:read("*all") ?? ? ? ? ? ? ? ? ? ? ? ? ? ?f:close() ?? ? ? ? ? ? ? ? ? ? ? ? ? ?return string ?? ? ? ? ? ? ? ? ? ?end ?? ? ? ? ? ? ? ? ? ?ngx.req.read_body() ?? ? ? ? ? ? ? ? ? ?local data = ngx.req.get_body_data() ?? ? ? ? ? ? ? ? ? ?if ngx.re.match(ngx.var.request_body, "file_id") then ?? ? ? ? ? ? ? ? ? ? ? ? ? ?ngx.say(getFile(string.format("/nginx/conf/conf.d/a.txt", f))); ?? ? ? ? ? ? ? ? ? ? ? ? ? ?return ?? ? ? ? ? ? ? ? ? ?end ?? ? ? ? ? ?} ?? ? ? ? ? ?proxy_pass http://$upstream; ?? ? ? ? ? ?proxy_set_header Host $host:$server_port; ?? ? ? ? ? ?proxy_set_header X-Real-IP $remote_addr; ?? ? ? ? ? ?proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; ?? ?}
保存nginx -t,先檢查后重啟,防止手心冒汗,簡單測了一下性能直接起飛,直接提供給第三方測試了。
億級數(shù)據(jù)毫秒級響應(yīng)?
晚上下班前發(fā)過來了初版的測試報(bào)告,組長一看,直接給我閱起兵來了,"你這也太快了,摟著點(diǎn)啊,管家指標(biāo)還一樣,快改改"。
我一看好家伙,億級數(shù)據(jù)28毫米返回,雀氏有點(diǎn)尷尬了。。。。趕緊改改。在lua腳本里sleep隨機(jī)幾百毫秒就真實(shí)了。
lua復(fù)制代碼 -- 定義睡眠函數(shù) ? local function sleep(ms) ? ngx.sleep(ms / 1000) ? end ? ? -- 隨機(jī)睡眠一段時(shí)間(1毫秒到100毫秒之間) ? math.randomseed(ngx.now()) ? local sleepTime = math.random(1, 100) ? sleep(sleepTime)
重啟下nginx重測,結(jié)果很合理,必須得在周報(bào)濃墨重彩一波。。。