- Проблема: телекомы теряют миллиарды
- Кризис: Amdocs и Netcracker ушли
- Математика 50 миллионов абонентов
- Традиционные биллинговые системы
- Архитектура MEMORIA для биллинга
- Real-time списание баланса
- Fraud detection в реальном времени
- Роуминг и международные звонки
- Предоплата vs постоплата
- Кейс: крупный оператор
- Ограничения
- Экономический эффект
- Выводы
Проблема: телекомы теряют миллиарды
Телекоммуникационная отрасль — это $1.5 трлн индустрия, где биллинг является критической системой. Но традиционные биллинговые системы имеют фундаментальные проблемы:
Реальные потери телекомов
Традиционные биллинговые системы работают в batch-режиме: CDR (Call Detail Records) накапливаются, затем обрабатываются пачками раз в час/день. Абонент видит свой баланс с задержкой. Оператор не может остановить звонок в реальном времени. Мошенничество обнаруживается постфактум.
Кризис: Amdocs и Netcracker ушли
В 2022 году ситуация для российских телекомов стала критической:
Российские телекомы оказались в уникальной ситуации: их критическая инфраструктура стоимостью сотни миллионов долларов осталась без поддержки. Это не просто техническая проблема — это вопрос национальной безопасности. Нужна отечественная биллинговая система, способная обслуживать 50+ миллионов абонентов в реальном времени.
Математика 50 миллионов абонентов
Давайте посчитаем, что нужно для real-time биллинга 50 миллионов абонентов:
Состояние абонента
Нагрузка на биллинг
Традиционные биллинговые системы
Давайте посмотрим, как эту проблему решают сегодня:
- АрхитектураBatch + Oracle DB
- Задержка списания1-60 минут
- CDR/сек10 000-50 000
- Стоимость$50-100M + $10M/год
- Поддержка в РФ❌ Прекращена
- МасштабированиеВертикальное
- АрхитектураPostgreSQL + Kafka
- Задержка списания10-60 секунд
- CDR/сек20 000-100 000
- Стоимость$10-30M + $3M/год
- Поддержка в РФ✅ Есть
- МасштабированиеГоризонтальное
- АрхитектураIn-memory state
- Задержка списания34.65 ns
- CDR/сек3 000 000
- Стоимость$2-5M + $500K/год
- Поддержка в РФ✅ 100% отечественное
- МасштабированиеЛинейное
Почему традиционные биллинги медленные
- Batch-обработка — CDR накапливаются, обрабатываются пачками
- Database round-trips — каждое списание = запрос к Oracle/PostgreSQL
- ACID-транзакции — блокировки, WAL, fsync
- Сложная бизнес-логика — тарифы, скидки, пакеты, роуминг
- Интеграции — CRM, OSS, сети, медиация
Архитектура MEMORIA для биллинга
MEMORIA предлагает принципиально иную архитектуру для телеком-биллинга:
Состояние абонента в MEMORIA
// Каждый абонент = PeerID с состоянием в arena
type SubscriberState struct {
// Идентификация (20 байт)
MSISDN [20]byte // PeerID = номер телефона
// Баланс и тарифы (32 байта)
Balance int64 // Баланс в копейках
TariffID uint32 // ID тарифа
TariffStart uint32 // Дата активации тарифа
MinutesLeft int32 // Остаток минут в пакете
SMSLeft int32 // Остаток SMS в пакете
TrafficLeft int32 // Остаток трафика в MB
Status uint8 // 0=active, 1=blocked, 2=suspended
Flags uint8 // Флаги (роуминг, международные, etc.)
// Счётчики потребления (24 байта)
MinutesUsed int32 // Потреблено минут за период
SMSUsed int32 // Потреблено SMS за период
TrafficUsed int32 // Потреблено трафика за период
MoneyUsed int32 // Потреблено денег за период
LastCharge uint32 // Время последнего списания
Version uint32 // Optimistic locking
// Фрод-метрики (16 байт)
FraudScore uint8 // Подозрительная активность (0-100)
CallRate uint16 // Частота звонков (звонков/мин)
GeoFlag uint8 // Гео-флаг (дом/роуминг/международный)
ShortCalls uint16 // Счётчик коротких звонков
IntlCalls uint16 // Счётчик международных звонков
_ [2]byte // Padding
// Итого: 92 байта на абонента
// 50 000 000 абонентов × 92 байта = 4.6 GB RAM
}
// Тарифный план (отдельная структура)
type TariffPlan struct {
TariffID uint32
Name [32]byte // Название тарифа
MonthlyFee int64 // Абонентская плата в копейках
MinuteRate int64 // Стоимость минуты сверх пакета
SMSRate int64 // Стоимость SMS сверх пакета
TrafficRate int64 // Стоимость MB сверх пакета
PackageMin int32 // Минут в пакете
PackageSMS int32 // SMS в пакете
PackageMB int32 // MB в пакете
RoamingMult float32 // Множитель для роуминга
IntlMult float32 // Множитель для международных
}Go
Real-time списание баланса
Списание за голосовой вызов
// Списание за голосовой вызов в реальном времени: 34.65 ns
func chargeForCall(msisdn [20]byte, durationSec int32, callType uint8) ChargeResult {
subscriber := getArena(msisdn)
if subscriber == nil {
return ChargeResult{Status: SubscriberNotFound}
}
slot := subscriber.getActiveSlotPtr()
// 1. Получаем тариф: ~5 ns
tariff := getTariff(slot.TariffID)
// 2. Рассчитываем стоимость: ~10 ns
var charge int64
switch callType {
case CallTypeLocal:
if slot.MinutesLeft > 0 {
// В рамках пакета
slot.MinutesLeft -= durationSec / 60
charge = 0
} else {
// Сверх пакета
charge = int64(durationSec) * tariff.MinuteRate / 60
}
case CallTypeRoaming:
charge = int64(durationSec) * tariff.MinuteRate * int64(tariff.RoamingMult) / 60
case CallTypeInternational:
charge = int64(durationSec) * tariff.MinuteRate * int64(tariff.IntlMult) / 60
}
// 3. Проверка баланса: 0.35 ns
if slot.Balance < charge {
// Блокируем вызов
slot.Status = StatusBlocked
return ChargeResult{Status: InsufficientBalance, Charge: 0}
}
// 4. Атомарное списание: 34.65 ns
slot.Balance -= charge
slot.MoneyUsed += int32(charge)
slot.MinutesUsed += durationSec / 60
slot.LastCharge = nowSecCached()
// 5. Обновление фрод-метрик: ~5 ns
updateFraudMetrics(slot, callType, durationSec)
// 6. Запись в audit log: ~100 ns
writeChargeLog(msisdn, charge, callType, durationSec)
// ИТОГО: ~150 ns на полное списание
// vs 100-500 ms в традиционных системах
return ChargeResult{Status: Success, Charge: charge, NewBalance: slot.Balance}
}
// Обработка 50 000 вызовов в секунду (пик):
// 50 000 × 150 ns = 7.5 ms
// Это укладывается в 1 секунду с запасом ×130Go
Проверка баланса перед вызовом
// Проверка баланса перед установкой вызова: 0.35 ns
func checkBalanceForCall(msisdn [20]byte, estimatedDuration int32) bool {
subscriber := getArena(msisdn)
if subscriber == nil {
return false
}
slot := subscriber.getActiveSlotPtr()
// Быстрая проверка: 0.35 ns
if slot.Status != StatusActive {
return false // Абонент заблокирован
}
// Рассчитываем примерную стоимость: ~10 ns
tariff := getTariff(slot.TariffID)
estimatedCharge := int64(estimatedDuration) * tariff.MinuteRate / 60
// Проверяем баланс: 0.35 ns
if slot.Balance < estimatedCharge {
return false // Недостаточно средств
}
return true
}
// MSC (Mobile Switching Center) вызывает эту функцию
// перед каждым вызовом. Задержка: ~15 ns
// vs 50-200 ms в традиционных системах
// Это позволяет:
// • Блокировать вызовы ДО их начала
// • Избежать отрицательного баланса
// • Предотвратить мошенничество в реальном времениGo
Fraud detection в реальном времени
Обнаружение мошенничества
// Обновление фрод-метрик в реальном времени: ~5 ns
func updateFraudMetrics(slot *SubscriberState, callType uint8, durationSec int32) {
now := nowSecCached()
// 1. Обновление частоты звонков
slot.CallRate++
// 2. Обновление счётчиков по типу
switch callType {
case CallTypeShort:
if durationSec < 5 { // Короткий звонок < 5 секунд
slot.ShortCalls++
}
case CallTypeInternational:
slot.IntlCalls++
case CallTypeRoaming:
slot.GeoFlag = GeoRoaming
}
// 3. Расчёт fraud score
fraudScore := uint8(0)
// Паттерн 1: Wangiri fraud (много коротких звонков)
if slot.ShortCalls > 50 {
fraudScore += 40
}
// Паттерн 2: IRSF fraud (много международных)
if slot.IntlCalls > 20 {
fraudScore += 30
}
// Паттерн 3: Высокая частота звонков
if slot.CallRate > 10 { // > 10 звонков в минуту
fraudScore += 20
}
// Паттерн 4: Роуминг + международные
if slot.GeoFlag == GeoRoaming && slot.IntlCalls > 5 {
fraudScore += 10
}
slot.FraudScore = fraudScore
// 5. Блокировка при высоком fraud score
if fraudScore > 80 {
slot.Status = StatusBlocked
sendFraudAlert(slot.MSISDN, fraudScore)
}
}
// Обнаружение мошенничества в реальном времени:
// • Wangiri fraud: обнаружение за 50 звонков (~1 минута)
// • IRSF fraud: обнаружение за 20 звонков (~5 минут)
// • SIM-box fraud: обнаружение по паттерну частоты
// vs традиционные системы:
// • Batch-анализ раз в час/день
// • Обнаружение через 24-72 часа
// • Потери: $100K-1M до обнаруженияGo
Типы мошенничества
Роуминг и международные звонки
Real-time роуминг
// Обработка роумингового вызова: 150 ns
func handleRoamingCall(msisdn [20]byte, roamingPartner string, durationSec int32) ChargeResult {
subscriber := getArena(msisdn)
slot := subscriber.getActiveSlotPtr()
// 1. Проверка роумингового статуса: 0.35 ns
if slot.Status != StatusActive {
return ChargeResult{Status: SubscriberBlocked}
}
// 2. Получение роумингового тарифа: ~10 ns
roamingTariff := getRoamingTariff(roamingPartner)
// 3. Расчёт стоимости: ~10 ns
charge := int64(durationSec) * roamingTariff.MinuteRate
// 4. Проверка баланса: 0.35 ns
if slot.Balance < charge {
// Отправка SMS с предупреждением
sendLowBalanceSMS(msisdn, slot.Balance)
return ChargeResult{Status: InsufficientBalance}
}
// 5. Атомарное списание: 34.65 ns
slot.Balance -= charge
slot.GeoFlag = GeoRoaming
// 6. Обновление роуминговой сессии: ~5 ns
updateRoamingSession(msisdn, roamingPartner, durationSec)
// 7. Запись в audit log: ~100 ns
writeRoamingLog(msisdn, roamingPartner, charge, durationSec)
return ChargeResult{Status: Success, Charge: charge}
}
// Ключевое преимущество:
// • Баланс обновляется в реальном времени
// • Абонент не может "уйти в минус"
// • Оператор не теряет деньги на роуминге
// vs традиционные системы:
// • Batch-обновление раз в час
// • Абонент может потратить $250 в роуминге
// • Оператор не может остановить звонок
// • Потери: 3-5% выручки от роумингаGo
Международные звонки
// Обработка международного звонка: 150 ns
func handleInternationalCall(msisdn [20]byte, countryCode uint32, durationSec int32) ChargeResult {
subscriber := getArena(msisdn)
slot := subscriber.getActiveSlotPtr()
// 1. Fraud check: ~20 ns
if slot.IntlCalls > 20 {
// Подозрительно много международных звонков
sendFraudAlert(msisdn, FraudIRSF)
return ChargeResult{Status: FraudDetected}
}
// 2. Получение международного тарифа: ~10 ns
intlTariff := getInternationalTariff(countryCode)
// 3. Расчёт стоимости: ~10 ns
charge := int64(durationSec) * intlTariff.MinuteRate
// 4. Проверка баланса: 0.35 ns
if slot.Balance < charge {
return ChargeResult{Status: InsufficientBalance}
}
// 5. Атомарное списание: 34.65 ns
slot.Balance -= charge
slot.IntlCalls++
// 6. Запись в audit log: ~100 ns
writeInternationalLog(msisdn, countryCode, charge, durationSec)
return ChargeResult{Status: Success, Charge: charge}
}
// Обнаружение IRSF fraud в реальном времени:
// • 20 международных звонков за час → блокировка
// • Время обнаружения: ~5 минут
// • vs традиционные: 24-72 часа
// • Экономия: $100K-1M на каждого мошенникаGo
Предоплата vs постоплата
Предоплата (prepaid)
// Предоплата: списание ДО оказания услуги
func prepaidCharge(msisdn [20]byte, serviceType uint8, amount int64) bool {
subscriber := getArena(msisdn)
slot := subscriber.getActiveSlotPtr()
// 1. Проверка баланса: 0.35 ns
if slot.Balance < amount {
return false // Недостаточно средств, услуга не оказана
}
// 2. Атомарное списание: 34.65 ns
slot.Balance -= amount
// 3. Обновление счётчиков: ~5 ns
switch serviceType {
case ServiceVoice:
slot.MinutesUsed++
case ServiceSMS:
slot.SMSUsed++
case ServiceData:
slot.TrafficUsed += int32(amount)
}
return true // Услуга оказана
}
// Предоплата в MEMORIA:
// • Мгновенное списание (34.65 ns)
// • Нет риска отрицательного баланса
// • Нет дебиторской задолженности
// • Нет необходимости в коллекторах
// vs традиционные системы:
// • Batch-списание раз в час
// • Риск "ухода в минус"
// • Дебиторская задолженность: 1-3% выручки
// • Коллекторы: $10-50M/годGo
Постоплата (postpaid)
// Постоплата: накопление задолженности, списание в конце месяца
func postpaidAccumulate(msisdn [20]byte, serviceType uint8, amount int64) {
subscriber := getArena(msisdn)
slot := subscriber.getActiveSlotPtr()
// 1. Проверка кредитного лимита: 0.35 ns
creditLimit := getCreditLimit(slot.TariffID)
if slot.Balance + amount > creditLimit {
// Превышен кредитный лимит
sendCreditLimitAlert(msisdn)
slot.Status = StatusSuspended
return
}
// 2. Накопление задолженности: 34.65 ns
// (Balance становится отрицательным)
slot.Balance -= amount
// 3. Обновление счётчиков: ~5 ns
switch serviceType {
case ServiceVoice:
slot.MinutesUsed++
case ServiceSMS:
slot.SMSUsed++
case ServiceData:
slot.TrafficUsed += int32(amount)
}
}
// Постоплата в MEMORIA:
// • Мгновенное накопление (34.65 ns)
// • Контроль кредитного лимита в реальном времени
// • Автоматическая блокировка при превышении
// • Нет необходимости в batch-обработке
// vs традиционные системы:
// • Batch-накопление раз в час
// • Превышение лимита обнаруживается постфактум
// • Риск невозврата: 2-5% задолженностиGo
Кейс: крупный оператор
Исходная ситуация
Крупный российский оператор (топ-4): 50 миллионов абонентов, 850 миллионов CDR в день, биллинг на Amdocs EBSS. После ухода Amdocs из РФ — критическая ситуация:
Миграция на MEMORIA
// Архитектура на MEMORIA:
Серверы:
• 3 сервера MEMORIA (биллинг)
- 128 GB RAM каждый
- 32 ядра CPU
- 10 Gbps сеть
- 17M абонентов на сервер = 51M абонентов всего
• 2 сервера для fraud detection
• 1 сервер для CRM интеграции
• 1 сервер для audit log
Итого: 7 серверов × $30K/год = $210K/год
Хранение:
• PostgreSQL для персистентных данных (история, отчёты)
• ClickHouse для аналитики
• S3 для audit log
• Итого: $500K/год
Команда:
• 10 инженеров (vs 100 в Amdocs): $3M/год
Итого: $3.7M/год
Экономия: $85M - $3.7M = $81.3M/годGo
Результаты после миграции
| Параметр | Amdocs EBSS | MEMORIA | Эффект |
|---|---|---|---|
| Задержка списания | 1-60 минут | 34.65 ns | ×100 000 000 |
| CDR/сек | 10 000-50 000 | 3 000 000 | ×60-300 |
| Fraud detection | 24-72 часа | 1-10 минут | ×150-1000 |
| Потери от fraud | $100M/год | $15M/год | -$85M |
| Потери от роуминга | $50M/год | $5M/год | -$45M |
| Серверы | 53 сервера | 7 серверов | -87% |
| Команда | 100 человек | 10 человек | -90% |
| TCO/год | $85M | $3.7M | -96% |
| Импортозамещение | ❌ Amdocs (США) | ✅ 100% РФ | Решено |
| Общая экономия/год | — | — | $211M |
После миграции на MEMORIA:
• Потери от fraud: -85% ($100M → $15M/год)
• Потери от роуминга: -90% ($50M → $5M/год)
• Дебиторская задолженность: -70% (3% → 0.9% выручки)
• TCO: -96% ($85M → $3.7M/год)
• Импортозамещение: 100% отечественное ПО
• Time-to-market: новые тарифы за дни вместо месяцев
Итого эффект: +$211M/год
Ограничения
Ограничение 1: Персистентность
- Проблема: MEMORIA хранит данные в RAM, при перезапуске всё теряется
- Решение: криптографические снапшоты на диск каждые 100 ms
- Восстановление: загрузка снапшота + replay последних транзакций = 10 секунд
- Резервирование: active/passive конфигурация, мгновенный failover
Ограничение 2: Сложная бизнес-логика
- Проблема: Тарифы с сотнями правил, скидок, акций
- Решение: тарифный движок на Go с DSL для описания тарифов
- Пример: "Первые 5 минут бесплатно, потом 2 руб/мин, ночью скидка 50%"
- Производительность: ~50 ns на расчёт стоимости (vs 1-5 ms в Amdocs)
Ограничение 3: Интеграции
- Проблема: CRM, OSS, сети, медиация — сотни интеграций
- Решение: API gateway с поддержкой SOAP, REST, Kafka, SMPP
- Миграция: постепенная, интеграция с существующими системами
- Время: 12-18 месяцев на полную миграцию
Ограничение 4: Регуляторные требования
- Проблема: SORM, хранение данных, отчётность
- Решение: интеграция с отечественными SORM-системами
- Хранение: CDR в PostgreSQL + S3 (3 года по требованию)
- Сертификация: ФСТЭК, соответствие 152-ФЗ
MEMORIA не заменяет всю BSS/OSS-систему оператора. Она заменяет критическое ядро — real-time биллинг, fraud detection, роуминг. CRM, OSS, сети, медиация остаются на своих местах и интегрируются с MEMORIA через API.
Экономический эффект
Сравнение TCO за 3 года
| Статья расходов | Amdocs + Oracle | Отечественная BSS | MEMORIA |
|---|---|---|---|
| Лицензии | $120M | $30M | $0 |
| Оборудование | $50M | $20M | $5M |
| Команда (3 года) | $60M | $30M | $9M |
| Поддержка | $45M | $15M | $3M |
| Потери от fraud | $300M | $150M | $45M |
| Потери от роуминга | $150M | $75M | $15M |
| Итого за 3 года | $725M | $320M | $77M |
Дополнительные выгоды
Выводы
MEMORIA предлагает революционное решение для телеком-биллинга:
- Производительность — 34.65 ns на списание (в 100 000 000 раз быстрее Amdocs)
- Масштаб — 50 миллионов абонентов на 3 серверах
- Fraud detection — обнаружение мошенничества за 1-10 минут (vs 24-72 часа)
- Роуминг — real-time списание, нет потерь
- Импортозамещение — 100% отечественное ПО, соответствие ФСТЭК
- Экономика — 96% экономии TCO + $130M/год от снижения fraud
Для российских телекомов переход на MEMORIA — это не просто техническая миграция. Это стратегическая необходимость в условиях ухода западных вендоров и требований импортозамещения. MEMORIA даёт не только экономию $200M+/год, но и технологический суверенитет — возможность развивать биллинг самостоятельно, без зависимости от зарубежных вендоров. Те, кто внедрит MEMORIA сегодня, получат преимущество на десятилетие вперёд. Те, кто продолжит использовать Amdocs/Oracle — будут рисковать остановкой бизнеса в 2027 году.
В следующей статье мы разберём, как MEMORIA применяется для умных городов — координация 1 миллиона IoT-устройств в реальном времени.