運(yùn)維不背鍋!持續(xù)兩年數(shù)據(jù)庫(kù)零故障的運(yùn)維優(yōu)化之道
大家好,我是來自平安科技數(shù)據(jù)庫(kù)技術(shù)部運(yùn)維團(tuán)隊(duì)的劉書安,從14年開始,配合平安集團(tuán)的互聯(lián)網(wǎng)金融轉(zhuǎn)型,我們運(yùn)維的數(shù)據(jù)庫(kù)也從單純的Oracle數(shù)據(jù)庫(kù)轉(zhuǎn)向到了多種數(shù)據(jù)庫(kù)的運(yùn)維,當(dāng)前管理的各類數(shù)據(jù)庫(kù)的實(shí)例已經(jīng)超過了一萬個(gè)。在這種情況下,我們連續(xù)兩年保持了數(shù)據(jù)庫(kù)零故障的狀態(tài)。
事實(shí)上在之前,運(yùn)維團(tuán)隊(duì)也是天天忙著應(yīng)付各種異常,長(zhǎng)久處于高壓狀態(tài)下。之后經(jīng)過我們團(tuán)隊(duì)一系列的優(yōu)化和改造,目前系統(tǒng)已穩(wěn)定很多。這期間也確實(shí)發(fā)生了很多事情。接下來就跟大家簡(jiǎn)單介紹一下我們這兩年對(duì)一些運(yùn)維問題的分析和團(tuán)隊(duì)管理的方法,拋磚引玉一下。
一、問題解決
首先我們從以下這張圖說起:
這個(gè)是扁鵲向魏王介紹他們?nèi)值艿尼t(yī)術(shù):扁鵲自己是在病人病入膏肓?xí)r用虎狼之藥將對(duì)方救活;扁鵲的二哥是在別人生小病時(shí)將人治愈;而扁鵲的大哥則是在病情未發(fā)時(shí)鏟除病因、避免生病。
在扁鵲看來,三個(gè)人的醫(yī)術(shù)排序應(yīng)該是:大哥>二哥>扁鵲,但在世人眼里卻是:扁鵲>二哥>大哥。
我比較認(rèn)同扁鵲的觀點(diǎn),因?yàn)槲乙恢倍加X得DB的運(yùn)維人員不應(yīng)該只是背鍋俠,而是應(yīng)該把自己當(dāng)成醫(yī)生來對(duì)待問題,不只是關(guān)注問題的解決,更需要多關(guān)注避免問題的發(fā)生。
我們?cè)跀?shù)據(jù)庫(kù)異常時(shí)去解決問題,別人可能會(huì)認(rèn)為我們是高手,能把問題解決好、事情處理掉。但實(shí)際上這時(shí)的運(yùn)維已經(jīng)是一個(gè)被動(dòng)式的處理,即便我們用了最快的手段去解決,故障已經(jīng)發(fā)生了,可能還造成了比較嚴(yán)重的影響。
如果我們能提前發(fā)現(xiàn)這些問題并解決掉,就能避免很多故障和影響的發(fā)生。因此在我看來,運(yùn)維相對(duì)高明的手段應(yīng)該是:在做架構(gòu)或設(shè)計(jì)時(shí)就把能想到的問題預(yù)先解決掉,確保系統(tǒng)的可拓展性和高可用性。運(yùn)維也應(yīng)該多從架構(gòu)的角度去考慮問題,并將這些問題提前解決好,而非被動(dòng)地等待問題發(fā)生后才去解決。
接下來和大家介紹我們團(tuán)隊(duì)解決的三個(gè)案例,以及之后我們通過什么方式避免問題的發(fā)生:
案例一
這是我們?cè)?016年解決的案例,版本是11.2.0.4 的Oracle數(shù)據(jù)庫(kù),這種數(shù)據(jù)庫(kù)使用SPM固化TOP SQL的執(zhí)行計(jì)劃,確保系統(tǒng)的穩(wěn)定。
當(dāng)時(shí)異常的問題是,幾乎每次發(fā)完大的版本后,已有的功能都會(huì)多少受到影響,有一些語(yǔ)句的執(zhí)行計(jì)劃會(huì)發(fā)生異常。
我們發(fā)現(xiàn),絕大多數(shù)語(yǔ)句都和這個(gè)語(yǔ)句是類似的,中間有一個(gè)SKIPSCAN(跳躍式掃描),很明顯可以看出它是一個(gè)輸入時(shí)間(對(duì)著用戶的),有一個(gè)范圍查詢。所以我們當(dāng)時(shí)就基本判斷問題出在這里了,使用的解決方案就是通過重新固化執(zhí)行計(jì)劃來選擇好的執(zhí)行計(jì)劃。
接著就開始分析問題產(chǎn)生的原因。
對(duì)于索引跳躍式掃描而言,在一般情況下,如果運(yùn)維索引的***個(gè)列沒有用到,當(dāng)它開始使用到第二個(gè)列時(shí),就只能用跳躍式的方法去進(jìn)行一個(gè)索引掃描。而在分析問題原因時(shí),因?yàn)轭愃频恼Z(yǔ)句比較多,我們當(dāng)時(shí)在固化了幾十條后,發(fā)現(xiàn)還有源源不斷的類似語(yǔ)句出現(xiàn),就考慮到問題可能并沒有那么簡(jiǎn)單。所以我們又進(jìn)行了進(jìn)一步分析,***發(fā)現(xiàn)可能是索引的統(tǒng)計(jì)信息有問題。于是我們就重新收集了索引的統(tǒng)計(jì)信息,至此,類似的語(yǔ)句問題才算是解決了。
但其實(shí)這個(gè)問題并沒有徹底結(jié)束:
我們?cè)谔幚硗旰笥种匦路治隽诉@個(gè)索引的問題,發(fā)現(xiàn)索引***列是一個(gè)空值,但不知道是誰(shuí)在空列和輸入時(shí)間上建了一個(gè)符合索引,導(dǎo)致這個(gè)索引有可能會(huì)被使用。
發(fā)現(xiàn)問題后,我們就查詢了這個(gè)索引的訪問方式,看看是否全都是INDEX SKIP SCAN。后來發(fā)現(xiàn),基本上訪問這個(gè)索引的語(yǔ)句都用的是這種索引跳躍式掃描,所以我們當(dāng)時(shí)就把這個(gè)索引設(shè)置為不可用,后面把它刪除了。類似的索引,我們當(dāng)時(shí)處理了有三個(gè),之后這個(gè)系統(tǒng)就沒有再出現(xiàn)這樣類似的問題。
SPM也是一種固化執(zhí)行計(jì)劃的方式,但為什么在這個(gè)庫(kù)里,SPM會(huì)失效呢?
之后我們分析了它的原因:是因?yàn)槊看伟l(fā)版本時(shí),有可能會(huì)多查一些字段,導(dǎo)致語(yǔ)句發(fā)生變化。SPM這類的固化執(zhí)行計(jì)劃的方式都和語(yǔ)句有強(qiáng)關(guān)聯(lián),只要語(yǔ)句上有一個(gè)小小的改動(dòng),都會(huì)導(dǎo)致固化的方式失效。這也是每次更新版本語(yǔ)句都會(huì)發(fā)生異常的原因之一。
之后我們繼續(xù)分析,為什么這個(gè)時(shí)間索引有這種類似問題?
這是我們之前整理的一個(gè)案例分析的原因:我們?cè)谧鏊饕姆秶樵儠r(shí),它的選擇率公式如下
但是在不同情況下,比如這種右側(cè)索引,比如創(chuàng)建時(shí)間、更新時(shí)間、輸入時(shí)間,我們寫入數(shù)據(jù)都是用sysdate寫入的,那么它永遠(yuǎn)都在索引列的右側(cè),類似這種方式是往里面插入數(shù)據(jù)的。
然而我們統(tǒng)計(jì)信息的收集又不是一個(gè)實(shí)時(shí)收集的,主要是對(duì)一些大表,比如一個(gè)一千萬的表可能要到10%,也就是100萬的DMR量;更大的表的DMR量會(huì)更大。這就會(huì)導(dǎo)致我們的統(tǒng)計(jì)信息和當(dāng)前的值永遠(yuǎn)是過時(shí)的,就會(huì)產(chǎn)生這種問題。
對(duì)于這三個(gè)查詢來說:***個(gè)查詢發(fā)生在有效范圍內(nèi),所以它可以反映出一個(gè)比較真實(shí)的數(shù)據(jù),第二個(gè)查詢也可以反映一部分,但第三個(gè)查詢就相當(dāng)于完成一個(gè)超范圍的查詢,計(jì)算出一個(gè)很低的值,這樣就會(huì)導(dǎo)致我們的語(yǔ)句偏異常。
更坑的是在OLPP系統(tǒng)里,新數(shù)據(jù)查詢的幾率永遠(yuǎn)比老數(shù)據(jù)的大,越新的數(shù)據(jù)被訪問的幾率越高,這也導(dǎo)致我們的語(yǔ)句每次都會(huì)出現(xiàn)異常的情況。
發(fā)現(xiàn)這些問題后,我們立即展開了一個(gè)行動(dòng),就是把數(shù)據(jù)庫(kù)里所有與時(shí)間索引相關(guān)的字段都提取一下,然后定期修改索引字段上面的HIGH VALUE,統(tǒng)計(jì)信息里面的HIGHVALUE,就能避免出現(xiàn)這種問題。
如上圖所示,是一個(gè)范圍查詢的情況,即在一個(gè)索引前導(dǎo)列的區(qū)別,類似于我們?cè)趧?chuàng)建時(shí)間和OWNER之間建索引。如果把創(chuàng)建時(shí)間放在前面,把OWNER放在后面就是***種情況;如果把OWNER放在前面,把CREATED放在后面就是第二種情況。
現(xiàn)在來分析這兩個(gè)不同索引的區(qū)別:
當(dāng)我們把創(chuàng)建時(shí)間放在前面時(shí),有一個(gè)很大的問題,我們通過時(shí)間字段去查詢時(shí)很難做到等值查詢,即不可能去發(fā)現(xiàn)每分每秒插入的值。對(duì)于這種查詢,我們一般都使用范圍查詢,比如查一個(gè)月或一天、一周的數(shù)據(jù)。所以大家可以看到,如果我在這個(gè)語(yǔ)句內(nèi)查這一分鐘、這一天DBMGR創(chuàng)建的情況,在***個(gè)索引里它整個(gè)范圍都會(huì)涉及到,隨后取相關(guān)聯(lián)的三個(gè)值;但是在第二個(gè)索引里,三個(gè)值是連在一起的,因?yàn)镈BMGR 是有序的,時(shí)間也是有序的,它們就可以完成只涉及到自己相關(guān)值的值。
這里面還有一些細(xì)小的區(qū)別:如果我先進(jìn)行范圍查詢,后做等值查詢,對(duì)于這樣的索引,F(xiàn)ilter時(shí)就會(huì)多做一個(gè)Filter步驟。但如果把這個(gè)順序調(diào)整一下,就不會(huì)有這種情況。所以我們?cè)谧鲞@種符合索引創(chuàng)建的時(shí)候,就一定要盡量把等值查詢的放在前面。
之前有一個(gè)說法:在選擇符合索引的前導(dǎo)列時(shí),要把選擇率比較低的值放在前導(dǎo)列。
但我們覺得這個(gè)說法是不完善的:比如對(duì)于一個(gè)時(shí)間字段而言,一天有86400秒,100天就可能有800多萬的不同值,一年會(huì)有更多不同值。可如果把這個(gè)作為前導(dǎo)列,有時(shí)候是不適合的,因?yàn)閷?duì)它來說,有可能我們是需要查詢一天或一個(gè)月的數(shù)據(jù),而一年有365天,或者說十二個(gè)月。因此更準(zhǔn)確的說法應(yīng)該是把查詢條件中選擇率低的列做為復(fù)合索引的前導(dǎo)列。
所以通過這個(gè)案例,我們就把運(yùn)維問題的解決分成了三個(gè)步驟:
- ***步:快速解決問題,確保應(yīng)用恢復(fù)。對(duì)于運(yùn)維人員來說,恢復(fù)應(yīng)用是***位的;
- 第二步:看問題是不是重復(fù)性發(fā)生的。比如前面說的案例一,如果我們當(dāng)時(shí)的處理方案僅是固化執(zhí)行計(jì)劃,或是收集統(tǒng)計(jì)信息,你沒有辦法保證它以后不會(huì)再出現(xiàn)類似的情況。如果我們使用的是收集統(tǒng)計(jì)信息的方式,可能再過一個(gè)月或兩個(gè)月,這種情況又會(huì)再次發(fā)生,所以根本的解決方案是找到這個(gè)問題發(fā)生的原因,確保這次問題解決后不會(huì)再?gòu)?fù)發(fā);
- 第三步:避免問題,看這個(gè)問題是否屬于共性問題、其他庫(kù)里有沒有類似問題。如果有類似問題,就要形成一種規(guī)范,去避免這種問題的發(fā)生。尤其是對(duì)于一些新的應(yīng)用來說,只有當(dāng)你制定規(guī)范、讓開發(fā)遵守后,后續(xù)才會(huì)減少類似問題的發(fā)生,不然就會(huì)演變成我們一邊解決問題,新問題又源源不斷發(fā)生的情況,***我們只能不斷地去解決這種重復(fù)發(fā)生的問題。
我記得之前有一個(gè)案例就是共性問題:當(dāng)時(shí)是在一個(gè)實(shí)際的庫(kù)里,我們分析發(fā)現(xiàn)它存在內(nèi)存泄漏的問題,但并沒有馬上開始處理,結(jié)果第二天另一個(gè)庫(kù)也發(fā)生內(nèi)存泄漏,于是我們不得不緊急重啟。
當(dāng)時(shí)我們分析出問題是由某一個(gè)BUG導(dǎo)致后,就搜索那個(gè)BUG相關(guān)的信息,發(fā)現(xiàn)早在兩三年前(2014年)已經(jīng)有同事解決了這個(gè)問題,只不過在另一個(gè)庫(kù)里還打了相應(yīng)的PATCH來解決問題,但就是因?yàn)闆]有把這個(gè)問題推廣到所有系統(tǒng)里,排查是否其他庫(kù)也存在這個(gè)問題而引起的。
從那之后我們就特別注意這種共性問題,如果每個(gè)系統(tǒng)、每個(gè)問題都要發(fā)生一次,代價(jià)實(shí)在是太大了,所以我們盡可能在發(fā)現(xiàn)共性問題后就解決掉,盡量排除其他庫(kù)也發(fā)生類似問題的情況。
案例二
第二個(gè)案例是一個(gè)版本為12.1.0.2的Oracle數(shù)據(jù)庫(kù),每到晚上總會(huì)不定時(shí)地主機(jī)CPU持續(xù)到100%,應(yīng)用同時(shí)會(huì)創(chuàng)建大量的數(shù)據(jù)到數(shù)據(jù)庫(kù)中。
當(dāng)時(shí)我們的應(yīng)急方案是把這種相關(guān)的等待時(shí)間全部批量Kill掉,因?yàn)檫@些系統(tǒng)是在比較核心的庫(kù)里,基本上每個(gè)系統(tǒng)被Kill掉的進(jìn)程有幾千個(gè),代價(jià)還是比較大的。
后來這個(gè)問題發(fā)生兩次后,我們開始著手重點(diǎn)分析問題,通過ASH分析發(fā)現(xiàn),出現(xiàn)這個(gè)異常等待是因?yàn)橐粋€(gè)很簡(jiǎn)單的語(yǔ)句——SELECT USER FROM SYS.DUAL。
之后我們就通過這個(gè)語(yǔ)句來一步步關(guān)聯(lián), 看到底是哪個(gè)地方調(diào)用的,結(jié)果發(fā)現(xiàn)是在一個(gè)應(yīng)用用戶的登錄TRIGGER中的用戶判斷步驟。這個(gè)USER是Oracle的內(nèi)部函數(shù),但就是這么簡(jiǎn)單的一個(gè)語(yǔ)句,就讓整個(gè)庫(kù)都Hang住了。
然后我們開始分析原因。我們通過ASH發(fā)現(xiàn)該語(yǔ)句在我們恢復(fù)應(yīng)用前有重新加載的過程。當(dāng)時(shí)我們懷疑是硬件導(dǎo)致的,就通過這種方式去分析,結(jié)果發(fā)現(xiàn)是在晚上10點(diǎn)時(shí)被Oracle的自動(dòng)任務(wù)做了一個(gè)統(tǒng)計(jì)信息的自動(dòng)收集,收集完后,又因?yàn)樗且粋€(gè)登錄的Trigger,用戶在不斷登錄,在做登錄解析時(shí)這個(gè)語(yǔ)句就沒辦法解析,所以才導(dǎo)致用戶源源不斷地卡在那里。而應(yīng)用是需要新建連接的,新建的連接又無法進(jìn)到庫(kù)里面,就會(huì)導(dǎo)致連接數(shù)越來越多,全都卡在那里。***我們通過鎖定dual表統(tǒng)計(jì)信息的收集來從根本上解決這個(gè)問題。
案例三
第三個(gè)案例有兩個(gè)問題,但后來我們發(fā)現(xiàn)這兩個(gè)問題是由相同的原因引起的。
我們有一個(gè)數(shù)據(jù)庫(kù)是從10.2.0.5.X升級(jí)到10.2.0.5.18版本,升級(jí)后會(huì)不定時(shí)出現(xiàn)cursor:pin相關(guān)的一些等待。其實(shí)出現(xiàn)cursor:pin是很正常的,因?yàn)檫@個(gè)數(shù)據(jù)庫(kù)的負(fù)載比較高,變化也較高,但問題是它是在升級(jí)之后出現(xiàn)的。運(yùn)營(yíng)認(rèn)為這是升級(jí)之后出現(xiàn)的異常,我們就開始著手分析問題的原因。
第二個(gè)問題是我們?cè)趹?yīng)急時(shí)發(fā)現(xiàn)的,有時(shí)異常出現(xiàn)時(shí),某個(gè)庫(kù)里有些語(yǔ)句的執(zhí)行次數(shù)會(huì)特別高,甚至15min能達(dá)到上億次,這對(duì)于一個(gè)正常的業(yè)務(wù)系統(tǒng)來說,出現(xiàn)這么高的執(zhí)行頻率是不正常的。
之后我們就去分析這些問題,發(fā)現(xiàn)這兩個(gè)問題有相同的一些點(diǎn),比如語(yǔ)句中間出現(xiàn)了個(gè)函數(shù)調(diào)用;比如說這個(gè)情況下,A表如果訪問的數(shù)據(jù)量較大時(shí),這些函數(shù)就有可能被調(diào)用很多次。
我們發(fā)現(xiàn),有一個(gè)語(yǔ)句,它執(zhí)行一次可能會(huì)出現(xiàn)十幾萬次的函數(shù)調(diào)用。如果在調(diào)用的過程中,關(guān)聯(lián)的那張表的執(zhí)行計(jì)劃發(fā)生了變化,比如說A表走了一個(gè)全程掃描,那可能會(huì)出現(xiàn)幾千萬次的函數(shù)調(diào)用。
當(dāng)時(shí)我們也總結(jié)了一些關(guān)于通過什么樣的方法去快速定位、是否是函數(shù)調(diào)用導(dǎo)致的看法。在10g之前確實(shí)沒有什么好的辦法,因?yàn)樗锩鏇]有一個(gè)顯示的關(guān)聯(lián),就可能通過代碼去掃描,去找對(duì)應(yīng)的語(yǔ)句。在11g后會(huì)比較簡(jiǎn)單一些,通過AS值相關(guān)的TOP LEVEL SQL ID就可以直接關(guān)聯(lián)到是哪個(gè)語(yǔ)句調(diào)的函數(shù)導(dǎo)致的問題。
這里還有一個(gè)問題是函數(shù)調(diào)用。因?yàn)樗{(diào)用的函數(shù)可能都是特別快的,但次數(shù)有會(huì)比較高,性能波動(dòng)可能帶來比較大的影響。之前我們有一個(gè)案例就發(fā)生在月底高峰,我們當(dāng)時(shí)發(fā)現(xiàn)某個(gè)數(shù)據(jù)庫(kù)中會(huì)出現(xiàn)很多CBC的等待,后來又發(fā)現(xiàn)有一個(gè)小表被頻繁訪問,那個(gè)小表就100多行數(shù)據(jù),但可能它相關(guān)的語(yǔ)句每隔15min就調(diào)用了上千萬次。
其實(shí)這么高的并發(fā)下,出現(xiàn)這種CBC的等待是很正常的。不過因?yàn)樗挥?00多行數(shù)據(jù),且都集中在一個(gè)數(shù)據(jù)塊里,所以才導(dǎo)致這個(gè)數(shù)據(jù)塊特別熱,就會(huì)一直出現(xiàn)這種CBC的等待。
于是我們就找辦法解決這個(gè)熱快的問題,但又因?yàn)椴荒茉谠碌讻_業(yè)績(jī)時(shí)停運(yùn)來做修改,所以我們就想了一個(gè)方案:建一個(gè)PCT FREE 99的索引,把表所有列的數(shù)據(jù)都包含進(jìn)去,確保每個(gè)索引塊里面只保留了一行數(shù)據(jù),變相地把這100多行數(shù)據(jù)分到100多個(gè)塊里。
做了這個(gè)操作后,CBC相關(guān)的問題被解決了,也順利地?fù)芜^了業(yè)務(wù)高峰期,但是第二天月初的報(bào)表發(fā)現(xiàn)又掉坑里了。
因?yàn)槲覀冊(cè)诿總€(gè)月月初需要上報(bào)給監(jiān)管的一個(gè)報(bào)表,這種報(bào)表是屬于一個(gè)長(zhǎng)事務(wù),但是它在那個(gè)報(bào)表里面也是調(diào)了之前優(yōu)化的那個(gè)索引,優(yōu)化后的語(yǔ)句雖然降低高峰期CBC的等待,但因?yàn)樗且L問100多個(gè)數(shù)據(jù)塊,單次訪問從0.25毫秒變成了1毫秒,相當(dāng)于效率降低了4倍。由于報(bào)表是一種長(zhǎng)事務(wù)的處理,相當(dāng)于那個(gè)進(jìn)程比原來多花了一倍多的時(shí)間也沒跑完。所以之后我們發(fā)現(xiàn)這個(gè)問題后,又不得不把那個(gè)索引給干掉了,讓它恢復(fù)原來那種狀態(tài)。
尤其是現(xiàn)在對(duì)IT的要求越來越高,時(shí)限的要求也越來越高,很多系統(tǒng)基本都是用這種敏捷的開發(fā)方式盡快地上線。新系統(tǒng)上線有一個(gè)很大的問題就是剛上線時(shí)壓力都不會(huì)很大、負(fù)載也不高,但其實(shí)是很多問題在開始階段被隱藏了。等到真正發(fā)生問題時(shí),負(fù)載高了或者壓力大了再去解決問題,難度就會(huì)比較大一點(diǎn)。
尤其對(duì)于數(shù)據(jù)庫(kù)來說,數(shù)據(jù)庫(kù)量小的時(shí)候,比如說300、500M的數(shù)據(jù),這個(gè)表格怎么整改都很簡(jiǎn)單,但等到這個(gè)表漲到300、500G甚至1、2T時(shí)再想去做這個(gè)表數(shù)據(jù)類的整改,難度就會(huì)大很多。
比如說,我們之前做分期表整改時(shí)會(huì)用這種在線重定義的方式,但對(duì)于一些比較大的表,幾百G甚至上T的表,再用這種在線重定義的方式,就會(huì)遇到各種各樣的BUG。
后來坑踩多了,我們現(xiàn)在對(duì)于大表的分表改造就是先同步歷史數(shù)據(jù)級(jí)改造,后做一個(gè)數(shù)據(jù)增量,方法會(huì)復(fù)雜很多。但其實(shí)如果在開始階段,我們對(duì)于這種大表就已經(jīng)設(shè)計(jì)好它的分區(qū),尤其在時(shí)間索引上,基于時(shí)間去做一個(gè)分區(qū),可以避免很多問題。
為什么我們的歷史庫(kù)里有那么多時(shí)間索引?
很大的一個(gè)原因是有很多報(bào)表是基于時(shí)間去查詢的,比如說要查這一個(gè)月或者這一天新增的一些數(shù)據(jù)的情況,都需要通過時(shí)間的字段去訪問。我之前就見過很多關(guān)于時(shí)間的索引,但***卻因?yàn)闀r(shí)間索引的特性,導(dǎo)致系統(tǒng)源源不斷地出現(xiàn)各種各樣的問題。如果在設(shè)計(jì)階段把這些大表提前就設(shè)計(jì)成分區(qū)表,完全可以避免這些不必要的問題。
二、運(yùn)維管理
因?yàn)楦鱾€(gè)公司具體情況不同,我接下來就簡(jiǎn)單介紹一下我司關(guān)于運(yùn)維管理的一些做法,給大家做個(gè)參考。
1、變更管理
相對(duì)來說,我們公司的變更管理比較嚴(yán)格,后續(xù)可能會(huì)更加嚴(yán)格。
變更管控
對(duì)于變更管控,比如在白天嚴(yán)禁做任何變更,工作時(shí)間內(nèi)任何變更都不能做,即便是一些緊急或故障的修復(fù),也是需要通過部門負(fù)責(zé)人確認(rèn)、領(lǐng)導(dǎo)同意后才可以做的,確保風(fēng)險(xiǎn)可控。
變更流程
可能每個(gè)公司都有變更流程,但我們公司有一個(gè)比較特殊的地方。因?yàn)橐恍┘嫒輸?shù)據(jù)庫(kù)的要求可能會(huì)高一些,流程管控的每個(gè)部分都要確保到位。
變更方案
我們的變更方案是每個(gè)人要提前去做評(píng)審和驗(yàn)證,包括制定方案的同事和實(shí)施操作的同事,就需要變更實(shí)施人員提前在一個(gè)環(huán)境下做完整的驗(yàn)證,確保每個(gè)步驟都是驗(yàn)證通過的。
2、規(guī)范管理
架構(gòu)規(guī)范
我自己之前在做架構(gòu)師時(shí),制定各種各樣的規(guī)范是一項(xiàng)重點(diǎn)的工作??赡苁丘B(yǎng)成習(xí)慣了,現(xiàn)在也和大家一起制定各式各樣的運(yùn)維規(guī)范。但我自己感受最深的是:規(guī)范一定要有統(tǒng)一的標(biāo)準(zhǔn),如果做不到統(tǒng)一就有可能會(huì)在后續(xù)產(chǎn)生問題。
比如我們之前有些開發(fā)測(cè)試環(huán)境不是那么規(guī)范,現(xiàn)在想改造做自動(dòng)化時(shí),發(fā)現(xiàn)根本就做不起來,因?yàn)槊總€(gè)庫(kù)的情況不一樣,自動(dòng)化的腳本不可能適應(yīng)所有情況來做這種標(biāo)準(zhǔn)化的改造。
把它弄成不標(biāo)準(zhǔn)是很簡(jiǎn)單的,但要想把不標(biāo)準(zhǔn)的改成標(biāo)準(zhǔn)的,難度就大了,尤其是在我們已經(jīng)形成習(xí)慣之后。
運(yùn)維規(guī)范
在2014年前,我們做的是純Oracle數(shù)據(jù)庫(kù)的運(yùn)維,因?yàn)橹敖⒌氖且粋€(gè)傳統(tǒng)的金融企業(yè),運(yùn)維的都是Oracle數(shù)據(jù)庫(kù),但2014年后我們逐步轉(zhuǎn)向了互聯(lián)網(wǎng)金融。因此我們陸續(xù)研究了MySQL、PG、Redis、MongDB、SQL Server、HBase等7、8種數(shù)據(jù)庫(kù),在運(yùn)維過程中遇的坑就會(huì)比較多。
最初有很多標(biāo)準(zhǔn),但沒有一個(gè)是***的實(shí)踐,很多也是根據(jù)業(yè)界、自己的經(jīng)驗(yàn)制定出來了;還有各種不同的數(shù)據(jù)庫(kù)里,不同的團(tuán)隊(duì)制定了不同標(biāo)準(zhǔn),***就有各種各樣的標(biāo)準(zhǔn)了。
所以我們?cè)谶\(yùn)維中會(huì)發(fā)現(xiàn)各種各樣的問題,***要強(qiáng)制去做這方面的規(guī)范整改。而且,之前的標(biāo)準(zhǔn)大部分都沒有經(jīng)過大規(guī)模使用和大規(guī)模負(fù)載的驗(yàn)證,很多標(biāo)準(zhǔn)并不那么統(tǒng)一、規(guī)范和有效。因此,我們?cè)谶\(yùn)維過程中對(duì)于這種規(guī)范,還是在不斷地去優(yōu)化和改進(jìn),畢竟很多情況在沒有遇到時(shí),你真的是沒有辦法去解決這個(gè)問題。
規(guī)范優(yōu)化
舉個(gè)例子,最初我們并沒有規(guī)定Redis一定要和應(yīng)用放在同一個(gè)網(wǎng)絡(luò)區(qū)域,但隨著 Redis的負(fù)載增加,我們發(fā)現(xiàn)防火墻已經(jīng)承受不了。當(dāng)時(shí)平安的WiFi剛上線不久,但關(guān)于Redis的訪問,幾個(gè)實(shí)例每秒都有高達(dá)到上萬次調(diào)用,整個(gè)防火墻都撐不住了,還差點(diǎn)導(dǎo)致一個(gè)比較嚴(yán)重的故障。
在解決這個(gè)問題后,我們就制定了一條強(qiáng)制的規(guī)范:Redis這種高并發(fā)訪問的數(shù)據(jù)庫(kù),一定要和應(yīng)用放在一起,不能有出現(xiàn)跨墻訪問的情況。
所以這個(gè)規(guī)范也是不斷去優(yōu)化的,包括我們運(yùn)維的一些標(biāo)準(zhǔn)。因?yàn)樵谧畛鮿?chuàng)建標(biāo)準(zhǔn)時(shí),我們可能會(huì)因?yàn)槭褂脮r(shí)間不長(zhǎng)而考慮不到一些問題。
我印象比較深刻的是MySQL剛引入時(shí)的一個(gè)問題,對(duì)于軟件的版本沒有明確到小版本,后來甚至出現(xiàn)有MySQL停庫(kù)時(shí)是5.6.22的版本,在維護(hù)完成后就被啟動(dòng)成5.6.16的版本,***是通過不斷地優(yōu)化來確保我們的規(guī)范和實(shí)際是相結(jié)合的,避免這種問題的發(fā)生。
3、 人員發(fā)展
團(tuán)隊(duì)意識(shí)
關(guān)于團(tuán)隊(duì)這塊,需要提升每個(gè)人在團(tuán)隊(duì)中的作用,需要確保團(tuán)隊(duì)里的每個(gè)人都是有備份的。如果發(fā)展成離開誰(shuí)都不行,那對(duì)團(tuán)隊(duì)的整體發(fā)展來說是不正常的。
所以我們?cè)诎才殴ぷ鲿r(shí),對(duì)于比較重要的工作,我會(huì)盡量不讓熟悉的同事重復(fù)去做,而是盡量讓一些不熟悉的同事參與去做。之前每走一個(gè)資深成員,都會(huì)明顯感覺到團(tuán)隊(duì)的整體技能或知識(shí)少了一塊。為了避免類似問題的發(fā)生,從2017年開始我們就制定了一些策略,讓大家做知識(shí)技能的分享,每周抽取兩個(gè)下午,每個(gè)下午抽取一到兩個(gè)小時(shí)做分享。
另一個(gè)策略是技能的積累,即把我們?cè)诠ぷ髦杏龅胶徒鉀Q的一些問題都錄入問題管理系統(tǒng)。這樣做有兩個(gè)好處:一是可以把重復(fù)的問題記錄下來,因?yàn)槲覀兿胍シ治瞿男﹩栴}是重復(fù)發(fā)生的、哪些是有共性的,就需要有一個(gè)這樣的系統(tǒng)去拉對(duì)應(yīng)的問題清單,***去解決問題;二是即便人員流失了,他們之前解決的一些問題和技能也能讓團(tuán)隊(duì)其他人發(fā)現(xiàn),不至于每走一個(gè)人就留下一個(gè)坑。
所以我們是通過這種手段來盡量避免人員流失或變動(dòng)給團(tuán)隊(duì)帶來的一些問題。但說到底,其實(shí)這是沒辦法完全避免的,因?yàn)閿?shù)據(jù)庫(kù)運(yùn)維有一定的復(fù)雜度,需要依靠不斷地發(fā)生故障、解決故障,包括一些人為失誤來提升。
權(quán)責(zé)分明
我們的輪班人員是7×24小時(shí),即上三班的方式來輪班的。之前團(tuán)隊(duì)有一個(gè)比較嚴(yán)重的問題,當(dāng)一件事情發(fā)生了,輪班人員有可能將問題交接給下一班次;或是升級(jí)給其他人后,就覺得與自己沒有關(guān)系了。還有就是風(fēng)險(xiǎn)意識(shí)不強(qiáng),有一些操作沒有評(píng)估過影響就開始在生產(chǎn)庫(kù)里操作。
當(dāng)時(shí)我們也發(fā)生了不少問題,后來在內(nèi)部重點(diǎn)提升兩點(diǎn)意識(shí):責(zé)任人意識(shí)和風(fēng)險(xiǎn)意識(shí)。
首先你需要在生產(chǎn)做措施前,確保要做的操作會(huì)有什么影響、導(dǎo)致什么后果,不能在做完后才去想這個(gè)問題:比如說我們現(xiàn)在每天變更,都需要提前把腳本和手冊(cè)做好,讓值班人員熟悉。操作會(huì)有什么后果?后續(xù)有什么異常會(huì)發(fā)生?應(yīng)對(duì)方法又是什么?……這些都是需要提前評(píng)估好的。
技能提升
關(guān)于技能提升,雖然必要的培訓(xùn)是必不可少的,但我們認(rèn)為關(guān)鍵還是要靠自己的學(xué)習(xí)、理解和在實(shí)踐中的積累,并沒有什么好的捷徑去實(shí)現(xiàn),大多時(shí)候還是要通過不斷地解決問題、發(fā)現(xiàn)問題甚至包括犯錯(cuò)的代價(jià)來提升的。