Presentation from MongoDB world conference 2014. BillRun is open-source billing system. Presentation demonstrate the advantages of MongoDB as storage for billing system.
6. S.D.O.C. Ltd. vision
We increase business success through great
open source technologies and services
○ Open & Transparent
○ Don't reinvent the wheel
○ High Quality
○ Lean & Effective
7. How did we get to billing (history)
● Client: Golan Telecom (Israel)
8. How did we get to billing (history)
● Client: Golan Telecom
○ New & lean player in the market
○ 0=>~1M subscribers in few years
○ Limited resources & loves open source
9. How did we get to billing (history)
● Client: Golan Telecom
○ Start up environment from Day 1
○ Short and aggressive time to market
○ Unlimited plan for ~25$
○ Customer can do almost everything using the website
■ Obviously requires 24/7 uptime
10. How did we get to billing (history)
● Start with Anti-Fraud solution
● 2 Different data structure, 2 separated tables
○ Outgoing calls (MOC)
○ incoming calls (MTC)
○ SMS (duration=0 means SMS)
11. Anti-Fraud in RDBMS
How did it look like? Example code...
$base_query = "SELECT imsi FROM moc WHERE callEventStartTimeStamp >=" . $start
. " UNION SELECT imsi FROM mtc WHERE callEventStartTimeStamp >=" . $start
$base_query = "SELECT imsi FROM (" . $base_query . ") AS qry ";
if (isset($args['imsi']))
$base_query .= "WHERE imsi = '" . $this->_connection->real_escape_string($args['imsi']) . "'";
$base_query .= "GROUP BY imsi ";
$mtc_join_query = "SELECT 'mtc' AS type, imsi, SUM(callEventDuration) AS duration, SUM(CEILING(callEventDuration/60)*60) AS duration_round "
. ", SUM(chargeAmount) charge "
. ", SUM(IF(SUBSTRING(callingNumber, 1, 3)='972', callEventDuration, IF(CHAR_LENGTH(callingNumber)<=10, callEventDuration, 0))) AS israel_duration
"
. ", SUM(IF(SUBSTRING(callingNumber, 1, 3)='972', CEILING(callEventDuration/60)*60, IF(CHAR_LENGTH(callingNumber)<=10, CEILING
(callEventDuration/60)*60, 0))) AS israel_duration_round "
. ", SUM(IF(SUBSTRING(callingNumber, 1, 3)!='972', IF(CHAR_LENGTH(callingNumber)>10, callEventDuration, 0), 0)) AS non_israel_duration "
. ", SUM(IF(SUBSTRING(callingNumber, 1, 3)!='972', IF(CHAR_LENGTH(callingNumber)>10, CEILING(callEventDuration/60)*60, 0), 0)) AS
non_israel_duration_round "
. ", SUM(IF(callEventDuration = 0, 1, 0)) AS sms_count "
12. Anti-Fraud in RDBMS
How did it look like? Example code...
. "FROM mtc "
. "WHERE callEventStartTimeStamp >=" . $start . " "
. "GROUP BY type, imsi";
$moc_join_query = "SELECT 'moc' AS type, imsi, SUM(callEventDuration) AS duration, SUM(CEILING(callEventDuration/60)*60) AS duration_round "
. ", SUM(chargeAmount) charge "
. ", SUM(IF(SUBSTRING(connectedNumber, 1, 3)='972', callEventDuration, IF(CHAR_LENGTH(connectedNumber)<=10, callEventDuration, 0))) AS
israel_duration "
. ", SUM(IF(SUBSTRING(connectedNumber, 1, 3)='972', CEILING(callEventDuration/60)*60, IF(CHAR_LENGTH(connectedNumber)<=10, CEILING
(callEventDuration/60)*60, 0))) AS israel_duration_round "
. ", SUM(IF(SUBSTRING(connectedNumber, 1, 3)!='972', IF(CHAR_LENGTH(connectedNumber)>10, callEventDuration, 0), 0)) AS non_israel_duration "
. ", SUM(IF(SUBSTRING(connectedNumber, 1, 3)!='972', IF(CHAR_LENGTH(connectedNumber)>10, CEILING(callEventDuration/60)*60, 0), 0)) AS
non_israel_duration_round "
. ", SUM(IF(callEventDuration = 0, 1, 0)) AS sms_count "
. "FROM moc "
. "WHERE callEventStartTimeStamp >=" . $start . " "
. "GROUP BY type, imsi";
13. Anti-Fraud in RDBMS
How did it look like? Example code...
$group_query = "SELECT base.imsi, moc.duration AS moc_duration, moc.charge AS moc_charge, "
. "mtc.duration AS mtc_duration, mtc.charge AS mtc_charge, "
. "mtc.duration_round AS mtc_duration_round, moc.duration_round AS moc_duration_round, "
. "moc.israel_duration AS moc_israel_duration, moc.non_israel_duration AS moc_non_israel_duration, "
. "moc.israel_duration_round AS moc_israel_duration_round, moc.non_israel_duration_round AS
moc_non_israel_duration_round, "
. "mtc.israel_duration AS mtc_israel_duration, mtc.non_israel_duration AS mtc_non_israel_duration, "
. "mtc.israel_duration_round AS mtc_israel_duration_round, mtc.non_israel_duration_round AS
mtc_non_israel_duration_round, "
. "mtc.sms_count AS mtc_sms_count, moc.sms_count AS moc_sms_count "
. "FROM "
. "( " . $base_query . " ) AS base "
. " LEFT JOIN (" . $mtc_join_query . " ) AS mtc ON base.imsi = mtc.imsi "
. " LEFT JOIN (" . $moc_join_query . " ) AS moc ON base.imsi = moc.imsi " ;
18. What is billing?
● Group of processes of communications
service providers
● responsible to collect consumption data
● calculate charging and billing information
● produce bills to customers
● process their payments and manage debt
collection
Wikipedia
26. Billing and MongoDB - Pros
Loose coupling compared to traditional billing components
Old
w/o MongoDb New
with MongoDb
27. Billing and MongoDB - Pros
● One call can be spread on few CDRs
● BillRun merges records only on presentation
layer or export
● No DB-level aggregation nor accumulation
○ No need for mediation
● Use billing and monitoring CDR in one system
database
28. Billing and MongoDB - Pros
Sophisticated rating module
● Rating module depends on CDR structure
● Easy to implement recurring rating
37. High performance tricks
● With SSD you get x20 more performance
● MongoDB loves RAM
● Follow MongoDB production notes
○ Readahead low as possible
○ THP - transparent hugepages
Pay Attention! What to keep in mind
38. More tips that happened to all
● Shorten property names
● MongoDB have database lock
○ Separate database for heavy-write collections
Pay Attention! What to keep in mind
39. TCO - MongoDB based solution
● 3 Months dev
● 3 Months QA
● Few days of maintenance infra and app
● Easy to add features
● Easy to scale
40. What can BillRun do
● 5,000 events per second
○ Including DB insert and transactional rating
● That means 157,680,000,000 events per year
● Create hundreds of millions invoices