原理:從費率表到模板化計費的演進與避坑)
簡介這份文檔面向電信運營商業(yè)務(wù)支撐系統(tǒng)的運營管理與設(shè)計人員以及希望理解在線計費機制的技術(shù)學(xué)習者系統(tǒng)講解OCS在線計費系統(tǒng)的計費原理與實現(xiàn)路徑幫助讀者厘清實時計費從概念到落地的關(guān)鍵環(huán)節(jié)。資源包內(nèi)共1個doc文件約1.87MB內(nèi)容按序篇、掃盲篇、計費流程等模塊組織涵蓋計費系統(tǒng)從離線批處理向?qū)崟r處理演進的背景TAG、業(yè)務(wù)用量、費用項、產(chǎn)品、訂購、入帳關(guān)系、模板、策略、事件與子事件等名詞解釋以及預(yù)處理、批價等流程拆解并延伸至計費引擎、數(shù)據(jù)庫、消息中間件等實現(xiàn)組件與安全機制。已有297人學(xué)習適合作為理解OCS工作流程、優(yōu)化計費流程與系統(tǒng)設(shè)計的參考材料。1. 一次通話還沒掛斷錢就已經(jīng)扣完了OCS 到底在背后做了什么你打完一通電話掛機短信還沒到余額已經(jīng)變了。這個“實時”背后并不是簡單的“通話結(jié)束扣錢”而是一套在線計費系統(tǒng)在通話進行中反復(fù)做預(yù)算、授權(quán)、再預(yù)算的循環(huán)。OCSOnline Charging System在線計費系統(tǒng)要解決的核心問題只有一個在用戶還沒消費完之前就判斷他還能消費多少并且保證最終扣的錢和實際用量對得上。這件事聽起來簡單做起來卻牽扯到業(yè)務(wù)用量怎么抽象、費用項怎么組織、定價計劃怎么復(fù)用、預(yù)付費和后付費怎么統(tǒng)一。搞懂 OCS 的計費原理本質(zhì)上是在搞懂一套“先授權(quán)后結(jié)算”的信用控制機制為什么能在線跑起來以及它的抽象層次是怎么一步步演進出來的。這份資料把計費系統(tǒng)從兩張表到 OCS 的演進拆得很細下面按機制層次往下推。2. 計費系統(tǒng)的四次演進為什么費率表最后一定會失控2.1 從兩張表到號碼分析維度爆炸是怎么發(fā)生的最早的計費系統(tǒng)只有兩張表用戶表存余額費率表根據(jù)主被叫歸屬地、主被叫拜訪地四個號碼頭查費率。這個設(shè)計在只有一個號段、一個地區(qū)的時候完全夠用。問題出在號段增長之后一個地區(qū)會有多個號段四個維度組合在一起費率表的記錄數(shù)不是線性增長而是按維度乘積膨脹。更麻煩的是局方調(diào)整費率時需要人工分析每個受影響地區(qū)的每一條記錄改錯一條就是計費事故。常見的實現(xiàn)思路是把“查費率”拆成三步。第一步號碼分析把主被叫的歸屬地、拜訪地號碼頭歸一成地區(qū)號一個地區(qū)的多個號段在號碼分析表里收斂成一條記錄。第二步計費矩陣把一次呼叫拆成基本費、漫游費、長途費三種消費類別每個類別對應(yīng)一個費率索引也就是 ChargeClass根據(jù)地區(qū)號查出該用哪組費率。第三步才是費率表只描述費率本身被計費矩陣引用。這樣改費率只動費率表幾條記錄加號段只動號碼分析表可維護性從“改一處牽全身”變成“各管各的”。這個拆分的關(guān)鍵在于把“維度”和“價格”解耦。號碼分析負責維度歸一計費矩陣負責消費分類費率表負責價格數(shù)值。三層各司其職任何一層的變更不會污染另外兩層。我一般會這么理解這不是簡單的表拆分而是把計費查詢從“一次多維匹配”改成了“三次單維查找”用查詢次數(shù)換維護性。2.2 帳戶抽象與消費類別擴展??顚dN為什么需要獨立帳戶用戶數(shù)增長之后運營商發(fā)現(xiàn)單純降價拉不動消費于是開始做套餐50 元買 500 分鐘長途、10 元買 200 分鐘市話長途時長只能打長途市話時長只能打市話用完再走基本余額。這就引出一個新問題余額不再是單一數(shù)字而是分類型、分用途的多個池子。實現(xiàn)上的做法是把余額從用戶表里抽出來單獨建帳戶表一個用戶可以掛多個帳戶每個帳戶有類型和余額。同時把 ChargeClass 從純粹的費率索引擴展成“消費類別”額外定義這個類別只能在哪些帳戶上扣、扣減優(yōu)先級是什么、費率是多少。比如長途呼叫產(chǎn)生的消費類別只能從長途免費時長、贈送金額、基本金額里按優(yōu)先級依次扣。這里的設(shè)計動機是消費類別是“怎么算錢”帳戶是“從哪扣錢”兩者通過入帳關(guān)系連接。入帳關(guān)系是一張映射表說明某類費用項應(yīng)該落到哪個帳戶。把“算”和“扣”分開之后專款專銷不需要改計費邏輯只需要配一條入帳關(guān)系。費率表也在這個階段從單一費率擴展成分檔費率頭 3 分鐘一個價、后 10 分鐘一個價越打越便宜就是分檔費率加累計用量判斷。2.3 OCS 時代的五個抽象業(yè)務(wù)用量、計費事件、模板、定價計劃、訂購到了多業(yè)務(wù)場景前面那套開始吃力。一次計費請求可能不是“通話 5 分鐘”而是“短信 3 條”“流量 200M”“直接扣款 2 元”用 ChargeClass 加時長已經(jīng)表達不了。套餐推出頻率越來越快改 ChargeClass 既不直觀也容易影響存量業(yè)務(wù)。預(yù)付費和后付費的計費邏輯被拆在兩套系統(tǒng)里同一個優(yōu)惠活動要配兩遍。OCS 的解法是五個抽象層層疊加。業(yè)務(wù)用量替代 ChargeClass表達“消費的是什么業(yè)務(wù)、量是多少”比如 20 分鐘長途費、2M 流量新增消費類型只是新增一個用量定義。計費事件把每種計費請求抽象成事件事件包含若干計費要素每個要素有自己的求解過程新增請求種類是加代碼而不是改老代碼修改是線性的。模板把可復(fù)用的計費能力封裝成模塊贈送模板只管贈送內(nèi)容參數(shù)呼叫計費模板只管費率和適配條件。定價計劃是一套完整的費用計算體系包通過調(diào)用多個模板組合出套餐比如 20 元套餐同時調(diào)贈送模板和呼叫計費模板。訂購決定用戶擁有哪些定價計劃只有訂購了才享受對應(yīng)費率。這五層的關(guān)系是事件觸發(fā)計費事件產(chǎn)生業(yè)務(wù)用量定價計劃里的模板對業(yè)務(wù)用量做批價批價輸出費用項費用項按入帳關(guān)系落到帳戶。新增一個優(yōu)惠活動只需要新增一個定價計劃并讓測試用戶訂購不動存量數(shù)據(jù)和代碼可測試性和兼容性都保住了。2.4 預(yù)付費與后付費的統(tǒng)一請求用量、授權(quán)用量、已使用用量預(yù)付費和后付費的本質(zhì)差別在風險控制時機預(yù)付費先扣錢后消費沒有欠費風險后付費先消費后出賬需要賬單、郵寄、催繳。OCS 把計費動作統(tǒng)一把差異推到用量類型上。預(yù)付費用戶使用前業(yè)務(wù)控制系統(tǒng)發(fā)起計費請求傳入“請求業(yè)務(wù)用量”系統(tǒng)根據(jù)帳戶余額算出“授權(quán)業(yè)務(wù)用量”返回業(yè)務(wù)側(cè)按授權(quán)量控制消費。后付費用戶使用完成后話單里的實際用量作為“已使用業(yè)務(wù)用量”送進系統(tǒng)批價入帳。批價入帳這段邏輯對兩者完全一致所以定價計劃對預(yù)付費和后付費都適用。預(yù)付費批價后出話單即可后付費再走賬單和催繳那套原有流程。這個統(tǒng)一還順帶解決了一卡多用。預(yù)付費用戶有 10 元A 業(yè)務(wù)請求 5 分鐘需要 1 元系統(tǒng)授權(quán)后還剩 9 元可用B 業(yè)務(wù)同時請求 200M 流量也能被響應(yīng)不需要等 A 業(yè)務(wù)結(jié)束。因為授權(quán)是在請求時刻基于當前余額算的多個業(yè)務(wù)可以并發(fā)占用同一份余額的授權(quán)額度只要總額不超。3. 批價流程拆解從事件到費用項鏈表到底經(jīng)過了幾層3.1 預(yù)處理、批價、入帳、后處理四段的分工一次完整的計費流程分四段。預(yù)處理負責把原始計費請求翻譯成系統(tǒng)內(nèi)部能處理的形態(tài)包括解析事件類型、提取計費要素、做必要的格式轉(zhuǎn)換和校驗。批價是核心根據(jù)業(yè)務(wù)用量和定價計劃算出費用項。入帳根據(jù)入帳關(guān)系把費用項落到具體帳戶上完成扣減。后處理做收尾比如生成話單、觸發(fā)通知、更新累計項。這四段里預(yù)處理和后處理對初學(xué)者是黑匣子資料里也明確說封裝細節(jié)只需要知道輸入輸出。真正要理解的是批價因為費率、優(yōu)惠、套餐的所有邏輯都壓在這一段。批價的輸入是業(yè)務(wù)用量集合和用戶訂購的定價計劃輸出是費用項鏈表。費用項鏈表這個數(shù)據(jù)結(jié)構(gòu)很關(guān)鍵每條記錄包含業(yè)務(wù)用量標識、用量數(shù)值、金額、費用項類型鏈表順序?qū)?yīng)消費明細的順序。3.2 業(yè)務(wù)識別一次呼叫怎么被拆成多個業(yè)務(wù)用量批價第一步是業(yè)務(wù)識別判斷這次計費請求涉及哪些業(yè)務(wù)用量。以主叫漫游撥打長途 5 分鐘為例系統(tǒng)要判斷主叫是否漫游、被叫是否長途然后生成基本費時長、長途費時長、漫游費時長三個業(yè)務(wù)用量各 300 秒。如果主叫沒有漫游漫游費時長為 0。這些用量名稱和 TAG 是設(shè)計時規(guī)劃好的比如基本費時長對應(yīng) TAG 2003長途費時長對應(yīng) 2005漫游費時長對應(yīng) 2004。業(yè)務(wù)識別的本質(zhì)是把“一次呼叫”這個復(fù)合事件拆成“多個可獨立計價的用量”。為什么要拆因為基本費、長途費、漫游費可能走不同的費率、落不同的帳戶、享受不同的優(yōu)惠。拆成獨立用量之后每個用量可以單獨匹配定價計劃里的模板互不干擾。這跟前面說的消費類別擴展是一脈相承的只是粒度更細、表達更通用。3.3 批價處理與費用項生成費率匹配和金額計算怎么落地業(yè)務(wù)用量確定后批價按用量逐個匹配定價計劃。匹配的依據(jù)是定價計劃里模板的適配條件比如“省內(nèi)漫游”這個條件只對漫游費用量生效。匹配上之后模板用傳入的費率參數(shù)對用量做計算。假設(shè)市話費率 0.1 元/分鐘、長途 0.2 元/分鐘、漫游 0.3 元/分鐘5 分鐘就是 300 秒三個用量分別算出 50 分、100 分、150 分生成三條費用項本地通話費用項、長途通話費用項、漫游通話費用項。費用項鏈表的結(jié)構(gòu)可以粗略表示為下面這樣字段名按資料里的描述歸納# 費用項節(jié)點批價輸出的消費明細單元 class ChargeItem: def __init__(self, usage_tag, usage_value, amount, item_type): self.usage_tag usage_tag # 業(yè)務(wù)用量標識如 2003 基本費時長 self.usage_value usage_value # 用量數(shù)值如 300 秒 self.amount amount # 金額單位分 self.item_type item_type # 費用項類型如 1 本地通話 self.next None # 鏈表指針串起多條消費明細 # 批價主循環(huán)的簡化邏輯 def rating(usages, pricing_plan): head None for usage in usages: template pricing_plan.match(usage) # 按適配條件匹配模板 if template is None: continue # 無匹配則不產(chǎn)生費用項 amount template.calculate(usage) # 模板內(nèi)按費率算金額 node ChargeItem(usage.tag, usage.value, amount, template.item_type) node.next head # 頭插或尾插形成消費清單 head node return head這段邏輯里match負責適配條件判斷calculate負責費率計算兩者都在模板內(nèi)部批價主循環(huán)只做遍歷和組裝。這樣新增一種計費能力只需要新增模板主循環(huán)不動。usage_tag和item_type的分離也值得注意用量標識說明消費了什么費用項類型說明這筆錢歸到哪類賬目入帳時看的是后者。3.4 入帳關(guān)系費用項怎么找到該扣的帳戶批價輸出費用項之后入帳按入帳關(guān)系把每條費用項映射到帳戶。入帳關(guān)系是一張配置說明某類費用項按什么優(yōu)先級從哪些帳戶扣。比如長途通話費用項先扣長途免費時長帳戶扣完再扣贈送金額帳戶最后扣基本余額帳戶。每個帳戶扣減時還要判斷余額是否足夠不足的部分按優(yōu)先級繼續(xù)往下找。這里有個容易忽略的點入帳不是簡單扣一個總數(shù)而是按費用項逐條處理每條費用項獨立走自己的入帳關(guān)系。這意味著一次呼叫產(chǎn)生的本地、長途、漫游三條費用項可能分別落到三個不同的帳戶組合上。這種設(shè)計讓??顚dN和分類型余額能夠精確執(zhí)行代價是入帳階段要做多次帳戶查找和扣減對性能有要求。常見的優(yōu)化是把同一用戶的帳戶和入帳關(guān)系做緩存批價和入帳之間盡量少查庫。4. 充值、月結(jié)與免費資源那些不在呼叫主流程里的計費能力4.1 充值流程的預(yù)處理與模板復(fù)用充值看起來是獨立流程但它復(fù)用了和呼叫計費同一套模板機制。充值請求進來先做預(yù)處理解析充值金額、充值類型、用戶標識然后匹配充值相關(guān)的定價計劃。充 100 送 40 分幾個月贈送這種活動本質(zhì)是充值模板加贈送模板的組合充值模板處理本金入帳贈送模板按分期規(guī)則生成后續(xù)的贈送計劃。模板復(fù)用的價值在這里體現(xiàn)得很明顯。贈送能力被封裝成模板之后呼叫套餐里的贈送、充值活動的贈送、月結(jié)的回贈調(diào)的都是同一個模板只是參數(shù)不同。參數(shù)包括贈送內(nèi)容、贈送時機、分期方式。這樣新增一種贈送活動不需要寫新代碼配參數(shù)就行。資料里把模板和策略并列解釋我理解模板是“計費能力的實現(xiàn)”策略是“模板被調(diào)用時的參數(shù)和條件組合”兩者配合才能表達一個完整的優(yōu)惠規(guī)則。4.2 月結(jié)與回贈定期事務(wù)怎么和實時計費共用一套帳戶月結(jié)是定期事務(wù)每天后臺跑處理月租扣取、套餐定期贈送、充值優(yōu)惠分期到賬。它和實時計費共用帳戶表和入帳關(guān)系區(qū)別在于觸發(fā)時機和用量來源。實時計費的用量來自呼叫事件月結(jié)的用量來自時間周期和預(yù)配的贈送計劃。月結(jié)流程里系統(tǒng)掃描到期的贈送計劃生成對應(yīng)的業(yè)務(wù)用量走批價和入帳把贈送金額或時長落到用戶帳戶?;刭浭窃陆Y(jié)的一個子場景比如充值送的分月到賬每個月結(jié)日把當月份額入帳。因為走的是同一套批價入帳邏輯月結(jié)贈送和呼叫計費在帳戶層面完全一致不會出現(xiàn)兩套余額對不上的情況。這也是 OCS 把 iCharge 和 iUser-bill 融合之后的好處定期事務(wù)和實時計費不再是兩個系統(tǒng)而是同一套計費能力的不同觸發(fā)方式。4.3 免費資源與累計項套餐里的“先用免費額度”怎么實現(xiàn)免費資源處理是套餐計費里的常見需求用戶訂購了含 300 分鐘市話的套餐打電話時先扣免費時長用完再按費率扣錢。實現(xiàn)上免費時長存在特定類型的帳戶里批價時業(yè)務(wù)用量先匹配免費資源模板模板判斷對應(yīng)帳戶是否有余額有則生成金額為 0 的費用項并扣減免費時長沒有則走正常費率模板。累計項處理解決的是“越打越便宜”和“消費累計”這類跨呼叫的狀態(tài)問題。累計項記錄用戶在某段時間內(nèi)的累計用量或累計消費批價時讀取累計項判斷當前處于哪個分檔。比如頭 3 分鐘 0.4 元/分鐘、后 10 分鐘 0.2 元/分鐘批價時要先查累計通話時長確定本次用量落在哪一檔再按對應(yīng)費率計算。累計項的更新發(fā)生在批價或后處理階段要保證和費用項生成的一致性否則會出現(xiàn)費率跳檔錯誤。常見的坑是累計項更新和批價不在同一個事務(wù)里并發(fā)呼叫時讀到舊值這個在排查章節(jié)會展開。5. 避坑與排查OCS 計費里那些容易翻車的地方5.1 費用項金額對但帳戶扣錯入帳關(guān)系配反了現(xiàn)象是批價輸出的費用項金額正確但用戶的基本余額沒動反而贈送帳戶被多扣了。原因通常是入帳關(guān)系里費用項類型和帳戶類型的映射配反或者扣減優(yōu)先級順序?qū)戝e。排查時先看批價輸出的費用項鏈表確認 item_type 正確再查入帳關(guān)系表里該 item_type 對應(yīng)的帳戶列表和優(yōu)先級逐條比對扣減記錄。解決方法是修正入帳關(guān)系配置并對已受影響的用戶做余額沖正。5.2 免費時長沒用完就開始扣錢免費資源模板的適配條件沒命中用戶套餐里有 300 分鐘市話但第一通電話就扣了基本余額。原因多半是免費資源模板的適配條件沒匹配上比如業(yè)務(wù)用量標識和模板條件里的用量類型不一致或者免費帳戶的入帳關(guān)系優(yōu)先級低于基本余額。排查時看批價日志里該次呼叫匹配到了哪些模板如果免費資源模板沒出現(xiàn)在匹配列表里就是適配條件問題如果匹配了但沒扣免費帳戶就是入帳關(guān)系優(yōu)先級問題。解決方法是修正模板適配條件或調(diào)整入帳優(yōu)先級。5.3 并發(fā)呼叫下余額被扣穿授權(quán)和扣減之間的時間窗預(yù)付費用戶同時發(fā)起兩路呼叫每路都請求授權(quán)系統(tǒng)基于同一份余額分別算出授權(quán)量結(jié)果兩路都授權(quán)成功實際消費超過余額。這是授權(quán)階段的經(jīng)典并發(fā)問題。原因在于授權(quán)時讀余額和扣減時讀余額之間有時間窗兩個請求都讀到了扣減前的余額。常見的實現(xiàn)思路是在授權(quán)時做額度預(yù)占把授權(quán)量對應(yīng)的金額先凍結(jié)扣減時用凍結(jié)額度結(jié)算釋放多余部分。排查時看授權(quán)記錄和扣減記錄的時間戳確認是否存在同一余額被多次授權(quán)。解決方法是引入預(yù)占機制或?qū)τ脩艏売囝~加鎖。5.4 月結(jié)贈送沒到賬贈送計劃的到期判斷用了錯誤時區(qū)月結(jié)跑完之后部分用戶的充值贈送沒有入帳。原因可能是贈送計劃的到期時間按 UTC 存儲月結(jié)任務(wù)按本地時間判斷到期跨時區(qū)時差導(dǎo)致部分計劃被跳過。排查時對比贈送計劃的到期時間字段和月結(jié)任務(wù)的判斷條件看時間基準是否一致。解決方法是統(tǒng)一時間基準或者在月結(jié)任務(wù)里顯式做時區(qū)轉(zhuǎn)換。這類問題在跨地區(qū)部署時特別容易翻車血淚經(jīng)驗是時間字段一定要標注時區(qū)。5.5 累計項跳檔錯誤批價和累計更新不在同一事務(wù)越打越便宜的套餐用戶反映費率跳檔不對有時提前跳檔有時延遲跳檔。原因是累計項更新和批價計算不在同一個事務(wù)里并發(fā)呼叫時批價讀到的累計值是舊的算完費率后另一個呼叫又更新了累計項導(dǎo)致分檔判斷錯位。排查時看同一用戶短時間內(nèi)的多次批價記錄對比每次讀到的累計值和實際累計值。解決方法是將累計項讀取、批價、累計項更新放在同一事務(wù)或同一把用戶級鎖內(nèi)保證讀到的累計值和更新之間沒有其他寫入。6. 抽象層次的取舍為什么 OCS 選擇用模板和定價計劃換靈活性回頭看這四次演進每一次都是在解決上一階段的抽象泄漏。兩張表階段費率和維度混在一起加號段就爆炸號碼分析加計費矩陣階段維度和價格分開了但消費類型和帳戶還是硬編碼帳戶抽象階段專款專銷能做了但多業(yè)務(wù)和多計費單位表達不了OCS 階段用業(yè)務(wù)用量、計費事件、模板、定價計劃、訂購五層抽象把“算什么”“怎么算”“從哪扣”“誰能享受”徹底拆開。這個拆分的代價是抽象層數(shù)變多初學(xué)者容易在模板和定價計劃之間迷路。資料里也承認 OCS 概念抽象、細節(jié)暴露多、版本里揉成一團。但從設(shè)計取舍看這是用前期理解成本換后期的擴展性新增業(yè)務(wù)類型加事件新增計費能力加模板新增優(yōu)惠活動加定價計劃新增用戶群加訂購每一層的變化都被限制在自己的邊界內(nèi)。對比智能網(wǎng)時代改 ChargeClass 牽一發(fā)動全身OCS 的線性修改特性是它能在多業(yè)務(wù)場景下站住腳的根本原因。驗證這套機制是否理解到位有個簡單方法拿一個具體套餐比如“20 元套餐贈送 300 分鐘市話、200 條網(wǎng)內(nèi)短信、省內(nèi)漫游 0.1 元/分鐘”從訂購開始往下推看它調(diào)了哪些模板、生成了哪些業(yè)務(wù)用量、批價輸出哪些費用項、按什么入帳關(guān)系落到哪些帳戶。能把這整條鏈路推通說明抽象層次和實現(xiàn)細節(jié)都對上了。我一般排查計費問題時也強制走一遍這個鏈路從費用項反推到業(yè)務(wù)用量再反推到事件和定價計劃比直接看代碼快得多。這份資料把掃盲、入門、提高三篇的層次鋪得很清楚配合實際配置數(shù)據(jù)看能把 OCS 的計費原理從概念落到可操作的細節(jié)上。希望幫到你。本文還有配套的精品資源點擊獲取