分散式下的區域問題,讓我們大戰了300回合

前言

我最近參與了公司的一個新專案,需要透過openapi介面把

接入方

的資料,比如:企業、訂單、合同、物流等,同步到我們平臺,然後我們平臺給他們提供金融能力。

由於

我方

對接方

不在同一個城市,為了提高工作效率,雙方進行了多次線上影片溝通。剛開始比較順利,沒想到在溝通企業資訊上傳介面時,介面文件中有個非常不起眼的

企業註冊地id

欄位,讓我們一下子進入了僵局。

到底是怎麼回事呢?

1。地區問題

在我們平臺的

企業表

中有一個

企業註冊地id

欄位,是必填的,使用者在註冊企業的頁面需要選擇一個地區,作為該企業的註冊地,實際上資料庫儲存的是地區的id。

如果該企業註冊成功了,會在企業詳情頁面上展示該地區名稱。當然我們系統的後臺邏輯是先透過

地區id

地區表

反查出地區名稱,然後在使用者介面中展示出來。

為了跟

企業表

保持一致,我方在定義介面文件時,企業註冊地id欄位也做成必填了。

當時的情況是這樣的:我方地區表中有id、地區名稱、國標碼、等級等欄位,但這裡的id,是我方資料庫的主鍵,對接方系統中肯定是沒有的。對接方系統中也有一套地區表,不過id是他們的資料庫id,他們的表中也有地區名稱、國標碼、等級等欄位。

分散式下的區域問題,讓我們大戰了300回合

所以他們系統內部需要經過一番轉換,才能把我們所需的地區id傳給我們。

1。1 持久化本地地區表

其實這個專案我是中途才加入的,之前在處理別的事情,我加入的時候介面文件已經定義好了。

我方跟對接方進行第二次線上溝通的時候,雙方一起過介面文件的細節,包括:介面的作用、每個引數的含義,以及他們是否有值傳過來等等。

其中過到企業資訊上傳介面時,介面文件中有個

企業註冊地id

欄位,對方沒法傳值過來。為了解決這個問題,我方第一版的方案是:

分散式下的區域問題,讓我們大戰了300回合

對接方呼叫我方地區查詢介面,透過多次分頁查詢,最終能獲取我方所有地區資料,落庫到他們本地的地區表。

他們在呼叫我方企業資訊上傳介面之前,先查詢本地的地區表,轉換成我方所需要的地區id。

在討論的過程中,對接方覺得他們也是平臺,不應該做這些額外的事情。所以在那次會議中,雙方針對這個問題,誰也沒有說服誰,最終也沒能達成共識。

後來,我思考了一下,確實這個方案太過理想化了,沒有真正站到使用者的角度思考問題,忽略了很多細節。可能跟文件設計者不對地區表不太熟悉有關係。

1。2 按名稱呼叫地區查詢介面

那次會議當中,我們這邊的幾位同事,短暫的討論了一下。既然對接方不願意接受在他們本地持久化地區表,我們就退而求其次,不要求他們持久化了。這時我們這邊有個同事提出,改成按名稱呼叫地區查詢介面,反查出地區id,具體方案如下:

分散式下的區域問題,讓我們大戰了300回合

這個方案表面上看起來沒有問題,但我之前負責過區域相關功能,我知道,就怕出現如下情況:

如果對接方傳的地區名稱不完整,比如:本來是

成都市

,實際上傳的

成都

。這樣,我們地區查詢介面,需要做模糊匹配,如果併發呼叫介面可能影響介面效能。

如果輸入關鍵字

北京市

,在我們這邊的地區表中,可以找到兩條資料,一條是跟

省級別

一樣的,另一條是跟

市級別

一樣的。到底對應哪條資料呢?

所以我當時把這兩個問題丟擲來了,不建議使用地區名稱查詢。

1。3 按國標碼呼叫地區查詢介面

那個同事聽完之後,也覺得用地區名稱查詢有點不靠譜。他馬上修改方案,改成使用地區的國標碼查詢地區id,具體方案如下:

分散式下的區域問題,讓我們大戰了300回合

由於當時討論時間非常短,我們沒來得及考慮太多,暫且打算用這套方案。

1。4 企業上傳介面入參傳國標碼

過了一會兒,雙方繼續過介面文件,重新討論企業資訊上傳介面中

企業註冊地id

欄位傳值問題。

他們在調企業資訊上傳介面之前,先調一下我們地區查詢介面,查出地區id,入參是國標碼。然後再將這個地區id,在企業資訊上傳介面中傳過來。

對接方仔細聽了我們的方案,猶豫了一下,他們覺得沒有必要再調一次地區查詢介面,雙方都使用國標碼不就行了?

他們的想法是:在企業資訊上傳介面中,入參由

企業註冊地id

改成

企業註冊地國標碼

,由於國標碼是國家統一的唯一編碼,雙方肯定是一樣,能保證資料的一致性。

分散式下的區域問題,讓我們大戰了300回合

2。想起了一個問題

說實話,如果你沒接觸過地區功能的話,大部分人可能會同意這套方案的。

但比較巧合的是我之前正好接觸過類似的功能,當時我突然想起了一個問題:

雙方資料的一致性如何保證?

我們都知道,由於國家的發展,有些城市可能會改名,比如:

襄樊

改成了

襄陽

,另外有時候多個地級市合併成一個市,這樣國標碼會變化,所以國家統計網每年都會調整地區名稱和國標碼。

我方的地區表是兩年之前建立的,資料初始化好之後沒有就更新過。

而對接方不是跟我們在同一時刻初始化的資料,而且他們會定期更新地區資料,這樣就導致了兩邊的資料不一致。如果對接方的業務表單中使用了新加的城市名和國標碼,而這些資訊在我方的地區表中沒有,就無法查詢出我方所需的地區id。

這種情況該怎麼辦?

2。1 雙方同一時刻更新地區表

顯然上面的問題是一個非常棘手的問題,這時候有些小夥伴可能會說:

雙方使用job同一時刻更新地區表

,不就能解決問題了?

分散式下的區域問題,讓我們大戰了300回合

我不太贊成這種方案,主要原因如下:

我方僅跟這個對接方有個同步執行的job,沒問題。但如果還有其他的對接方,也需要呼叫企業資訊上傳介面,是不是也要整一個job,而且還要求大家都同一時刻執行,耦合性太大了。

如果我方和對接方同時執行job,但萬一有任意一方執行失敗了,也會導致資料不一致的情況。如果恰好這時候對接方在呼叫企業資訊上傳介面,會不會出問題?

2。2 以一方的地區資料為準?

上面的雙方同一時刻更新地區表的方案確實有點不靠譜,但有些讀者可能會問,以一方的地區資料為準,另一方把資料同步過來不就行了。具體方案如下:

分散式下的區域問題,讓我們大戰了300回合

這個方案其實跟之前我方給出的第一個方案很相似,已經被對接方拒絕了。站在他們的角度來說,確實沒有必要因為上傳企業資訊,而儲存我們的地區資料。

說實話,即使他們同意了,這種跨公司跨系統的資料一致性問題,也不好保證,因為如果對接方呼叫我們的地區介面失敗了,此時,正好在上傳企業資訊,是不是也有問題?

3。其他解決方案

其實,我們當時為了解決問題,還穿插著討論過這些方案。

3。1 上傳的資料存快照

我當時提出既然是儲存對接方的資料,為啥不能存快照呢?我們可以把資料寫到mongodb,資料格式用json,簡單又高效。我的方案是:

分散式下的區域問題,讓我們大戰了300回合

我們自己的業務資料存到mysql的業務表,而對接方的資料存在mongodb,互不干擾。

看起來,沒有問題。

但是,當時產品說:銀行那邊規定,審查資料時只看我們mysql的業務表,其他的資料來源不看。

好吧,不得不承認銀行惹不起。

3。2 人工更新資料

另外一個同事的想法是,先讓他們呼叫企業資訊上傳介面,如果發現有地區問題,我們手動幫他們調整地區表的資料。

具體方案如下:

分散式下的區域問題,讓我們大戰了300回合

如果呼叫企業資訊上傳介面時,出現地區不存在的情況,則發報警郵件給指定人員。然後,指定人員手動新增或修改相關的地區資料。

這套方案看起來也可以,不過有個比較坑爹的地方就是,就怕在下班或者週末的時候出問題,反正我是不願意去做這個事情的,你願意嗎?

3。3 提供更新介面

除此之外,我們還相關這套方案:對接方在調我們企業資訊上傳介面之前,先調我們地區查詢介面查一下資料是否存在,如果不存在,則儲存地區介面(儲存包括:新增和修改),如果存在,則正常上傳資料。

具體方案如下:

分散式下的區域問題,讓我們大戰了300回合

這個方案還可以簡化一下:

分散式下的區域問題,讓我們大戰了300回合

將查詢並儲存地區的邏輯可以放到企業資訊上傳介面中,這樣對接方肯定非常高興,對他們來說是透明的,地區問題不存在了。

但產品覺得地區是我們的基礎資料,處於安全考慮,不能提供入口給他們修改,不然以後可能會亂套的。

這樣不行,那也不行。我們一下子進入了困境,但為了不影響整體進度,只能先記錄一下問題,然後跳過這個問題,繼續討論其他欄位了。

4。如何解決這個問題?

我當天晚上思考了良久,第二天早上,發現跟我們老大的想法不謀而合。得出的結論是,既然存在差異化,沒辦法避免,我們就要從系統設計上接受差異化。在企業資訊上傳介面中增加兩個欄位:

企業註冊地國標碼

地區名稱

,對接方改成傳入這兩個欄位,具體方案如下:

分散式下的區域問題,讓我們大戰了300回合

在我方的企業表中增加地區名稱欄位,是非必填的,同時把之前的地區id欄位也改成非必填。

對接方在呼叫我方企業資訊上傳介面時,同時傳入地區國標碼和地區名稱。

我方企業資訊上傳介面中判斷,如果透過國標碼能夠找到地區id,則將地區id寫入db,如果找不到,則將地區名稱寫入db。

我們評估了一下影響範圍,在企業表中的地區欄位,只做展示用,沒有修改入口,所以上面的這套方案是可行的。

後來,再次跟對接方線上溝通時,把我們的這套方案告訴他們了,他們非常贊同。

5 總結

雖說這個地區問題,在眾多技術問題中不值得一提。但是我仔細思考了一下,還是有一些寶貴的經驗值得總結一下的,給有需要的小夥伴一個參考。

5。1 要從使用者的角度設計介面

在設計介面文件時,要真正做到從使用者的角度出發。

尤其是像這種openapi介面,定義的引數應該儘量選擇通用的,大家都認可的引數,避免出現我方定製化的引數,比如:地區id。

儘量減少使用者的複雜度,讓他們呼叫介面時更簡單一些。

5。2 技術方案要有包容性

技術方案要有包容性,不是非黑即白,需要有柔性的思想。在分散式環境中,如果去一味地追求資料的強一致性,不會有太好的結果。就像高併發下的商品秒殺系統,如果非要用同步方案去實現,系統最終可能會掛掉,更好的方案其實是改成非同步佇列處理。

我方和對接方都有地區表,資料很難保證完全一致,我們不要為了一致性而一致性,這樣會適得其反。為了工作能夠順利進行下去,必然有一方要妥協,我的建議是openapi介面方做妥協,這種技術方案才夠通用。

5。3 沒有最好的方案,只有最適合的

我方最後的那個方案,其實並沒有完全解決地區id找不到的問題,但是從業務的角度來看,即使沒有地區id,有地區名稱也是一樣的。很顯然,最後的方案是非常適合我們實際業務場景的。

所以沒有最好的方案,只有最適合業務場景的。

5。4 進行有效的溝通

在跟對接方線上溝通時,不要因為某個問題卡殼了,而一直僵持下去。如果當時沒有好的技術方案,可以先選擇暫時跳過這個問題,而溝通其他的內容。後面我們再私下單獨花時間,仔細思考當時的問題,從而能夠提出更合理的方案。

5。5 技術是為業務服務的

本文的這個地區問題,咋一看比較簡單。如果一細想,會發現裡面有點東西。再加上各種外部因素的限制,你會發現分散式的環境中保證地區資料一致性,並不是那麼好實現。

整個過程當中,我們提出了很多種技術方案,有些方案看似可以完美解決問題,但都被我們實際的業務場景給否定了。

技術是為業務服務的,技術雖說非常重要,但是如果離開了業務都是紙上談兵。

原文連結:https://mp。weixin。qq。com/s/WFkavA49UNOFCs_t5ugAtg

作者:蘇三說技術