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