靜兒歷時8個月終於如願回歸寫代碼的生活。希望這8個月的成長能對自己的碼磚起到一定的指導意義。下面就介紹一下靜兒回歸后的第一次碼磚經歷。
以下是靜兒的方案設計:
01
—
方案設計
背景:

DNS綁定會有一定的失敗率。失敗原因包括但不僅限於:
-
dnsupdate服務只進行基本的ip和域名唯一對應合法性檢查:add操作,如果已存在域名的正解或ip的反解,則會更新失敗。
-
dnsupdate服務由於各種原因造成的不可用或處理錯誤
針對上面情況需要做一個補單
調查:
dnsupdate域名更新服務API接口說明 對此文檔,針對dns.add,返回結果舉例如下:
XXXXX
此例子來源於線上日志,新美大日志中心地址:
XXXXX
其中返回值中有個status='init'字段。通過向雲計算部門XXX同學了解,對於dns綁定和解綁,都是異步操作,先提交任務,然后再查詢任務執行狀態。實際執行線上目前要跟X台dns服務器更新數據。校驗不通過,狀態碼是400;在狀態碼200的情況下,如果能拿到taskid,status,就說明任務是校驗通過,理論上應該執行成功的,后來查詢到status時failed,可能是dns服務器異常,或者已經有了相關記錄。
自身優化:
XXX里的
public boolean dnsAction(String action, String ip, String host, String domain) 和
public void add(String ip, String name, String host)
public void delete(String ip, String name, String host)
做了同樣的工作,但是dnsAction沒有cat埋點,統一用dns.add和dns.delete,並添加cat埋點。
XXX的封裝,這個封裝判斷成功的依據是可以獲取到更新dns的request id。但是作為補單來說可以做更細粒度的處理,此處需要優化。
技術調研:
-
MQ:
因為hulk-config項目中已經使用了mafka,根據項目穩定需要盡量減少依賴的原則,所以一開始考慮使用mafka做延時消息隊列,調研結果支持延時時間區間沒有確認是否能符合要求。
| 延遲消息隊列 |
發展歷史 |
是否BG隔離 |
部署機房 |
延遲精度 |
是否考慮時鍾漂移 |
支持延時時間區間 |
線上接入業務 |
線上接入量 |
KV雙寫 |
單點故障 |
是否有容災演練 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| mafka延遲隊列delayserver |
2016年中旬至今 |
是,每個BG都有單獨集群 |
北京側:dx,yf,gh均有部署 上海側:gq |
100ms |
考慮了 |
5s-7天 |
金融支付,到餐退款,外賣等均有接入 |
600+topic 15000+qps |
無 |
有,優化方案已開發完畢 |
有 |
| rabbitmq延遲隊列 koala |
2016年底至今 |
只接入外賣業務 |
dx處於使用狀態 yf冷備 |
1s |
未考慮 |
不限制 |
外賣配送業務 |
共有105個隊列 10000+qps |
有 |
無 |
有 |
beanstalked無團隊維護,技術團隊在主推mafka,逐漸淘汰rabbitmq。所以如果考慮支持延時時間區間不符合要求采用MQ代替方案。
-
Redis:
因為實際上只需要一個隊列,延遲可以控制客戶端的消費頻率來實現。而redis里有List結構來實現消息隊列,理論上是可以實現的,而項目中已經依賴了squirrel,不會產生新的依賴。之前在樂視做過redis cluster的map結構性能壓測,在一個map超過萬級的時候,性能惡化非常嚴重。list同map一樣,也存在集群的性能優勢不能發揮作用的問題。性能方面有待測試(Mark),目前問題不大,數據量增大可用多個list橫向擴展解決,還避免了MQ的分片上限影響擴展性。
-
下游支持
涉及公司內部信息,此處省略
補單處理:
-
邏輯梳理
針對調用XXXX,結果分為下面幾種情況:
*注意:第三方 的報警設置,加上,請求url,參數,返回參數。若cat無法支持此種報警策略,可考慮自定義大象。

總體采用mafka延時隊列實現
1>查詢時間間隔:(1)5s,(2)5s,(3)5s,(4)5s
最長查詢時間20s,設置MCC開關控制,最大重試4次
2>補單時間間隔:(1)5s,(2)10s,(3)60s,(4)10*60s,(5)20*60s,(6)30*60s
最長補單時間1小時,設置MCC開關控制,最大重試6次
3>流控初期先用開關控制,后續可以考慮做熔斷。
4>需要在XXXX表里做標記
-
CAT埋點方案
調用dnsupdate服務前后埋點記錄輸入和輸出
后續TODO:
-
出一個DNS調用數據,預估需要DNS服務要支持的容量,看是否需要推動DNS服務的擴容、性能優化。
-
需要DNS服務的兄弟給出細化的錯誤原因
02
—
開發
代碼開發很簡單,靜兒整個開發階段(不算測試和聯調)實際上耗時兩小時。這里主要談談遇到的問題和一些思考。
程序無法啟動
在開發過程中最不願意遇到的問題就是環境問題。靜兒代碼開發完了,想啟動驗證效果,程序啟動不起來。在啟動之前
-
靜兒新拿到服務,之前沒有啟動過
-
做了一些修改
-
其他同事用的是外部配置的jetty啟動,我直接在pom文件里添加了個jetty控件啟動的
-
確定了其他同學拿到代碼沒有做任何修改直接可以啟動
這時候我是不是應該慌里慌張的新拉一下原始分支試一試是不是自己改出來的問題?答案是“No”,為什么呢?
從報錯來看,日志堆棧最上面是最表面現象,最下面是直接原因。表面現象是數據庫連接問題,最下面有定位到一個點評框架的代碼。直接來看和我新寫的代碼沒有關系。
之所以選用mafka是因為項目本來就用到了,所以我新開發的代碼不存在引入新的中間件問題。新配置了一個遠程調用的服務,是啟動時加載的,但是原來也是有調用,調用方式不同,並未引入新的jar包,也不存在少引用的問題。
錯誤和代碼之間沒有直接關系,先不考慮新修改代碼的影響。直接根據堆棧信息找錯誤原因。
堆棧里報的最直接的cause是一個NPE(空指針異常),定位了一個報錯代碼位置,但是由於不是直接引用,所以不能點進入定位原因,那就先做一個依賴。依賴后點擊進入一個反解析后的代碼,代碼是使用點評的配置框架。配置需要依賴一個本地文件。
這時候心里的想法是通常這種問題可能和我使用的mac本需要寫入授權有關。找到本地文件的路徑,果然在磁盤上沒有這個問題。所以授權了整個目錄所有權限,重啟還是沒有這個文件。手動創建文件,再次啟動還是同樣錯誤。
這時候想的是:這應該是一個使用這個點評框架的通用問題,美團同事會常遇到這個坑。所以這時候我根據問題去美團的wiki上搜索,果然搜到需要進行一個文件配置,里面要寫內容。
所以我跟一個項目的同事要了他的文件,將內容寫入,啟動成功。
測試用例啟動報錯
程序可以起來了,但是我們是一個后台系統,測試不能點頁面做黑盒測試,我們都是自己寫測試用例做白盒測試。測試用例跑不起來?
報錯ClassDefNotFound,少jar包?引用沖突?問了同一組的哥哥,他那邊沒有任何修改可以正常啟動。先不管這些,少什么加什么,既然正常程序沒有問題,新加的pom引用scope都是test,添加了三個引用,啟動成功,問題是why?
我將自己沒有修改過的原分支在其他地方重新下載一份。將兩個分支的mvn dependency:tree做對比:
發現我手動添加的三個引用
| \- org.codehaus.plexus:plexus-classworlds:jar:2.5.1:compile
[INFO] | | +- org.codehaus.plexus:plexus-utils:jar:3.0.24:compile
[INFO] | | \- org.apache.xbean:xbean-reflect:jar:4.5:compile
在原分支的
com.dianping.squirrel:squirrel-client:jar
這里面做了間接引用。而新分支我添加一個exclusion:

然后直接引用了這個jar包:

問題是:

我沒有exclusion掉cat啊?結果卻成了:


why?
這是maven的傳遞性依賴,具體請參考:https://www.cnblogs.com/wuchanming/p/5403135.html
靜兒的博客近期會進行一些改版,在博客園的文章只有技術干貨,分離出“總結與思考”、“跑題時間”在每次自己個人公眾號上單獨發表。
靜兒個人公眾號:

本期文章:

