LLM.coPrivate, self-hosted LLM deployments
Legal AI infrastructure for firms
AI RFP discovery and response drafting
Automatic.coBusiness process automation
Secure AI virtual data rooms
Erlang Mnesia Schema Design for Telecom Billing Systems
Billing apps move money every second, and money hates slow code. As the guardians of reliable voice minutes and megabytes, we have to stitch together a data layer that never blinks. That is where Erlang’s built-in database, Mnesia, slides in with quiet confidence. In the crowded field of software development, it offers soft-real-time performance, actor-friendly syntax, and a knack for distributing data without throwing tantrums.
Crafting a proper schema is the difference between invoices that print on time and customers who rage-quit at midnight. Buckle up, grab your favorite caffeine delivery system, and let’s design a data model tough enough for telco traffic yet nimble enough to keep your ops team smiling.
Understanding Erlang Mnesia in a Billing Context
A telecom switch can feel like a casino floor at peak hour. Thousands of calls start, stop, and spawn rating events faster than you can say “please hold.” Mnesia shines here because it marries an in-memory data store with disk durability, letting hot data live in RAM while colder rows nap on disk. The secret sauce is its transparent distribution layer, which shards and replicates tables across nodes with only a line or two of configuration. You gain horizontal scaling without bolting on a fragile external cluster.
Why Telecom Billing Loves Distributed Databases
A single billing node will eventually choke on the volume of Call Detail Records, or CDRs for short. Spreading tables lets each machine share the load while still offering ACID transactions. You can charge customers mid-call, update balances in milliseconds, and remain sure the ledger is accurate even if a node decides to take an unexpected coffee break.
Mnesia Basics Without the Headache
Tables come in three flavors: ram_copies, disc_copies, and disc_only_copies. Think of them as “all in RAM,” “in RAM but flushed to disk,” and “on disk only.” For real-time charging you keep subscriber balances in ram_copies. For archive CDRs you accept the slower disc-only-copy. Add transactional functions, and Mnesia juggles copies so your code still feels like vanilla ETS but gains persistence and replication for free.
Modeling Core Entities: Subscribers, Services, and Usage
Telecom models revolve around who made the call, what service they used, and how long they used it. Translating that to Mnesia tables is step one.
Building a Subscriber Table That Scales
Each subscriber gets a primary key, typically the IMSI or account number, plus mutable fields for balance, status, and plan identifier. Storing the balance as an integer in the smallest currency unit—say, cents—avoids float nightmares. Index the plan identifier so promotional campaigns can fetch a cohort without scanning every record. Finally, replicate the table across all nodes as ram_copies so any charging process can look up a balance locally with microsecond latency.
Usage Records and Time Buckets
CDRs roll in at frightening speed. Splitting the CDR table into daily or hourly buckets keeps index size under control and simplifies retention. Name tables like cdr_2025_12_08 to group rows by date, then drop them once legal retention periods expire. Each record holds subscriber id, timestamp, service id, usage units, and pre-rated cost. Extending the schema is painless—just add a new attribute and let Mnesia auto-patch the record definitions during rolling upgrades.
Handling Rating and Charging Logic
Charging is where a neat schema turns into actual revenue. The design must cope with massive concurrent writes while guarding against double charging.
Using Fragmented Tables for High-Volume Inserts
Mnesia fragmentation lets a logical table split into many physical segments. You pick a hash function, say on subscriber id, and Mnesia routes inserts to the correct fragment. This spreads write load and enables you to retire a fragment cleanly when it ages out. Keep each fragment small enough that loading it into memory for reporting does not require a heroic laptop.
Avoiding Hotspots With Hashing Tricks
A common trap is to hash by subscriber id only. Popular numbers create hotspots, and a single heavy user can overwhelm its fragment. Mix in the date or even the last few digits of the session id to scatter writes more evenly. That tiny tweak keeps write amplification low and avoids lock contention in the transaction manager.
Ensuring Consistency and Fault Tolerance
Money is allergic to inconsistency. Even a single miscounted penny fuels customer support tickets that multiply like gremlins.
Transaction Types That Matter
Mnesia offers two transaction modes: transaction and dirty. Dirty operations skip locking and logging for raw speed. Use them for non-critical metrics but never for balances. For charging functions, wrap operations in a normal transaction so you get atomicity. If two calls arrive at once, only one can decrement the same balance at a time. The losing transaction retries until it wins, guaranteeing no double spending.
Replication Strategies and Node Quorum
Replicating every table to every node is tempting yet wasteful. Instead, replicate real-time tables, like subscriber balances, to all nodes while archiving CDRs to a subset. Keep at least three replicas to survive a node outage without flipping into read-only mode. Mnesia waits for a quorum of acknowledgments before declaring a commit, so pick even-numbered replicas carefully. Odd counts dodge split-brain scenarios better.
Performance Tuning and Maintenance
Even the snazziest schema can sag under load if left unchecked. Good housekeeping avoids midnight alarms.
Keeping Indexes Trim and Fit
An index accelerates reads but slows writes. For fast-moving CDR inserts, store the primary key only and build secondary indexes offline if analytics teams need them. When you do index, choose attributes with high selectivity like subscriber id plus date rather than generic service codes. Periodically run mnesia:table_info(Table, size) to watch growth and prune indexes that no one actually queries.
Schema Evolution Without Downtime
Telcos love new tariffs, which means new columns. Mnesia supports live schema changes with mnesia:transform_table. Ship a code change that includes a converter function, let it rewrite rows in the background, and the cluster keeps serving calls without a hiccup. Test converters on a staging copy first because nothing ruins a weekend faster than botched migration of forty million rows.
Conclusion
Designing a billing database is part art, part owl-eyed vigilance. Erlang Mnesia hands you distribution, transactions, and flexible schema evolution in one tidy box. Model subscribers in RAM, shard CDRs by time, and choose transaction modes with ruthless intent.
Keep replicas odd, hashes varied, and indexes purposeful. When you do, minutes and megabytes flow through your system like water, revenue tallies correctly, and your on-call pager stays eerily silent. With a little wit and a solid plan, you can make Mnesia sing even while the network roars.
