訂單同步工程標準化改造事記

提及來,也是一段比較有挑戰有壓力的經歷。作完以後,有一種雲淡風輕的感受,故記之。

html

緣起

週二下午,忽報:QA 環境下單以後,訂單搜索不出來了。java

略排查,發現訂單記錄並未同步到 ES 索引裏。進一步發現,訂單同步工程 S 雖然進程還在,但已經再也不處理消息了。昨天由於一個項目的需求才測試過 QA 環境訂單同步無問題,上午也沒動靜,怎麼下午就忽然報問題了呢?mysql

很快聯想到,前兩日,框架層發了通告:再也不爲使用了 3.2.x 如下 dubbo 版本的應用提供自動註冊 dubbo 服務的能力。極可能是 S dubbo 版本太低,沒法註冊和訪問 dubbo 服務,沒法進行訂單同步,進而影響訂單搜索和詳情,嚴重阻塞了項目的測試。訂單是核心嘛~~react

因而我將 pom 裏的 dubbo 版本改爲了最新版本。可仍是不行。要找框架同窗一塊兒排查下了。

git

舊世界

ClassVisitor

框架同窗東順說,早上貌似改過 zan 版本,也許是這個致使的。因而,我請求降回到原來的版本,先解決問題再說。sadly,即便降回到原來的版本進行部署, S 的服務依然起不來。退路已斷。面試

框架同窗子傑的第一個想法,是在本地啓動調試。由於這樣方便且高效。不過 S 應用已經好久沒有在本地啓動。並且 S 依賴比較多,在本地恐怕很難啓動。sql

報 ClassVisitor should be a interface , not a class 。此類錯誤一般是 jar 衝突致使。所以,我在工程裏搜索了下 ClassVisitor ,果真發現有兩個,一個是接口,一個是類。 看來要排掉那個有類 ClassVisitor 的 jar 包。apache

<dependency>
            <groupId>com.youzan.platform</groupId>
            <artifactId>bootstrap</artifactId>
            <version>3.2.7.3-RELEASE</version>
            <exclusions>
                <exclusion>
                    <groupId>org.ow2.asm</groupId>
                    <artifactId>asm</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

排掉以後,就再也不報這個錯了。 然而, S 依然不處理消息。json

一邊是測試同窗在催促,一邊是毫無頭緒。內心有些急,可一時也想不到如何解決。子傑指望本地調試,可本地啓動老是報奇怪的 groovy 不兼容錯誤。調了一夜,終於把這個問題解決了。 但 S 依然不處理消息。

bootstrap

補丁

週三早上,繼續戰鬥。子傑發了一段配置,讓放在 S 工程的 XML 配置裏。說這段配置是用來註冊 dubbo 服務的。 加入以後,報錯: cause: Could not initialize class com.coreos.jetcd.api.KVGrpc, dubbo version: 1.0.1-SNAPSHOT, current host: x.x.x.x

子傑看了,開心地說,這個錯誤以前見過,可能 protobuf 版本衝突了。 離成功不遠了。

<dependency>
            <groupId>org.apache.hbase</groupId>
            <artifactId>hbase-server</artifactId>
            <version>1.2.6</version>
            <exclusions>
                <exclusion>
                    <groupId>com.google.protobuf</groupId>
                    <artifactId>protobuf-java</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

排除 protobuf-java 包以後,終於能夠起來了。 驗證了下,訂單同步 OK 了。 鬆了一口氣。

間歇性跪

纔沒輕鬆多久, 又跪了。又跪了。又跪了。又跪了。 測試同窗又來催了。

溝通

在這種情形下,發生一點小「糾紛」老是可能的。有一次,在吃飯的時候,S 跪了。 測試同窗羣裏喊:進度如何了,找到根本緣由了麼? 內心有點惱火:做爲開發,我確定要盡職盡責儘早排查和解決問題;但是你也不能只是催,在這樣尷尬的時刻,能夠支援一下嘛。 不過,你們都很通情達理,我提供了「臨時啓動服務」的方法,測試同窗就幫忙先啓動服務了。

反思一下,測試同窗的作法也是合情合理的,由於他們要負責保障更大域範圍的環境穩定,須要知道進度和緣由。解決棘手問題時,同步進度和緣由也是很重要的,內心應該裝下更大的世界。此外,若我能及早同步「臨時解決方案」,讓測試同窗知道怎麼解決,也不會有這樣的「糾紛」。有話好好說,總能找到更柔和的方式來解決。

因而我在羣裏回覆:他們的擔憂和考慮是合理的,且已經快接近成功了。稍安。其實我也不知道距離成功還有多遠。

蛛絲馬跡

排查問題,只能從錯誤日誌裏尋找一切蛛絲馬跡。子傑找了一段 JVMExitHook 的代碼,加在啓動的時候,這樣方便在進程退出的時候,打印一些線索。 不過,這招沒起效果,打印出的信息彷佛沒有派上用場。

同時,我也在仔細觀察日誌裏出現的各類細微錯誤。不能放過一個嫌疑份子。確認了有四種可能的影響因素:1. 應用 M 跪; 2. Hbase 讀寫失敗; 3. 髒數據; 4. 底層 jar 不兼容,致使某種隱藏的問題。

M跪

又跪了。發現 S 有個任務訪問 M 服務報錯,登陸機器,發現 M 服務跪了。重啓 M 。 過了一段時間,S 又跪了,M 服務也跪了。會不會受了這個服務的影響呢 ? 將 M 服務所涉及的任務暫時禁用了。將 M 禁用後,S 彷佛就沒有跪過了。

M 報錯的緣由,是由於零售同窗將一個接口遷移到了新的工程,也就是說,原來的接口下線了。 S 去註冊這個接口的服務的時候找不到。

HBase

發現有一些 HBase 寫入失敗。諮詢 HBase 同窗,是由於 QA 集羣運行了一些離線任務,有時資源比較緊張。 雖然有疑點,但不太可能致使 S 跪。

髒數據

在排查過程當中,也發現有些髒數據,致使 NSQ 消息處理失敗。髒數據可能把一個任務搞跪,不過 S 裏有不少任務,要把 S 跪掉,還須要一些「道行」 吧。

隱藏的坑

只是猜想,但確實是比較大的嫌疑。 由於前三者都是局部的影響,不太可能將 S 整個搞跪掉,但這個多是全局的影響。好比說,某個 jar 版本的組件,與另外一個組件交互,可能產生 bug , 吃內存,致使內存 OOM 。只是猜想。

暫時維穩

子傑有了新的發現。從 dmsg 日誌裏看到,S 獨佔內存過多,Linux 內核將 S 的 java 進程 kill 掉了。調整了堆內存從 6.5G 到 4G,而後運行了一成天都沒有跪。

java invoked oom-killer: gfp_mask=0x201da, order=0, oom_adj=0, oom_score_adj=0
java cpuset=/ mems_allowed=0
Pid: 4288, comm: java Not tainted 2.6.32-754.9.1.el6.x86_64 #1
[ 4286] 602 4286 3321904 1898888 2 0 0 java
Out of memory: Kill process 4286 (java) score 929 or sacrifice child
Killed process 4286, UID 602, (java) total-vm:13287616kB, anon-rss:7595528kB, file-rss:24kB


新工程

QA 環境終於能夠暫時安靜一會了。 但是,生產環境如何解決呢?

S 承載着公司億級訂單的同步,顯然不能容忍用打補丁的方式來解決(況且這個補丁很噁心,會埋很大的坑),並且也沒法接入 aladdin ,自動升級 jar 版本。 所以, QA 的作法,只能暫時維穩,不能用做生產環境的解決方案。

諮詢子傑 ,是否有辦法能夠以最小成原本改造 S 應用 ? 回答:使用 youzan-boot 標準化工程。但是要改形成 youzan-boot 工程,勢必改動很大,整個工程結構都變了,部署方式也變了,上線風險是很大的。對於 S 這樣的應用,稍有不慎,就是 P1 或 P0 故障。

進退兩難。

由於本身不太熟悉應用打包和部署的方式,有點畏難。但想了想,本質上就是把應用裏的任務想辦法啓動起來。絕大部分代碼都是能夠複用的,只須要在新的工程結構中,將原來的啓動代碼嵌入進去。想到這裏,有了一些信心,決定採用新工程的方式來解決這個問題。

new出了null

根據子傑提供的文檔及界面,很快創建了新的標準化腳手架工程。接着,將原工程的代碼拷貝到新的工程裏,並在啓動的入口,將原來啓動任務的類的方法添加進去。

我是一個不解決主要問題寢食難安的人。深夜,繼續。部署後,初始化任務出錯。只好加日誌,看看哪裏拋異常了。不加沒關係,一加he一跳。
`Task task = new Task(); logger.info("task:{}", task) , 居然打出了個 null !

new 出了個 null ? 百思不得其解。想着,恐怕又沒進展了, 打算睡覺了。正準備睡覺的時候,忽然靈光一閃,去查看了下 toString 方法,是打印 task 實例中的 taskConfig 的,而此時 taskConfig 做爲入參尚未設置到 task 中,所以打印爲 null 。真是腦經急轉彎啊。 遇到的每一個問題,都是一道面試題。):

看來,在程序的世界裏,一切奇怪的事情,總有一個合理的原因。 聯想到前不久的 「奇怪之事總有原因:訂單狀態對比不一致問題排查」 ,有所領會。

環境變量引用改造

繼續排查爲何 task 沒有正確初始化。對比原工程,發現 task 是一個聲明爲 prototype 的類,所引用的組件,也是 prototype 的。新老工程沒有差別。

從日誌裏能夠看到,環境變量讀取到應用裏,依然是佔位符,並無正確地被替換。 原工程爲了靈活,使用了 yaml 文件來配置環境變量,並在代碼裏作了遍歷,這樣,若是須要增長新的環境變量,只須要在 yaml 增長一項便可。

<bean id="mysqlDataSource" class="com.youzan.trade.sync.v2.EnvConfigLoader" init-method="init">
     <constructor-arg value="config/config.yaml"/>
</bean>

@Slf4j
public class EnvConfigLoader {

    private final String dir;

    public EnvConfigLoader(String dir) {
        this.dir = dir;
    }

    public void init() {
        try {
            String content =
                    StreamUtils.copyToString((InputStream) this.getClass().getClassLoader().getResource(dir).getContent(), Charset.forName("utf-8"));
            YamlReader reader = new YamlReader(content);

            Object object = reader.read();
            JSONObject config = JSONObject.parseObject(JSONObject.toJSONString(object));
            for (String key : config.keySet()) {
                Constants.urlMap.put(key, config.getString(key));
            }
        } catch (Exception e) {
            throw new RuntimeException("load config failed:" +dir, e);
        }
        log.info("load config success ,config is :{}", JsonUtils.toJson(Constants.urlMap));
    }
}

config/config.yaml 文件裏的配置, 好比:
zk: ${hbase.zookeeper.address}

改形成新工程以後,因爲 yaml 文件裏的引用變量好比 ${hbase.zookeeper.address} 已經沒法讀取,所以,須要改形成新的方式讀取環境變量。

考慮到 S 的任務所使用到的環境依賴基本已經齊全,很小几率會再添加一項。所以,打算改形成不那麼靈活但足夠清晰的方式。直接將 zk 做爲 EnvConfigLoader 的實例變量注入,省去了讀 yaml 文件的步驟。

@Slf4j
public class EnvConfigLoader {

    @Setter
    private String zk;

    public void init() {
        Constants.urlMap.put("zk", zk);
        log.info("load config success , config is :{}", JsonUtils.toJson(Constants.urlMap));
    }
}

折騰到凌晨一點,終於可以看到,任務在正確消費消息了。階段性的重大進展! 奇怪的是,消息消費的任務日誌沒有打出來 。先睡覺吧。

日誌

次日一大早,就去找東順排查日誌爲何沒找到。東順在一個 home_IS_UNDEFINED 的目錄下找到了消息消費的日誌文件。 日誌路徑的配置有問題。 按照他的指點,導入了標準的 XML 日誌配置,在指望的目錄打印了任務處理日誌。略開懷。

可錯誤日誌沒打出來。這也是要命的事情。在發佈線上的過程當中,若沒有錯誤日誌的提醒,那是冒着槍林彈雨的衝鋒,是容易中彈身亡的。

想起東順以前提到:能夠把原來的日誌配置文件直接拷貝到新工程的配置文件裏。錯誤日誌終於打出來了! 開心 !~~ 又前進了一步,more closed to success。

打印日誌到本地磁盤以後,還要上報到公司內部的日誌平臺上,方便查看多臺服務器的日誌。照葫蘆畫瓢,折騰了下,搞定了。喜。

簡化

至此,新工程的總體和主要部分沒問題了。還須要作一些簡化,好比去掉一些無用的模塊和文件,優化 pom 裏的 jar 引用等,保持工程的簡潔與乾淨,沒有贅餘。

需求支持

在新工程發佈以前,有兩個項目已經快接近尾聲,須要在 trade-sync 作一個改動支持。一個改動很小,一個改動略大。若是等 trade-sync 改造上線以後再上線,恐怕這兩個項目都要被延誤。怎麼辦呢 ?

決定: 先在老的系統上改,隨老的系統先發布; 而後再遷移到新的工程裏,這些改動所涉及的任務從新再回歸一遍。有個擔憂,若是把這些改動複製到新的工程裏,恐怕容易有遺漏。所幸,使用 git merge 命令,能夠很方便地將改動從老的上面挪到新的工程上。


發佈準備

接下來就要考慮發佈了。

CR

工程改動太多了,有點失控的感受。 在發佈以前,找幾位有經驗的同窗幫忙一塊兒 check 下是明智的選擇,也是必經的流程。一位是一直幫我排查 QA 同步問題的子傑同窗, 一位是見識比較廣能力不錯的王立同窗,由於他做爲後端同窗解決了react 容器部署的問題,讓 S 的新界面又從新問世啦!靠譜,厲害!還有一位是個人有伴水王,也是很踏實的。


業務迴歸

CR 的同時,也要驗證這個工程是否能保證原有的任務都能正常進行。

前面談到, 訂單同步使得搜索和詳情的任務都是 OK 的,也就是最重要的任務沒問題;

有些任務是與第三方交互的,在 QA 是沒法驗證的。 好在:這個工程裏絕大部分都是訪問 DB, ES, HBase 的組件,絕大多數的業務邏輯都在配置的任務裏。能夠說是「將基礎技術設施與業務邏輯相分離而實現配置化「的典範作法。所以,從基本層面看,只要驗證部分任務, 覆蓋到全部的組件類別, 就能夠看做是驗證了全部任務。

既能夠把這種作法當作一種巧妙的方式,也能夠看做是某種取巧和偷懶。這種方式仍是會有漏網之魚。

虛驚一場

使用新工程部署以後,一直在觀察中,沒有跪過。 有點安心了。 在發佈前晚,忽然發現: 跪掉了。 天 ! 難道還有什麼細坑 ?又得繼續觀察和排查細坑了 ! 恐怕要延期發佈了。

幸虧,當天早上, 有伴告訴我,他重啓過一次,運維同窗也重啓過一次,可是沒啓動成功。 我當即想到,可能他們是用老的 zan 版本啓動的, 由於不兼容致使失敗。我用 zan 的新版本啓動是 OK 的。

很快確認了這一點, 虛驚一場。

廟算幾何

孫子曰:「夫未戰而廟算勝者,得算多也,未戰而廟算不勝者,得算少也;多算勝,少算不勝,而況於無算呼?」

距離計劃發佈時間只有幾個小時了。 這個工程的發佈勝算在 92% 以上, 有 8% 的不肯定性。勝算以下:

  1. 最主要的訂單同步任務是沒有問題的;
  2. 十幾個的任務及子路徑,我驗證了大部分是能夠正確輸出的;
  3. 組件代碼無改動,只是工程結構變了;
  4. 在 QA 和 預發環境運行穩定。

不肯定性以下:

  1. 有一個任務是外部交互的,沒法驗證; 四個任務是邊緣業務,不太好構造測試用例; 但這些任務所使用的組件,都在其餘被驗證過的任務中使用過了,所以,理論上也應該是間接被驗證了;實際上是有點懶,結果是受了懲罰。
  2. 引入了 youzan-boot 的包,還有之前工程裏的 jar 包,可能存在一些細微的不兼容的坑,未被發現。

無論怎樣, 勝算仍是很大的。在發佈的時候,再細心一些, 應該不會出什麼問題。

決戰時刻

預發的啓示

在預發部署的時候,發現新的進程並無正常起來,必須先手動 kill 掉原來的進程,再部署新的工程,才能讓新進程正常啓動和運行服務。 這一點尤其重要, 不然很容易出問題。

若是能對預發出現的問題敏銳地感知,有時預發的問題真的是神明的指示。 前不久作過的一個項目中,須要作一些交易配置的變動。在預發驗證拼團訂單的時候,訂單狀態沒有正常流轉,經排查日誌發現:預發的請求居然發到線上去了! 聯繫營銷同窗得知,訂單的後續通知,取決於接收最後一個參團訂單的請求的機器所處的環境。好比說吧,拼團發起者的下單請求在 T1 機器, 拼團參團者的下單請求在 T2 機器上。 機器 T1 切換到了新的配置, T2 尚未。 此時, T2 將向營銷發送消息,營銷處理消息完成後,向交易機器 T3 發送回送消息。若是 T3 尚未切新配置,就可能致使走不下去。 發現這個問題後, 仔細思考了下,發如今 下午正常發佈窗口發佈是有風險的。由於若是正好在那個時間段有不少拼團活動,勢必會致使不少拼團訂單的狀態流轉有問題,不只會對商家的交易有影響,還要應對後續複雜麻煩的數據修復。 想一想,仍是辛苦一點,凌晨發佈好了, 此時拼團活動極少, 且有更多時間來驗證項目改動和迴歸業務。

通過溝通,決定在凌晨發佈。安全上線。

發佈文檔

因爲要趕在新進程起來以前手動 kill 老進程,這個時機得把握好, 爲了不誤操做,臨陣手忙腳亂,所以,必要寫個發佈文檔, 寫清楚每個步驟要執行的命令, 在真正發佈的時候,只要簡單的複製粘貼就能夠了。

原本想把這些命令寫成一個腳本,但是 kill 老進程的執行要切換用戶,一時間沒有太多時間調試這個,且要執行的批量命令也很少, 所以,仍是直接複製粘貼了。好在發佈的時候,機器的編號是逐漸遞增的,能夠預測每批次發哪幾臺機器, 這就容易多了:只要在每批次發佈以前,先 kill 掉將要發佈的機器的老進程便可。

會影響線上服務麼? 因爲還有其餘服務器在處理消息,且凌晨的消息量極少,所以 kill 幾臺機器的進程不會對線上服務有影響。

單測

寫好發佈文檔以後,已經 十一點半了。 該提發佈申請了。

在提發佈申請以前,得先運行並單測所有經過。到單測平臺上運行了下,發現報錯: groovy 與 spock-core 的版本不兼容。

鬱悶了。在本地運行是 OK 的,爲啥在這個節骨眼報錯了。 看了下工程的配置,仍是比較老的版本。想一想能夠升級到較新的版本,對任務運行應該沒有影響。因而從核心工程拷貝了更新的版本號,並修復了一個單測文件。

爲了簡單,根據報錯只把 groovy 的版本升到了 2.0.1 , —— 給本身買了個坑。在程序的世界裏,因果命中註定。

小插曲

忽然想到, 除了 S ,還有一個附屬應用 s, 代碼與 S 相同 ,但只運行對比任務。嗯, 這個應用也要發佈, 也在預發驗證下。

我在 QA 也部署了應用 s ,可啓動日誌顯示:訪問交易配置表報錯了:用戶名被拒絕。這是怎麼回事呢? 在發佈以前,有一些配置變動我提交了。我想到應該是運維同窗更新過,不會有問題。 QA 無法驗證, 只好上預發驗證了。

因而,我在預發也部署了 s 應用。啓動日誌沒報錯,可也沒消費日誌。想了想,也許以前就沒有吧。 應該是 OK 的,就作發佈前的準備去了。

忽然被拉到一個羣裏,是預發交易配置庫訪問出錯排查。因爲我集中精力在準備發佈,所以對這個並未投以太多關注。但羣裏好像說是比較嚴重的事情,堅持要查明白,彷佛說我故意配錯了用戶名和密碼,以至於訪問到錯誤的地方,險些形成安全事故,還連累了不少同窗耗費時間來查問題。可我只是提交了被別人改動的配置(而且我相信是運維同窗改動且應該是正確的),並沒作出格的事情。難道,我一不留神就犯下了錯誤 ?

事情原委是:DBA 同窗楊大俠監控到交易配置庫有大量訪問錯誤,並且還來自於不一樣的機房,認爲這是很大的不合理。初步排查到,訪問出錯來自於預發的 s 應用。這有什麼關聯呢? 我一時也有點懵逼,彷彿處於雲山霧繞。

####&amp;####

我提交了發佈申請,開始發佈 s 應用。未料,線上也報錯了。這可奇怪了,我對比了下 S 與 s 的 交易配置表的用戶名和密碼,徹底同樣的啊 ! 在 跳板機上用 mysql 鏈接了下,也是通的; S 在預發部署也沒報錯,這可奇怪了。

楊大俠提醒: DB 鏈接的 jdbcURL中有 &amp; 這樣的字符。 我忽然想到了, 在 QA 遇到過這個問題,由於高版本的 mysql 不支持這個老的語法,須要將這個變成 & 自己。

哪裏還藏有 &amp; 這個字符呢 ? 從新再check 了下 s 應用的配置。 發現,交易配置表的配置有兩處,其中一處是徹底同樣的,但還有一處。 重複出現的 DB 配置,真坑啊!

修改以後,就沒有報錯了。DBA 監控也沒有報錯了。 排查這個錯誤耗費了將近三個小時。發佈完 s 應用後,已經三點了。

Bean沒有找到

S 應用的發佈彷佛順利一些。發了幾臺,沒有報 DB 訪問錯誤,或者其餘奇怪的錯誤。

四點半了, 剛發了幾臺機器,發現有錯誤: RefundBizNsqInput 的 bean 找不到,任務啓動報錯。這個任務是消費退款消息,寫入退款數據,供訂單導出來計算退款狀態及金額的。若是這個數據有誤,可能會影響訂單狀態的展現,誤導商家發貨。

心裏有點崩潰。 這可怎麼辦呢? 繼續發佈完成 ? 這樣會致使這個任務大量報錯, 退款消息沒法消費, 引發上述問題, 形成故障; 若是暫停發佈,等待下午發佈,一則如今新老混布有較大風險,二則下午發佈風險更大; 從新發布,已經快到 5 點的發佈截止窗口了,稍有延遲,就要走緊急發佈了。

思前想後,仍是趁這會清淨,趕忙發完吧。因而,我緊急看了下代碼,發現 RefundBizNsqInput 不在組件自動 scan 的包路徑下。 因而將這個任務涉及的組件類都移到了能夠被自動掃描組件的路徑下,修復了下單測。此刻,若是要再驗證 OK 再發布的話,恐怕會耗時太長。 因而,我作了個大膽的決定,不驗證就直接發佈。由於只是經過 IDE 的重構功能挪了下包路徑,理論上是不會有問題的。 其實內心仍是有點虛的。有時,直覺很重要,雖然它來自於大量經驗的積累;當機立斷也很重要。

想定,取消了以前的發佈單,聯繫運維同窗,幫忙從新開了個緊急發佈的綠燈, 從新開始發佈。幸運的是,此次沒有再報錯誤日誌。因而,我按照寫好的發佈文檔,一我的在這靜靜的天亮時分,循序漸進地開始發佈, 一直髮了兩個小時,到七點半多才發完,一如 08 年踏雪歸來的感受。

反思: 若是在 QA 有驗證那個退款消息的任務, 就不會出現這個尷尬的局面了。由於這個任務的消息處理,須要加載一個自定義的 消息接收器,而這個沒有被覆蓋到。 這是一條漏網之魚。


尾聲

電子發票同步

正要鳴金收兵,忽現新軍情:電子發票索引同步的一隊小騎兵,趁我睏倦之時,偷襲過來,想來個以逸待勞。任務裏的一段 groovy 腳本沒法執行。有幾條消息就出錯幾條。得趕忙解決,否則線上又要報問題了。

排查這個錯誤,有點尷尬。 錯誤日誌只打印了: failed to execute 。。。 啥信息也沒有。 我總不可能添加一行日誌, 再發布一次吧。近乎崩潰。怎麼辦怎麼辦 ? 掃了一眼腳本,有個奇怪的格式化日期的變量彷佛沒定義。想用另外一種先替換看看。沒效果。試來試去,沒效果。

此刻,意識有點模糊,有點扛不住了。但是又不能就此睡去。 怎麼辦 ? 思來想去,只好打擾一下團隊同窗了。 叫醒了三位懂些 groovy 的同窗,幫忙一塊兒排查下。

孔鵬同窗提醒說,在本地運行下這個腳本。 我立刻想到了,能夠把消息和腳本放到本地工程裏運行下,看看哪裏報錯。那個被懷疑的變量也找到了定義的地方。在本地運行是經過的。 這可以讓人有點摸不着頭腦了。 天已經亮了,八點多了。

有同窗建議說,回滾吧。但是,回滾的代價太大了。 花了一整晚,終於將老的工程遷移到新的工程, 難道要由於一個小的問題,再滾回到原來的 ? 且新的工程回滾到老的,也是有比較大的風險的,發佈也要通過一系列比較繁瑣的操做,容易出錯。 我寧肯背一個 P4 故障,也要把這個問題解決掉。已經沒有退路了。

忽然靈光一閃,能夠在預發起相同的任務,而後加調試日誌,在預發看看是什麼緣故 。 燃起了新的但願。

用最後的精力折騰了一下, 發現報 unable to solve groovy.json.JsonSlurper 。 我覺得是沒有 import ,所以加了一行 import 。但是仍是報錯。 孔鵬同窗突然在羣裏說, JsonSlurper 這個類沒有找到啊,且最好把 groovy-all 也引用進去吧。關鍵的一擊啊 ! 我立刻去工程裏看了下,groovy 2.0.8 才支持 JsonSlurper ,而我以前爲了單測經過,只用了 groovy 2.0.1 。 細心的讀者應該注意到,前面跑單測的時候,我把 groovy 的版本改爲了 2.0.1 。 因果的命中註定 ,是說,在你寫下這行代碼或配置的時候,命運已經註定了,只待前來認領。要慎重啊!

當即修改,部署到預發, 解決了。 耶 !!

線上消費出錯怎麼辦呢 ? 先用預發的任務消費線上的消息吧,確保後續的數據都寫入 OK , 待明天作個優化後,再切回到線上的任務消費。原來預發能夠做爲線上的 「備胎」 啊!

反思: 不用說,這個任務也沒回歸到,由於很邊緣。 然而,這個任務引用了一個類,依賴更高版本的 groovy ,是個局部細節問題,沒有覆蓋到。 看來, 凡是有疏忽,必受懲罰。 老天爺的懲罰仍是比較輕的: 照這樣算下來,勝算大抵只有 80% 左右。

終於能夠碎覺了。 emm.... 別打擾我。

監控統計

下午來到公司, 王爺 跟我說, S 的監控統計不對勁, 曲線值很低,跟業務量徹底不匹配。我想,多是日誌平臺又出問題了 ? 以前間歇性也會這樣。但王爺堅持要查一下。因而,我開完一個會以後,就找日誌平臺的同窗蘇蘇一塊兒去查了。

蘇蘇顯然更相信本身抓包看到的數據,說,這個業務量可能就是這樣。但我深知,業務量確定不是這樣,更多是改造工程的過程當中,某個配置有問題,但暫時不知道是哪裏有問題。

不過蘇蘇查底層問題仍是頗有章法的,脾氣也不錯,提及批評人的話來也是很溫和。在通過我承認後,在機器上安裝工具,抓包,看監控圖表,發現 在 S 發佈點以後,寫監控統計就一直報錯了。查來查去,發現 S 引用了一個自研輕量級 R 的包,來寫入監控數據, R 則會讀取 S 的一個配置文件,而這個文件的 NSQ 配置是錯誤的。至此,真相大白。

想到以前還沒仔細看過監控統計的代碼,領悟: 每個不清楚的想要暫時跳過的地方, 老天爺都會恩賜一個問題, 逼着你最終弄清楚。


小結

像是走過了一段較長的路。 面對大流量下的大改動的發佈,曾經感受到比較大的壓力。發佈完成以後,感受彷佛沒那麼可怕了。 一切都過去了。

流量似山海,心內亦平川。 日常心就好。

相關文章
相關標籤/搜索