在我們開(kāi)始之前,先介紹一下我是誰(shuí)以及為什么它在這種情況下很重要。我是筆記本制造公司的軟件開(kāi)發(fā)人員,過(guò)去兩年在這里工作。在我現(xiàn)在所在的團(tuán)隊(duì)中,我是唯一的開(kāi)發(fā)人員,負(fù)責(zé)使用 Go 和 Grafana 創(chuàng)建、監(jiān)控和維護(hù)數(shù)據(jù)管道、自動(dòng)化以及監(jiān)控系統(tǒng)。
我還要補(bǔ)充一點(diǎn),前一年我是實(shí)習(xí)生。而且我是自學(xué)的。
好吧,但是為什么這很重要呢?
嗯,當(dāng)我遇到自己無(wú)法解決的障礙或問(wèn)題時(shí),我沒(méi)有高級(jí)開(kāi)發(fā)人員,也沒(méi)有任何形式的內(nèi)部指導(dǎo)可以指導(dǎo)我,這就是我寫(xiě)作的主要原因。我認(rèn)為這是一件有趣的事情并且想要分享。它不會(huì)是一個(gè)令人驚嘆的軟件,一個(gè)突破或類(lèi)似的東西,但它提醒我們從頭開(kāi)始構(gòu)建東西是可能的。您不需要成為百萬(wàn)分之一的 10 倍開(kāi)發(fā)人員或類(lèi)似的人。
P.S:順便說(shuō)一句,我使用 neovim。
一百萬(wàn)行
這個(gè)數(shù)字可能看起來(lái)有些夸張或類(lèi)似的東西,盡管我希望如此,但事實(shí)并非如此。看,在制造環(huán)境中工作時(shí),有時(shí)我們不會(huì)考慮需要多少個(gè)項(xiàng)目,以及當(dāng)您必須跟蹤每個(gè)組件的許多制造隊(duì)列的每個(gè)點(diǎn)時(shí)它會(huì)生成多少數(shù)據(jù)。
無(wú)論是一個(gè)小螺絲,還是上一代 CPU,都必須被跟蹤,帶有時(shí)間戳!
所以,是的,生成的數(shù)據(jù)量是正確的,而這只是開(kāi)始。以下是使問(wèn)題變得很酷的其他酷點(diǎn)(在我看來(lái)):
- 該數(shù)據(jù)的來(lái)源沒(méi)有經(jīng)過(guò)壓縮或類(lèi)似的處理,因此天氣好的時(shí)候平均請(qǐng)求時(shí)間接近 2 到 3 分鐘。如果源代碼滯后,它可能會(huì)超過(guò) 5 分鐘(這是一個(gè)比我更舊的 java 系統(tǒng)。)。
- 關(guān)于格式,我可以選擇處理 XML 響應(yīng)或 CSV 響應(yīng),當(dāng)然我選擇了 CSV 路線。我不是受虐狂。
- 并且需要選擇數(shù)據(jù)獲取的間隔,至少一小時(shí)(不,我不知道為什么,是的,我嘗試過(guò)較小的間隔)。
- 源沒(méi)有延遲加載或緩存系統(tǒng),因此兩個(gè)相同的請(qǐng)求將生成相同的響應(yīng),但時(shí)間不同。
- 最后,讓事情變得更有趣的是,它是 Microsoft 的產(chǎn)品,稱(chēng)為 SQL Server Reporting Services,但也有一些晦澀的警告。哦,而且我需要使用的數(shù)據(jù)庫(kù)是 MSSQL,這很痛苦。
這就是整個(gè)上下文,現(xiàn)在有趣的部分開(kāi)始。
第一次迭代——DMP
我喜歡使用軟件的方式非常簡(jiǎn)單。讓它變得丑陋且?guī)缀醪黄鹱饔?->保持丑陋并改進(jìn)功能 ->仍然丑陋,但優(yōu)化得更好 ->漂亮、優(yōu)化且工作 ->然后你的經(jīng)理說(shuō)你所做的工作太好了,源無(wú)法處理它,導(dǎo)致中斷。臥槽。
無(wú)論如何,DMP 代表 Dumb Mode Protocol,只要讓它以最愚蠢的方式工作即可,這意味著勉強(qiáng)可以工作。
所以,對(duì)于第一輪,我的目標(biāo)很簡(jiǎn)單,進(jìn)行身份驗(yàn)證,發(fā)出請(qǐng)求,解析數(shù)據(jù),發(fā)送到數(shù)據(jù)庫(kù)。很簡(jiǎn)單,對(duì)吧?而且,在紙面上,它是,直到我發(fā)現(xiàn)我必須使用的身份驗(yàn)證和授權(quán)方法是 ntlmssp,這是一種我不知道存在的質(zhì)詢(xún)響應(yīng)身份驗(yàn)證方法。事實(shí)上,我必須進(jìn)入舊版 .NET 4 代碼才能找到它。我沒(méi)學(xué)過(guò)C#。
在瀏覽了比我年長(zhǎng)的遺留代碼之后,我在嘗試?yán)斫馑鼤r(shí)遇到了困難,因?yàn)槌鲇谀撤N原因,編寫(xiě)它的人認(rèn)為將其隱藏到 5 層抽象、構(gòu)造函數(shù)和 OOP 中是一個(gè)好主意。不有趣,令人羞愧的經(jīng)歷。然后我成功了。一小時(shí)后,我的用戶被屏蔽,因?yàn)轱@然該來(lái)源有速率限制。但沒(méi)有緩存或延遲加載。
好吧,在這一切之后,我只需要傳遞查詢(xún)參數(shù)并獲取數(shù)據(jù),不再需要源的復(fù)雜性。好吧,我們來(lái)查一下查詢(xún)參數(shù)的文檔。
...
此時(shí),考慮到所有因素,您可能猜對(duì)了。文檔?這是只有硅谷才有的異國(guó)美食嗎?
不管怎樣,在絞盡腦汁之后,我決定檢查一下這個(gè) SQL Server Reporting Services 的站點(diǎn)/界面,令我高興的是,然后是仇恨,它有一種方法來(lái)了解過(guò)濾器及其值。
只知道頁(yè)面中的(“全部”)過(guò)濾器,例如選擇所有生產(chǎn)線,只是選中所有框的抽象。好吧,讓我們復(fù)制過(guò)濾器并將其放入查詢(xún)字符串中,對(duì)其進(jìn)行編碼,然后開(kāi)心吧!
成功了!或者說(shuō)我是這么想的。
還記得我說(shuō)過(guò)我的用戶被屏蔽了嗎?好吧,看起來(lái)?yè)碛袌?zhí)行此類(lèi)任務(wù)的管理員權(quán)限,并由 C-Suite 授權(quán)執(zhí)行此操作(事實(shí)上,這是他們要求的),但不足以允許我執(zhí)行多個(gè)請(qǐng)求。我的用戶被屏蔽了,但是,對(duì)于我的經(jīng)理來(lái)說(shuō),這就像說(shuō)“什么也沒(méi)發(fā)生”。幸運(yùn)的是,我很快就解封了。
與此同時(shí),我決定按照我處理該項(xiàng)目其余部分的方式進(jìn)行工作。此時(shí)我已經(jīng)有了一個(gè)樣本,它符合帖子的標(biāo)題??吹竭@七位數(shù)字讓我懷疑自己是否能夠做到,因?yàn)槲覍?duì)這個(gè)數(shù)據(jù)量的經(jīng)驗(yàn)為零。
為了將我的想法付諸實(shí)踐,我希望進(jìn)入 exlidraw 并設(shè)計(jì)出我想做的事情。我知道工作池的概念,但之前沒(méi)有實(shí)現(xiàn)過(guò)。因此,我閱讀了相關(guān)內(nèi)容,看到了一些實(shí)現(xiàn),并詢(xún)問(wèn)了一位對(duì)我?guī)椭艽蟮呐笥?。他是我沒(méi)有的前輩。
用偽代碼寫(xiě)出來(lái)后,我心里想:
“哇,這非常簡(jiǎn)潔,所有這些通道和 goroutine 肯定不會(huì)產(chǎn)生內(nèi)存泄漏,對(duì)吧?”
好吧,可能不是那些確切的詞,但大致意思是這樣的。在完成第一次迭代、設(shè)法執(zhí)行請(qǐng)求(不會(huì)被阻止)并將其加載到內(nèi)存中之后,我應(yīng)用了工作池概念。
然后我就遇到了 BSOD。有趣的是,就在 CrowdStrike 罷工的同一天,我當(dāng)然不認(rèn)為我造成了工廠的重大停電。
另外,是的,我必須使用 Windows 來(lái)工作,但不用擔(dān)心!我使用 WSL2。
在檢查了我的第一次堆棧溢出的大量堆棧跟蹤后,我發(fā)現(xiàn)了這個(gè)錯(cuò)誤。在將數(shù)據(jù)發(fā)送到消費(fèi)者通道時(shí),我沒(méi)有考慮到某些數(shù)據(jù)可能會(huì)出錯(cuò),主要是由于違反了主鍵,或者僅僅是因?yàn)?,也許,我沒(méi)有正確處理錯(cuò)誤。
經(jīng)驗(yàn)教訓(xùn),使用錯(cuò)誤通道來(lái)避免重大問(wèn)題。并處理您的錯(cuò)誤,無(wú)論是通過(guò)簡(jiǎn)單的字符串檢查(丑陋,但有效),或者只是頂級(jí)記錄它,然后高興。由于我遇到的錯(cuò)誤并不嚴(yán)重,所以我可以繼續(xù)。
第二次迭代。內(nèi)存泄漏。
這一步產(chǎn)生的內(nèi)存泄漏量讓我以為我在做 C。但這只是主要的技能問(wèn)題。
不管怎樣,你可能會(huì)想:
“你是如何在如此簡(jiǎn)單的過(guò)程中造成內(nèi)存泄漏的?”
很簡(jiǎn)單,我正在學(xué)習(xí)和嘗試。
這一步中的主要問(wèn)題是我天真地沒(méi)有確保數(shù)據(jù)被正確插入,并且我得到的主鍵違規(guī)量違反了我的記憶。這是我知道如何解決的問(wèn)題,讓我們緩存數(shù)據(jù)吧!
等等,考慮到每一行都是唯一的,如何為每一行創(chuàng)建一個(gè)唯一標(biāo)識(shí)符?
現(xiàn)在,這是很多人會(huì)嘲笑我的部分,因?yàn)?,公平地說(shuō),這是最讓我崩潰的部分。我只是簡(jiǎn)單地加入當(dāng)前行的信息并將其解析為哈希函數(shù),該哈希就成為我在映射中的鍵。
“為什么不使用 Redis?” - 你可能會(huì)問(wèn)自己。
很簡(jiǎn)單,官僚主義。這不是一家小公司。事實(shí)上,你們中的許多人可能正在使用他們制造的筆記本電腦。請(qǐng)求一個(gè) Redis 實(shí)例這個(gè)簡(jiǎn)單的行為至少需要三個(gè)工作日、四次會(huì)議、對(duì)官僚之神的犧牲,以及一份解釋原因和方式的完整文檔。
所以,是的,讓我們使用一個(gè)簡(jiǎn)單的哈希圖并在第一次運(yùn)行之前對(duì)其進(jìn)行預(yù)初始化。它會(huì)增加整體加載時(shí)間,但會(huì)比請(qǐng)求更快。
通過(guò)這樣做,整個(gè)過(guò)程得到了改善,就像有了一個(gè)新電機(jī)一樣,memleaks 停止了,批次不會(huì)每次都失敗,錯(cuò)誤和斷開(kāi)連接的數(shù)量也減少了,非常好,對(duì)吧?對(duì)嗎?
現(xiàn)在,您知道有些事情變得混亂了。
第三次迭代。生活本來(lái)可以很美好。
我沒(méi)有考慮到的一點(diǎn)是,通過(guò)批量插入,可以驗(yàn)證數(shù)據(jù)。這是流程的簡(jiǎn)單表示。
獲取數(shù)據(jù)->檢查hashmap中是否存在數(shù)據(jù)的hash ->批量&插入
這有什么問(wèn)題嗎?那么,如果我的批次中的單個(gè)插入失敗,會(huì)發(fā)生什么情況,它會(huì)在沒(méi)有條目的情況下重試嗎?如果是這樣,我可以重試多少次而不會(huì)使系統(tǒng)混亂并失去工作池實(shí)現(xiàn)的優(yōu)勢(shì)?
只有一種方法可以找出答案!我們來(lái)檢查一下。
我要補(bǔ)充的一點(diǎn)是,該源返回了超過(guò) 25 列,因此我必須小心每批插入的數(shù)據(jù)量,以免超過(guò) 2100 個(gè)參數(shù),這是 MSSQL 的限制。
此時(shí),我已經(jīng)在 Docker 容器中運(yùn)行一些東西,該容器模仿資源有限的生產(chǎn)空間。為了添加上下文,該進(jìn)程使用 1GB RAM 和大約 0.5CPU 運(yùn)行。我本可以分配更多的資源,但這只是強(qiáng)行逼我出路。
通過(guò)在容器內(nèi)運(yùn)行這個(gè)新的迭代,添加一些時(shí)間戳并將其記錄到文件中以供以后分析。我發(fā)現(xiàn)由于重試次數(shù)增加了大約 5 分鐘。這是行不通的,刪除“臟”條目不是一個(gè)選項(xiàng)。
第四次迭代。生活是美好的。
為了解決這個(gè)問(wèn)題,我增加了工人的數(shù)量。我使用了大約 50 名工作人員,并且由于 ThePrimagen 頂級(jí)貨架上的不和諧用戶的隨機(jī)猜測(cè),我將其增加到 1000 名工作人員,并確保每個(gè)工作人員都驗(yàn)證交易中的每個(gè)條目。萬(wàn)一交易失敗,我直接回滾。
通過(guò)這樣做,我能夠解決核心問(wèn)題并總體上提高該過(guò)程的整體速度?,F(xiàn)在是時(shí)候?qū)⑵浞湃氘a(chǎn)品中并對(duì)其進(jìn)行監(jiān)控了,因?yàn)?,你知道,產(chǎn)品妖精可能會(huì)弄亂你的軟件。 (它們也被稱(chēng)為技能問(wèn)題,但這個(gè)名稱(chēng)是禁止的。)
知道減少該系統(tǒng)的獲取間隔,要求使其接近實(shí)時(shí)(這意味著足夠快,讓他們不會(huì)注意到延遲),我創(chuàng)建了一個(gè)新容器,這一次具有更強(qiáng)健的功能檢查是否能夠承受負(fù)載,并將間隔設(shè)置為 3 分鐘??紤]到平均獲取時(shí)間,這意味著我可能會(huì)有一些重疊,但我真的很想看看會(huì)發(fā)生什么。
我讓它運(yùn)行了一夜,記錄結(jié)果以便稍后查看,令我驚訝的是,在工作日結(jié)束之前,我接到了經(jīng)理的電話。請(qǐng)注意,他不是技術(shù)人員或類(lèi)似的人。
“嘿,‘我們’部署了一些與[我無(wú)法透露的系統(tǒng)名稱(chēng)]交互的東西嗎?”
“是的,我按照要求實(shí)時(shí)部署了數(shù)據(jù)獲取系統(tǒng)。為什么?”
“你能,嗯,停下來(lái)嗎?它導(dǎo)致了停電,我們無(wú)法在這里工作?!盻
這,gadies and lentleman,完全是另一個(gè)級(jí)別的破壞性刺激。毫不夸張地說(shuō),我讓 20 多條生產(chǎn)線停止了一分鐘左右。無(wú)論如何,我停止了系統(tǒng),一切都恢復(fù)正常。
第二天,我被要求將讀取之間的間隔從 3 分鐘增加到 30 分鐘,好吧,我想沒(méi)問(wèn)題。我不會(huì)說(shuō)謊,我有點(diǎn)難過(guò),因?yàn)槲覠o(wú)法看到它以最大速度運(yùn)行,但是嘿,至少我讓它工作了。
使用這個(gè)新系統(tǒng),使用該數(shù)據(jù)的報(bào)告的平均更新時(shí)間減少到 8~10 秒,這導(dǎo)致經(jīng)理以??相同的方式請(qǐng)求更多相同來(lái)源的報(bào)告。良好的工作會(huì)得到更多工作的回報(bào)!
注意事項(xiàng)
這是一次有趣的經(jīng)歷,主要是因?yàn)樗屛艺嬲庾R(shí)到 Go 的強(qiáng)大之處。使用比谷歌瀏覽器更少的內(nèi)存,比微軟應(yīng)用程序更少的存儲(chǔ)空間,比 Windows 計(jì)算器更少的 CPU 功率,我能夠改進(jìn)一個(gè)舊的進(jìn)程,這個(gè)進(jìn)程實(shí)際上是暴力強(qiáng)制通過(guò)的(它在插入之前實(shí)際上檢查了數(shù)據(jù)庫(kù)中的每一行。我不知道)不知道前一個(gè)人怎么認(rèn)為這是一個(gè)好主意。)。真的很有趣。
無(wú)論如何,請(qǐng)隨意分享您在整個(gè)過(guò)程中的想法,您會(huì)如何處理以及您會(huì)采取哪些不同的做法。由于我沒(méi)有開(kāi)發(fā)同事,我想了解更多對(duì)此的看法。
以上是我如何處理每個(gè)請(qǐng)求的條目 - 使用 Go!的詳細(xì)內(nèi)容。更多信息請(qǐng)關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

熱AI工具

Undress AI Tool
免費(fèi)脫衣服圖片

Undresser.AI Undress
人工智能驅(qū)動(dòng)的應(yīng)用程序,用于創(chuàng)建逼真的裸體照片

AI Clothes Remover
用于從照片中去除衣服的在線人工智能工具。

Clothoff.io
AI脫衣機(jī)

Video Face Swap
使用我們完全免費(fèi)的人工智能換臉工具輕松在任何視頻中換臉!

熱門(mén)文章

熱工具

記事本++7.3.1
好用且免費(fèi)的代碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
功能強(qiáng)大的PHP集成開(kāi)發(fā)環(huán)境

Dreamweaver CS6
視覺(jué)化網(wǎng)頁(yè)開(kāi)發(fā)工具

SublimeText3 Mac版
神級(jí)代碼編輯軟件(SublimeText3)

Golang主要用于后端開(kāi)發(fā),但也能在前端領(lǐng)域間接發(fā)揮作用。其設(shè)計(jì)目標(biāo)聚焦高性能、并發(fā)處理和系統(tǒng)級(jí)編程,適合構(gòu)建API服務(wù)器、微服務(wù)、分布式系統(tǒng)、數(shù)據(jù)庫(kù)操作及CLI工具等后端應(yīng)用。雖然Golang不是網(wǎng)頁(yè)前端的主流語(yǔ)言,但可通過(guò)GopherJS編譯成JavaScript、通過(guò)TinyGo運(yùn)行于WebAssembly,或搭配模板引擎生成HTML頁(yè)面來(lái)參與前端開(kāi)發(fā)。然而,現(xiàn)代前端開(kāi)發(fā)仍需依賴(lài)JavaScript/TypeScript及其生態(tài)。因此,Golang更適合以高性能后端為核心的技術(shù)棧選擇。

要構(gòu)建一個(gè)GraphQLAPI在Go語(yǔ)言中,推薦使用gqlgen庫(kù)以提高開(kāi)發(fā)效率。1.首先選擇合適的庫(kù),如gqlgen,它支持根據(jù)schema自動(dòng)生成代碼;2.接著定義GraphQLschema,描述API的結(jié)構(gòu)和查詢(xún)?nèi)肟冢缍xPost類(lèi)型和查詢(xún)方法;3.然后初始化項(xiàng)目并生成基礎(chǔ)代碼,實(shí)現(xiàn)resolver中的業(yè)務(wù)邏輯;4.最后將GraphQLhandler接入HTTPserver,通過(guò)內(nèi)置Playground測(cè)試API。注意事項(xiàng)包括字段命名規(guī)范、錯(cuò)誤處理、性能優(yōu)化及安全設(shè)置等,確保項(xiàng)目可維護(hù)性

安裝Go的關(guān)鍵在于選擇正確版本、配置環(huán)境變量并驗(yàn)證安裝。1.前往官網(wǎng)下載對(duì)應(yīng)系統(tǒng)的安裝包,Windows使用.msi文件,macOS使用.pkg文件,Linux使用.tar.gz文件并解壓至/usr/local目錄;2.配置環(huán)境變量,在Linux/macOS中編輯~/.bashrc或~/.zshrc添加PATH和GOPATH,Windows則在系統(tǒng)屬性中設(shè)置PATH為Go的安裝路徑;3.使用goversion命令驗(yàn)證安裝,并運(yùn)行測(cè)試程序hello.go確認(rèn)編譯執(zhí)行正常。整個(gè)流程中PATH設(shè)置和環(huán)

sync.WaitGroup用于等待一組goroutine完成任務(wù),其核心是通過(guò)Add、Done、Wait三個(gè)方法協(xié)同工作。1.Add(n)設(shè)置需等待的goroutine數(shù)量;2.Done()在每個(gè)goroutine結(jié)束時(shí)調(diào)用,計(jì)數(shù)減一;3.Wait()阻塞主協(xié)程直到所有任務(wù)完成。使用時(shí)需注意:Add應(yīng)在goroutine外調(diào)用、避免重復(fù)Wait、務(wù)必確保Done被調(diào)用,推薦配合defer使用。常見(jiàn)于并發(fā)抓取網(wǎng)頁(yè)、批量數(shù)據(jù)處理等場(chǎng)景,能有效控制并發(fā)流程。

使用Go的embed包可以方便地將靜態(tài)資源嵌入二進(jìn)制,適合Web服務(wù)打包HTML、CSS、圖片等文件。1.聲明嵌入資源需在變量前加//go:embed注釋?zhuān)缜度雴蝹€(gè)文件hello.txt;2.可嵌入整個(gè)目錄如static/*,通過(guò)embed.FS實(shí)現(xiàn)多文件打包;3.開(kāi)發(fā)時(shí)建議通過(guò)buildtag或環(huán)境變量切換磁盤(pán)加載模式以提高效率;4.注意路徑正確性、文件大小限制及嵌入資源的只讀特性。合理使用embed能簡(jiǎn)化部署并優(yōu)化項(xiàng)目結(jié)構(gòu)。

音視頻處理的核心在于理解基本流程與優(yōu)化方法。1.其基本流程包括采集、編碼、傳輸、解碼和播放,每個(gè)環(huán)節(jié)均有技術(shù)難點(diǎn);2.常見(jiàn)問(wèn)題如音畫(huà)不同步、卡頓延遲、聲音噪音、畫(huà)面模糊等,可通過(guò)同步調(diào)整、編碼優(yōu)化、降噪模塊、參數(shù)調(diào)節(jié)等方式解決;3.推薦使用FFmpeg、OpenCV、WebRTC、GStreamer等工具實(shí)現(xiàn)功能;4.性能管理方面應(yīng)注重硬件加速、合理設(shè)置分辨率幀率、控制并發(fā)及內(nèi)存泄漏問(wèn)題。掌握這些關(guān)鍵點(diǎn)有助于提升開(kāi)發(fā)效率和用戶體驗(yàn)。

搭建一個(gè)用Go編寫(xiě)的Web服務(wù)器并不難,核心在于利用net/http包實(shí)現(xiàn)基礎(chǔ)服務(wù)。1.使用net/http啟動(dòng)最簡(jiǎn)服務(wù)器:通過(guò)幾行代碼注冊(cè)處理函數(shù)并監(jiān)聽(tīng)端口;2.路由管理:使用ServeMux組織多個(gè)接口路徑,便于結(jié)構(gòu)化管理;3.常見(jiàn)做法:按功能模塊分組路由,并可用第三方庫(kù)支持復(fù)雜匹配;4.靜態(tài)文件服務(wù):通過(guò)http.FileServer提供HTML、CSS和JS文件;5.性能與安全:?jiǎn)⒂肏TTPS、限制請(qǐng)求體大小、設(shè)置超時(shí)時(shí)間以提升安全性與性能。掌握這些要點(diǎn)后,擴(kuò)展功能將更加容易。

select加default的作用是讓select在沒(méi)有其他分支就緒時(shí)執(zhí)行默認(rèn)行為,避免程序阻塞。1.非阻塞地從channel接收數(shù)據(jù)時(shí),若channel為空,會(huì)直接進(jìn)入default分支;2.結(jié)合time.After或ticker定時(shí)嘗試發(fā)送數(shù)據(jù),若channel滿則不阻塞而跳過(guò);3.防止死鎖,在不確定channel是否被關(guān)閉時(shí)避免程序卡??;使用時(shí)需注意default分支會(huì)立即執(zhí)行,不能濫用,且default與case互斥,不會(huì)同時(shí)執(zhí)行。
