余晟:從軟件設(shè)計(jì)角度看攜號(hào)轉(zhuǎn)網(wǎng)
“攜號(hào)轉(zhuǎn)網(wǎng)”的事情已經(jīng)談了很久很久了,但看看我們四周,真正成功辦理了攜號(hào)轉(zhuǎn)網(wǎng)的人少之又少。即便辦理成功,似乎也有這樣那樣的問題。
那么,到底有什么問題?
網(wǎng)上有不少文章,看起來云山霧罩,語焉不詳,實(shí)在難以令人滿意。身處 IT 行業(yè),凡事都應(yīng)該擺事實(shí)講道理,能說得清楚。雖然我沒做過移動(dòng)網(wǎng)絡(luò)和運(yùn)營(yíng)商的相關(guān)業(yè)務(wù),但查查資料還是能得到不少信息。“攜號(hào)轉(zhuǎn)網(wǎng)”之所以難辦,似乎不只是運(yùn)營(yíng)商偷懶,還有技術(shù)上的難點(diǎn)。如果從軟件設(shè)計(jì)的角度來看看攜號(hào)轉(zhuǎn)網(wǎng)這回事,應(yīng)當(dāng)會(huì)有許多新的發(fā)現(xiàn)。
攜號(hào)轉(zhuǎn)網(wǎng)的問題其實(shí)在世界上普遍存在,它有個(gè)專門的名稱叫 Mobile Number Portability(MNP,移動(dòng)號(hào)碼遷移),其中主要涉及三個(gè)概念:原運(yùn)營(yíng)商(donor)、新運(yùn)營(yíng)商(recipient)、轉(zhuǎn)網(wǎng)需求(number portability request,NPR)。對(duì)應(yīng)的,它的技術(shù)方案也是現(xiàn)成的,主要有兩種技術(shù)方案。
***種是美國(guó)、歐洲以及國(guó)際通行的方案,叫 recipient-led。用戶在轉(zhuǎn)網(wǎng)時(shí),先向新運(yùn)營(yíng)商提出申請(qǐng),然后新運(yùn)營(yíng)商會(huì)聯(lián)系原運(yùn)營(yíng)商,經(jīng)過數(shù)據(jù)校驗(yàn)之后完成資料轉(zhuǎn)移,將原號(hào)碼“調(diào)過來”。
第二種是英國(guó)和印度用的方案,叫 donor-led。用戶在轉(zhuǎn)網(wǎng)時(shí),先向原運(yùn)營(yíng)商提出申請(qǐng),獲得對(duì)應(yīng)代碼(英國(guó)叫 PAC,porting authorisation code,印度叫 UPC,unique porting code)之后轉(zhuǎn)交給新運(yùn)營(yíng)商,新運(yùn)營(yíng)商據(jù)此完成轉(zhuǎn)網(wǎng)。
第二種方案雖然看起來麻煩,但可以避免欺騙,因?yàn)樵\(yùn)營(yíng)商有機(jī)會(huì)直接核實(shí)號(hào)碼所有者的身份。但是,這也會(huì)導(dǎo)致不公平競(jìng)爭(zhēng),因?yàn)樵\(yùn)營(yíng)商可能會(huì)借此機(jī)會(huì)故意拖延,想各種辦法挽留用戶。
完成了運(yùn)營(yíng)商遷移,還只是遷移了移動(dòng)用戶和運(yùn)營(yíng)商之間的關(guān)系,問題還沒完。要知道,移動(dòng)通訊不只是發(fā)生在運(yùn)營(yíng)商和用戶之間,還發(fā)生在用戶和用戶之間。所以還要讓呼入的電話(其他用戶)知道,這個(gè)號(hào)碼已經(jīng)遷移到了新的運(yùn)營(yíng)商,這樣呼入的電話、發(fā)來的短信才能正確抵達(dá)新運(yùn)營(yíng)商承載的用戶。這種抵達(dá)的專業(yè)叫法是 routing,也就是“路由”。
路由的實(shí)現(xiàn)方式同樣不止一種。國(guó)際和歐洲通行的方案是集中式號(hào)碼庫 CDB(Central Database)。簡(jiǎn)單說,它就像一張大表,詳細(xì)記錄了每個(gè)號(hào)碼屬于哪個(gè)運(yùn)營(yíng)商。相應(yīng)的,每次發(fā)生攜號(hào)轉(zhuǎn)網(wǎng),都必須在 CDB 中新增對(duì)應(yīng)的記錄。運(yùn)營(yíng)商會(huì)維護(hù) CDB 的副本,在外呼電話或者外發(fā)短信時(shí)先查詢它,然后直接聯(lián)系對(duì)應(yīng)號(hào)碼的當(dāng)前運(yùn)營(yíng)商。
根據(jù) RFC3482,這個(gè)查詢叫 ACQ(All Call Query)。合起來的整套方案就叫做 ACQ/CDB routing,美國(guó)用的也是這套方案,只是美國(guó)的管理機(jī)構(gòu)叫 NPAC(Number Porting Administration Center)。
上面說的只是路由方式之一,英國(guó)的攜號(hào)轉(zhuǎn)網(wǎng)流程不同,路由方式同樣獨(dú)樹一幟。英國(guó)沒有采用 ACQ/CDB,即便用戶已經(jīng)攜號(hào)轉(zhuǎn)網(wǎng),呼入的電話或發(fā)來的短信仍然會(huì)首先抵達(dá)原運(yùn)營(yíng)商,原運(yùn)營(yíng)商再將它轉(zhuǎn)發(fā)給新運(yùn)營(yíng)商,這就是“間接路由”(indirect routing),它類似 Unix 中的符號(hào)鏈接。
這種方案避免了對(duì)集中式號(hào)碼庫的依賴,將攜號(hào)轉(zhuǎn)網(wǎng)的信息分散給運(yùn)營(yíng)商各自維護(hù),問題***是增加了無謂傳輸,第二是已經(jīng)轉(zhuǎn)網(wǎng)的用戶仍然無法擺脫對(duì)原運(yùn)營(yíng)商的依賴——所謂“打斷骨頭連著筋”,如果原運(yùn)營(yíng)商故障或者倒閉,已經(jīng)轉(zhuǎn)網(wǎng)的用戶仍然會(huì)受影響,這樣用戶可能很難理解。
現(xiàn)在來說國(guó)內(nèi)移動(dòng)運(yùn)營(yíng)方案。按照目前國(guó)內(nèi)運(yùn)營(yíng)商公布的攜號(hào)轉(zhuǎn)網(wǎng)流程,用戶攜號(hào)轉(zhuǎn)網(wǎng)時(shí),必須先向當(dāng)前運(yùn)營(yíng)商咨詢資格,并獲得授權(quán)碼,然后才能到新運(yùn)營(yíng)商處辦理轉(zhuǎn)入手續(xù)。據(jù)此可以猜測(cè)出,國(guó)內(nèi)應(yīng)當(dāng)采用的是 donor-led 方案。不過,因?yàn)閲?guó)內(nèi)的手機(jī)號(hào)可能還有捆綁套餐,轉(zhuǎn)網(wǎng)時(shí)需要進(jìn)行復(fù)雜的業(yè)務(wù)確認(rèn)。通過詢問辦理過攜號(hào)轉(zhuǎn)網(wǎng)的伙伴得知,這個(gè)“復(fù)雜的業(yè)務(wù)確認(rèn)”過程,恰恰是原運(yùn)營(yíng)商極力挽留用戶的過程。
好玩的是,雖然轉(zhuǎn)網(wǎng)是 donor-led 方案,而且國(guó)內(nèi)之前似乎是沒有集中式數(shù)據(jù)庫的。這個(gè)事情也不難理解,很長(zhǎng)時(shí)間里似乎只有三大運(yùn)營(yíng)商,各運(yùn)營(yíng)商自成一體,工信部更多的是行使管理職能,而沒有基礎(chǔ)系統(tǒng)的建設(shè)和維護(hù)。
攜號(hào)轉(zhuǎn)網(wǎng)對(duì)任何一家運(yùn)營(yíng)商來說,似乎都是“得不償失”的。如果用戶要轉(zhuǎn)出去,相當(dāng)于自己流失了用戶;如果用戶要轉(zhuǎn)進(jìn)來(按照目前看到的報(bào)道,攜號(hào)轉(zhuǎn)網(wǎng)的用戶比例極低),又要額外增加系統(tǒng)建設(shè),其實(shí)相當(dāng)不劃算。所以看來看去,還是工信部牽頭最合適,也最有可能。
按照我看到的技術(shù)文檔,現(xiàn)在我國(guó)正在采用類似 ACQ/CDB 的方案來完成轉(zhuǎn)網(wǎng)用戶的路由。具體來說,工信部會(huì)維護(hù)統(tǒng)一的中心攜號(hào)轉(zhuǎn)網(wǎng)數(shù)據(jù)庫(CNPDB),還有管理全國(guó) NP 業(yè)務(wù)中心 CSMS。聯(lián)通、電信、移動(dòng)三家會(huì)維護(hù)各自的 LNPDB 和 LSMS,數(shù)據(jù)與 CNPDB 保持一致。
中國(guó)聯(lián)通攜號(hào)系統(tǒng)架構(gòu)。來源:張偉強(qiáng),杜忠?guī)r,李嵩泉,肖祿《移動(dòng)號(hào)碼攜帶核心網(wǎng)部署方案探討》
用戶每次外呼時(shí),運(yùn)營(yíng)商先查詢自己的 LNPDB,判斷外呼號(hào)碼對(duì)應(yīng)的運(yùn)營(yíng)商(進(jìn)行 NP 查詢),然后將外呼信號(hào)做對(duì)應(yīng)路由。整套技術(shù)方案看起來沒有問題,但是之前并沒有集中式的數(shù)據(jù)庫,所以 CNPDB 的建設(shè),以及整套流程的理順都需要時(shí)間。
運(yùn)營(yíng)商呼叫流程。來源:張偉強(qiáng),杜忠?guī)r,李嵩泉,肖祿《移動(dòng)號(hào)碼攜帶核心網(wǎng)部署方案探討》
那么目前,攜號(hào)轉(zhuǎn)網(wǎng)遇到的***問題是什么呢?我覺得是短信的路由問題。這一點(diǎn)也被許多攜號(hào)轉(zhuǎn)網(wǎng)者的經(jīng)歷所證實(shí)——客服會(huì)告知,轉(zhuǎn)網(wǎng)之后許多短信可能收不到了。為什么會(huì)這樣呢?
目前大量的短信服務(wù)提供商判斷用戶所屬的運(yùn)營(yíng)商時(shí),完全是按照線下約定的規(guī)則。比如“130 開頭是聯(lián)通的,135-139 開頭是移動(dòng)的,189 開頭是電信的”。短信服務(wù)商在收到短信數(shù)據(jù)包之后,會(huì)首先按照號(hào)段把任務(wù)分開,對(duì)接到不同的運(yùn)營(yíng)商通道進(jìn)行發(fā)送。對(duì)于攜號(hào)轉(zhuǎn)網(wǎng)的用戶,會(huì)被首先按照號(hào)碼分配到原有的運(yùn)營(yíng)商通道,而該運(yùn)營(yíng)商已經(jīng)不負(fù)責(zé)該用戶了,短信就無法發(fā)送——當(dāng)然反過來看,它也可以屏蔽大部分垃圾短信。
這個(gè)問題在充值時(shí)也存在。許多充值網(wǎng)站會(huì)根據(jù)用戶輸入的手機(jī)號(hào)來自動(dòng)選擇運(yùn)營(yíng)商,它看起來方便,但攜號(hào)換網(wǎng)的用戶也會(huì)出現(xiàn)錯(cuò)誤。此外,在一些需要判斷用戶歸屬運(yùn)營(yíng)商的場(chǎng)合,也會(huì)有同樣問題,如果你輸入的手機(jī)號(hào)“看起來”是聯(lián)通的,其實(shí)已經(jīng)轉(zhuǎn)到了移動(dòng),而系統(tǒng)又是根據(jù)號(hào)段來判斷運(yùn)營(yíng)商的,就會(huì)報(bào)錯(cuò),無法繼續(xù)使用。
如果我們暫時(shí)放下對(duì)運(yùn)營(yíng)商的評(píng)價(jià),單純聚焦在攜號(hào)轉(zhuǎn)網(wǎng)的技術(shù)方案,就會(huì)發(fā)現(xiàn)這其實(shí)是開發(fā)中很常見的問題:資源遷移的要如何設(shè)計(jì)?
狹義的遷移很簡(jiǎn)單,只是 donor(原資源持有方)對(duì) recipient(新資源持有方)做數(shù)據(jù)傳輸而已。但是安全的系統(tǒng)必須要解決一個(gè)問題:如何判斷這種遷移真的可信的?
攜號(hào)轉(zhuǎn)網(wǎng)的 recipient led 方案中,recipient 可以直接發(fā)起資源遷移請(qǐng)求,donor 會(huì)信任這種請(qǐng)求,這看起來足夠簡(jiǎn)單直接,但它有一個(gè)前提條件,運(yùn)營(yíng)商數(shù)量不多,成立門檻很高,追責(zé)也很方便。如果不具備這個(gè)前提條件,資源持有方很多,成立門檻也很低,那么直接由 recipient 向 donor 申請(qǐng)數(shù)據(jù)遷移就會(huì)面臨安全問題。
這個(gè)問題要怎么解決?我們可以想想如今網(wǎng)上流行的 OAuth 是怎么做的?當(dāng) recipient 向 donor 發(fā)出申請(qǐng)時(shí),多了一道“donor 與用戶確認(rèn)”的手續(xù),因?yàn)橛杏脩舻闹苯訁⑴c,就解決了“信任”的問題。
當(dāng)然辦法不止一種,也可以借鑒 donor led 的方案,由用戶先向 donor 獲得許可及驗(yàn)證碼,再完成遷移——實(shí)際上,域名遷移正是采用的這種方案,它解決了“眾多服務(wù)商”環(huán)境下建立信任的問題。
但是只做到這一步,并不算資源遷移方案。稱職的工程師一定不能只看到眼前的這一點(diǎn),還必須做完整的方案,保證遷移完成之后,所有相關(guān)的業(yè)務(wù)都保持平穩(wěn)順利,不受影響。你看了上面的 ACQ/CDB 方案,大概會(huì)覺得“這不是顯然的事”嘛,但現(xiàn)實(shí)未必如此,這是有無數(shù)痛苦教訓(xùn)的。
許多年前我開發(fā)過電商的物流系統(tǒng)。有一天,業(yè)務(wù)的人問:“為了節(jié)省成本,同一個(gè)收件人的兩件貨品,是不是可以合并發(fā)貨?” 負(fù)責(zé)開發(fā)的程序員一聽:“這個(gè)沒問題呀,這個(gè)簡(jiǎn)單,我馬上就可以做好”。
沒兩天真的就開發(fā)完成了,揀貨、打包、出倉、掛號(hào)分配和錄入,確實(shí)都沒有問題,于是順利上線。剛開始一切正常,他倆正打算為這個(gè)”透明“的方案邀功,前方傳來大量投訴,相關(guān)人員叫苦不迭。
一問才發(fā)現(xiàn),這個(gè)工程師根本沒考慮異常情況。兩件貨可以拼單,那么三件貨,四件貨呢?合并的最小單位到底是貨物還是訂單?如果用戶要發(fā)票,到底是開一張票還是兩張票?和供應(yīng)商結(jié)算的時(shí)候,運(yùn)費(fèi)怎么分?jǐn)??最麻煩的是逆向流?mdash;—如果用戶要針對(duì)其中某件商品退款或者退貨,到底要如何操作?費(fèi)用又如何計(jì)算?
輕率決定的后果就是,一定要踩了大坑才知道,“合并發(fā)貨”真不是看上去那么簡(jiǎn)單,遠(yuǎn)比想象的要麻煩得多。它也不是程序員或者小產(chǎn)品經(jīng)理能搞定的,還必須加上物流、財(cái)務(wù)等等一大圈人。程序員想當(dāng)然“沒問題”,造成了很多問題,給所有人都挖了個(gè)大坑……
回到數(shù)據(jù)遷移問題,我見過好些數(shù)據(jù)遷移方案,完全就是想當(dāng)然,“我知道這里數(shù)據(jù)遷走了”,拍拍腦袋就做了,拍拍屁股就遷了。設(shè)計(jì)者根本不考慮其他人,完全沒想過“其他人或業(yè)務(wù)知不知道數(shù)據(jù)遷走了”,也不關(guān)心其他人或其它業(yè)務(wù)后來會(huì)怎么辦。
在“攜號(hào)轉(zhuǎn)網(wǎng)”的方案里,要解決這個(gè)問題,就必須保持?jǐn)?shù)據(jù)的同步更新。一種方案是提供集中式記錄(ACQ/CDB)方案,這種方案職責(zé)清晰,能保持通話路徑最短,但是對(duì)中心節(jié)點(diǎn)的穩(wěn)定性、響應(yīng)速度、復(fù)雜能力都提出了很高的要求。
另一種 indirect routing 在某種意義上可以稱為“分布式”方案,即必須通過原服務(wù)商來中轉(zhuǎn),這時(shí)候轉(zhuǎn)網(wǎng)信息碎片其實(shí)是由運(yùn)營(yíng)商各自維護(hù)的。這種方案不需要花大力氣建設(shè)中心節(jié)點(diǎn),缺點(diǎn)則是職責(zé)不清晰,多了不必要的中轉(zhuǎn),已遷移用戶仍然會(huì)受原運(yùn)營(yíng)商服務(wù)質(zhì)量的影響。
中轉(zhuǎn)還會(huì)帶來其它問題:如果用戶多次遷移就會(huì)形成“中轉(zhuǎn)鏈條”,鏈條一長(zhǎng),不但影響效率,排查問題也異常麻煩。這還沒完,如果設(shè)計(jì)不當(dāng)還可能形成環(huán)路……
***我們不妨再深挖一點(diǎn)——所謂“攜號(hào)轉(zhuǎn)網(wǎng)”,真正跳出來看,核心就是一個(gè)函數(shù)問題。
函數(shù)最簡(jiǎn)單的方式是 f(x) = y,這大家都知道。對(duì)攜號(hào)轉(zhuǎn)網(wǎng)來說,關(guān)鍵也是根據(jù)手機(jī)號(hào)查詢運(yùn)營(yíng)商,它可以看作 f(x) = y,其中 x 就是“具體的手機(jī)號(hào)”,y 就是“運(yùn)營(yíng)商”。只要掌握了這個(gè)信息,其它都好辦。
雖然大家都默認(rèn)有 f(x) = y 這個(gè)函數(shù),但許多人也知道函數(shù)f的內(nèi)部到底是怎么做的,而且這個(gè)函數(shù)并沒有官方版本,所以基本所有人都自己實(shí)現(xiàn)了一遍:130~133 號(hào)段是聯(lián)通,135~139 號(hào)段是移動(dòng),189 號(hào)段是電信……
同時(shí)我們也知道,軟件設(shè)計(jì)中提倡“暴露接口而不暴露實(shí)現(xiàn)”。為什么呢?因?yàn)榻涌谑顷P(guān)于抽象行為的定義,比如“輸入手機(jī)號(hào),得到運(yùn)營(yíng)商”就是抽象行為,它包裝了 f(x) = y,至于哪個(gè)手機(jī)號(hào)(x)對(duì)到哪個(gè)運(yùn)營(yíng)商(y),規(guī)則可能不停變化,甚至有一些特例。不過這都不要緊,因?yàn)橥獠坎槐刂兰?xì)節(jié),只要放心調(diào)用這個(gè)接口既可以,外部原有業(yè)務(wù)流程照跑。相反,如果暴露的是實(shí)現(xiàn),你就需要在各處不停更新號(hào)段規(guī)則,如果遇上攜號(hào)轉(zhuǎn)網(wǎng)這種特例,維護(hù)難度更是上了幾層樓。
那么“根據(jù)手機(jī)號(hào)查詢運(yùn)營(yíng)商”的功能,為什么暴露的是實(shí)現(xiàn)而不是接口呢?這大概有歷史原因,缺乏頂層設(shè)計(jì),一開始沒有權(quán)威公用接口,實(shí)現(xiàn)這種接口要承受巨大的負(fù)載,技術(shù)上有挑戰(zhàn)……
所以,早期許多技術(shù)問題,確實(shí)都是采用“線下共識(shí)”來解決的。比如早期不少電商的訂單號(hào),上面就承載了很多信息,單純看訂單號(hào)就可以識(shí)別出下單日期、所屬倉庫、商品種類等等。
不過現(xiàn)在,隨著軟件的復(fù)雜度越來越高,隨時(shí)在線變得越來越普遍,這種“線下共識(shí)”已經(jīng)越來越多地被替代了。不信你可以看看各大電商的訂單號(hào),早年還可以從中看出下單日期、當(dāng)日序號(hào)等等,但是現(xiàn)在,已經(jīng)基本看不出任何編號(hào)規(guī)律了。但是手機(jī)號(hào)處理起來很麻煩,手機(jī)號(hào)綁定的線下規(guī)則很多,不只有判斷運(yùn)營(yíng)商,還有歸屬地……
總之,從攜號(hào)轉(zhuǎn)網(wǎng)這么個(gè)“簡(jiǎn)單直觀”的事情中我們可以看到,軟件設(shè)計(jì)要解決的問題原型往往簡(jiǎn)單,但這些問題往往牽連眾多因素,而且沒有放之四海而皆準(zhǔn)的方案,不同的方案各有利弊,必須根據(jù)具體環(huán)境來取舍和抉擇——許多時(shí)候,這恰恰是架構(gòu)設(shè)計(jì)中最重要的因素,也是架構(gòu)人才的核心競(jìng)爭(zhēng)力。
P.S. 高春輝、胡姝琦對(duì)本文亦有貢獻(xiàn),在此表示感謝。



























