Từ Monolith đến Modern Core Banking
Các hệ thống Core Banking truyền thống (T24, Flexcube) được xây dựng theo kiến trúc Monolithic — toàn bộ nghiệp vụ (CIF, CASA, Lending, GL, Payments…) chạy trong một ứng dụng khổng lồ. Điều này gây ra:
- Deploy rủi ro cao: Sửa một module nhỏ phải deploy lại toàn bộ hệ thống.
- Scale không hiệu quả: Không thể scale riêng module Payments đang bị tải cao mà không scale cả hệ thống.
- Technology lock-in: Bị buộc chặt vào một ngôn ngữ, một database duy nhất.
Xu hướng hiện nay là chuyển sang Headless Core Banking — tách rời domain logic khỏi kênh giao tiếp (Mobile App, Internet Banking, ATM).
Kiến trúc tổng thể
┌─────────────────────────────────────┐
CHANNELS │ Mobile App │ Internet Banking │ ATM/POS │
└──────────────────────┬──────────────────────────┘
│ REST/gRPC
┌──────────────────────▼──────────────────────────┐
API GATEWAY │ API Gateway (Auth, Rate Limit, Routing) │
└──────────────────────┬──────────────────────────┘
│
┌─────────────────────────────────┼──────────────────────────┐
│ │ │
┌──────▼──────┐ ┌──────────▼─────────┐ ┌──────────▼──────────┐
│ CIF Service │ │ Account Service │ │ Payment Service │
│ (Customer) │ │ (CASA, GL) │ │ (Transfers, Fees) │
└─────────────┘ └────────────────────┘ └─────────────────────┘
│ │ │
└─────────────────────────────────┼──────────────────────────┘
│ Events (Kafka/Dapr)
┌──────────────────────▼──────────────────────────┐
EVENT BUS │ Message Broker (Kafka / Redis) │
└──────────────────────┬──────────────────────────┘
│
┌─────────────────────────────────┼──────────────────────────┐
│ │ │
┌──────▼──────┐ ┌──────────▼─────────┐ ┌──────────▼──────────┐
│ Loan Service│ │ Notification Svc │ │ Reporting Service │
│ (Lending) │ │ (SMS, Push, Email)│ │ (CQRS Read Side) │
└─────────────┘ └────────────────────┘ └─────────────────────┘
Pattern 1: Event Sourcing cho Sổ Cái (Ledger)
Trong kiến trúc truyền thống, chúng ta lưu trạng thái hiện tại (current state). Trong Event Sourcing, chúng ta lưu chuỗi sự kiện (immutable events) tạo ra trạng thái đó.
Tại sao Event Sourcing phù hợp với Core Banking?
Ledger đã vốn là Event Sourcing rồi — mỗi bút toán là một event không thể thay đổi. Số dư hiện tại là kết quả replay tất cả các bút toán từ đầu.
// Các event trong Account domain
type AccountOpened struct {
AccountID string
CIFNumber string
Currency string
OpenedAt time.Time
}
type MoneyDeposited struct {
AccountID string
Amount int64
TransactionID string
OccurredAt time.Time
}
type MoneyWithdrawn struct {
AccountID string
Amount int64
TransactionID string
OccurredAt time.Time
}
// Tính số dư bằng cách replay events
func calculateBalance(events []Event) int64 {
var balance int64
for _, event := range events {
switch e := event.(type) {
case MoneyDeposited:
balance += e.Amount
case MoneyWithdrawn:
balance -= e.Amount
}
}
return balance
}
Pattern 2: CQRS — Command Query Responsibility Segregation
Core Banking có đặc thù: ghi phải cực kỳ chắc chắn (ACID) nhưng đọc cần cực kỳ nhanh (dashboard, báo cáo). CQRS tách hai luồng này hoàn toàn:
WRITE SIDE (Command) READ SIDE (Query)
──────────────────────── ──────────────────────────
POST /transfers → Materialized Views
POST /accounts → Elasticsearch Index
PUT /loans/repay → Redis Cache
↓ Event Published ↓ ↑ Subscribe & Update ↑
└──────────────────────────┘
(Event Bus / Kafka)
Ví dụ thực tế:
- Write Side: Xử lý lệnh chuyển tiền với PostgreSQL + full ACID, đảm bảo tiền không sai.
- Read Side: Dashboard hiển thị lịch sử giao dịch từ Elasticsearch — truy vấn cực nhanh, full-text search, filter theo nhiều điều kiện.
Pattern 3: Saga — Giao dịch Phân tán qua nhiều Service
Khi chuyển tiền liên ngân hàng cần phối hợp 3 service: Account Service (trừ tiền), Payment Service (gửi lệnh NAPAS), Notification Service (báo SMS), làm sao đảm bảo tính toàn vẹn?
Choreography Saga (Hướng sự kiện)
Account Service Payment Service Notification Service
│ │ │
│── TransferInitiated ──────────▶│ │
│ │── PaymentSubmitted ──────▶│
│ │ │── SMS Sent
│◀── PaymentCompleted ──────────│ │
│ │ │
(release hold) (done)
Nếu Payment thất bại:
│◀── PaymentFailed ─────────────│
│ │
(cancel hold, hoàn tiền)
Outbox Pattern — Đảm bảo Event không bao giờ bị mất
Vấn đề: Nếu service commit database thành công nhưng publish event lên Kafka thất bại thì sao?
Giải pháp: Ghi event vào database trong cùng transaction, sau đó có worker riêng đọc và publish lên Kafka.
-- Bảng outbox: ghi cùng transaction với business data
CREATE TABLE outbox_events (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
topic VARCHAR(100) NOT NULL, -- 'account.transfer.completed'
payload JSONB NOT NULL,
status VARCHAR(20) NOT NULL DEFAULT 'PENDING',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
published_at TIMESTAMPTZ
);
-- Trong cùng một Database Transaction:
-- 1. Cập nhật số dư tài khoản
-- 2. Ghi ledger entries
-- 3. INSERT vào outbox_events
-- Worker riêng chạy định kỳ:
-- SELECT * FROM outbox_events WHERE status = 'PENDING'
-- → Publish lên Kafka
-- → UPDATE status = 'PUBLISHED'
Thiết kế API cho giao dịch tài chính
Nguyên tắc thiết kế
- Stateless API: Mỗi request phải tự chứa đủ thông tin.
- Idempotency header bắt buộc cho mọi API thay đổi trạng thái.
- Phân tách rõ Request (lệnh) và Status (kiểm tra trạng thái).
POST /v1/transfers → Khởi tạo lệnh chuyển tiền
Header: Idempotency-Key: <uuid>
Body: { from, to, amount, currency }
Response: { transfer_id, status: "PROCESSING" }
GET /v1/transfers/{transfer_id} → Kiểm tra kết quả
Response: { status: "COMPLETED" | "FAILED", ... }
Không bao giờ thiết kế API chuyển tiền theo kiểu synchronous block vì việc xử lý qua NAPAS/SWIFT có thể mất vài giây đến vài phút.
Lựa chọn Stack Kỹ thuật
| Tầng | Lựa chọn phổ biến | Lý do |
|---|---|---|
| Service Framework | Go (Kratos, Fiber), Java (Spring Boot) | Hiệu năng cao, type-safe |
| Database chính | PostgreSQL | ACID mạnh, JSONB flexible |
| Cache | Redis | Số dư, session, rate limiting |
| Event Bus | Apache Kafka, Dapr PubSub | Durable, ordered, replay |
| Service Mesh | Istio, Dapr | mTLS, circuit breaker |
| Orchestration | Kubernetes | Auto-scaling, self-healing |
Tiếp theo, chúng ta sẽ hiểu cách Core Banking giao tiếp với thế giới bên ngoài — các chuẩn quốc tế mà mọi hệ thống tài chính đều phải nói cùng một “ngôn ngữ”. Đọc tiếp Phần 5 — Chuẩn Tích hợp Quốc tế: ISO 8583 & ISO 20022.