Image
Build
Connect & operate
Design & teams
Start hereScope a build in one callBring a spec, a wireframe, or a paragraph. You leave with an architecture, a timeline, and a number.Book a scoping call
AI software
LLM & data systems
Vibe coding
Ready to ship?Put AI where the work isAgents, RAG, and private LLMs wired into the systems your team already uses — not a chatbot bolted to a homepage.Discuss an AI project
Domain firstWe learn your workflow before we model itRegulated, operational, or high-volume — the constraints belong in the schema, not in a training doc.Talk about your domain
Plan smarterEstimate before you commitCost ranges, scope templates, and the questions we ask in discovery — free, no form.Open the cost calculator
Real conversationsTalk with a technical leadNo SDR, no discovery gauntlet. The person on the call is the one who scopes the build.Book a call
Eric Lamanna
Author
Erlang Mnesia Schema Design for Telecom Billing Systems — featured image
9/29/2026

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.

Table Storage Mode Sets the Read-Latency FloorRelative read latency by Mnesia table copy type (lower is faster)1xram_copies3xdisc_copies8xdisc_only_copies

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.

Dirty Ops Are Fast; Transactions Are the Ones You Trust With MoneyIllustrative relative write throughput by Mnesia operation mode100dirty_write(no locking)40transaction(ACID, retries on conflict)

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.

More Replicas Buy You More Node FailuresNode outages a billing cluster survives without going read-only, by replica count01 replica13 replicas25 replicas

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.

Author
Eric Lamanna
Eric Lamanna is a Digital Sales Manager with a strong passion for software and website development, AI, automation, and cybersecurity. With a background in multimedia design and years of hands-on experience in tech-driven sales, Eric thrives at the intersection of innovation and strategy—helping businesses grow through smart, scalable solutions. He specializes in streamlining workflows, improving digital security, and guiding clients through the fast-changing landscape of technology. Known for building strong, lasting relationships, Eric is committed to delivering results that make a meaningful difference. He holds a degree in multimedia design from Olympic College and lives in Denver, Colorado, with his wife and children.