NoSQL 7 — Redis: bền vững, nhân bản & vận hành

13 thg 7, 2026 2 lượt xem
#sql
#cluster
#operations
#nosql
#redis
#persistence

NoSQL 7 — Redis: bền vững, nhân bản & vận hành

Hai bài trước đã dựng nền về Redis như một kho key-value trong bộ nhớ và các pattern thực chiến (cache-aside, rate limiting, distributed lock, hàng đợi). Nhưng biết dùng Redis và biết vận hành Redis trong môi trường sản xuất ngân hàng là hai chuyện khác nhau. Khi Redis đứng trước core banking, gánh session của hàng trăm nghìn phiên mobile banking và cache những dữ liệu mà mất đi sẽ gây sự cố, câu hỏi trở nên nghiêm túc: dữ liệu trong RAM có mất khi restart không? Một node chết thì hệ thống có sập theo không? Làm sao scale khi RAM một máy không đủ? Bài này trả lời những câu hỏi đó.

Lưu ý về sandbox: SQL sandbox của Knowledge Base chạy trên PostgreSQL (chỉ đọc). Mọi lệnh Redis và đoạn cấu hình redis.conf trong bài này đều không chạy được ở đây — chúng chỉ minh hoạ cú pháp/cấu hình. Không có khối SQL nào trong bài này được đánh dấu "▶ Chạy được".

Bền vững: RDB vs AOF

Điểm gây hiểu lầm lớn nhất về Redis: "nó nằm trong RAM nên restart là mất sạch". Sai. Redis có hai cơ chế persistence ghi dữ liệu xuống đĩa để khôi phục sau khi restart. Hiểu rõ hai cơ chế này — và cách chúng đánh đổi — là kiến thức vận hành nền tảng.

RDB — snapshot định kỳ

RDB (Redis Database) chụp một ảnh chụp nhanh (snapshot) toàn bộ dataset tại một thời điểm và ghi ra một file nhị phân nén (dump.rdb). Nó chạy định kỳ theo điều kiện "sau N giây mà có ít nhất M key thay đổi".

# redis.conf — lưu snapshot khi:
save 900 1        # sau 900s (15 phút) nếu có >= 1 key đổi
save 300 10       # sau 300s nếu có >= 10 key đổi
save 60 10000     # sau 60s nếu có >= 10000 key đổi
dbfilename dump.rdb
dir /var/lib/redis

Khi tới ngưỡng, Redis gọi fork() tạo một tiến trình con; tiến trình con ghi snapshot ra đĩa còn tiến trình chính tiếp tục phục vụ lệnh. Nhờ copy-on-write của hệ điều hành, tiến trình con nhìn thấy ảnh dữ liệu đông cứng tại thời điểm fork mà không chặn tiến trình chính.

Đặc điểm RDB:

  • Nhanh khôi phục: file nhị phân nén, load lại rất nhanh — RDB là cách khôi phục nhanh nhất với dataset lớn.
  • File gọn: một file duy nhất, dễ backup/chuyển đi.
  • Có thể mất dữ liệu: đây là đánh đổi cốt lõi. Giữa hai snapshot, mọi thay đổi chỉ nằm trong RAM. Nếu Redis crash ngay trước snapshot kế tiếp, mọi ghi từ snapshot gần nhất tới lúc crash đều mất — có thể là vài phút dữ liệu.
  • Chi phí fork: với dataset rất lớn, fork() có thể gây một cú ngập ngừng độ trễ ngắn (do sao chép bảng trang bộ nhớ).

AOF — nhật ký chỉ-thêm

AOF (Append Only File) ghi mọi lệnh ghi (write command) vào một file log theo thứ tự nhận được. Khôi phục = phát lại (replay) toàn bộ log từ đầu để dựng lại dataset.

appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec      # chính sách fsync: everysec | always | no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

Điểm mấu chốt của AOF là chính sách fsync — tần suất Redis buộc hệ điều hành flush buffer log xuống đĩa vật lý:

appendfsyncÝ nghĩaĐánh đổi
alwaysfsync sau mỗi lệnh ghiAn toàn nhất (gần như không mất dữ liệu) nhưng chậm nhất — mỗi ghi chờ đĩa
everysecfsync mỗi giây một lầnCân bằng khuyến nghị: tối đa mất ~1 giây dữ liệu khi crash, thông lượng cao
noĐể OS tự quyết khi nào flushNhanh nhất nhưng có thể mất tới 30s dữ liệu (theo cơ chế OS)

AOF rewrite: file log càng chạy càng phình (một key bị INCR một triệu lần sinh ra một triệu dòng log). Redis định kỳ rewrite — nén log bằng cách viết lại một file mới chứa tập lệnh tối thiểu đủ dựng lại trạng thái hiện tại (một key chỉ cần một lệnh SET giá trị cuối). Rewrite cũng chạy trên tiến trình con để không chặn.

Đặc điểm AOF:

  • Bền vững hơn RDB: với everysec, tệ nhất mất 1 giây — tốt hơn nhiều so với "mất vài phút" của RDB.
  • File lớn hơn và khôi phục chậm hơn RDB (phải replay lệnh, dù rewrite đã nén).
  • Log dễ đọc/audit hơn snapshot nhị phân (định dạng lệnh Redis).

Kết hợp cả hai

Thực tế sản xuất thường bật cả RDB lẫn AOF. Từ Redis 7, có chế độ multi-part AOF: một file base dạng RDB (snapshot gọn, khôi phục nhanh) cộng các file incremental AOF (log các thay đổi sau đó). Khi khởi động, Redis ưu tiên dùng AOF để khôi phục (nếu bật) vì nó mới hơn.

Cách chọn theo vai trò:

  • Redis làm cache thuần (mất là cache-miss rồi nạp lại từ DB): có thể tắt cả hai (save "", appendonly no) — persistence chỉ tốn I/O vô ích. Mất dữ liệu không gây hại, chỉ cần cân nhắc cache-stampede khi cả cache trống lúc restart.
  • Redis làm store bán-bền (session, dữ liệu real-time không có nguồn khác): bật AOF everysec để giới hạn mất mát ở 1 giây, kèm RDB để khôi phục nhanh và có snapshot backup.

Nhân bản: replication primary-replica

Persistence chống mất dữ liệu khi restart, nhưng không giúp gì khi cả node chết hay khi cần mở rộng năng lực đọc. Đó là việc của replication.

Redis dùng mô hình primary–replica (trước đây gọi master–slave): một node primary nhận mọi lệnh ghi; một hoặc nhiều replica sao chép dữ liệu từ primary và phục vụ đọc. Cấu hình đơn giản: trên replica trỏ về primary.

# trên node replica
replicaof 10.0.1.10 6379
replica-read-only yes           # replica chỉ đọc (mặc định, khuyến nghị)

Cơ chế đồng bộ:

  1. Full resync lần đầu: replica kết nối, primary tạo một snapshot RDB gửi sang, replica load; đồng thời primary đệm mọi lệnh ghi phát sinh trong lúc đó rồi gửi tiếp.
  2. Partial resync khi mất kết nối tạm: primary giữ một replication backlog (bộ đệm vòng). Nếu replica mất kết nối ngắn rồi nối lại, nó xin đồng bộ phần thiếu thay vì full resync — tránh cú fork/RDB tốn kém.

Điểm cực kỳ quan trọng: replication là bất đồng bộ (async). Primary xác nhận lệnh ghi cho client trước khi replica nhận được. Hệ quả:

  • Không đảm bảo bền vững tuyệt đối: nếu primary crash sau khi ack client nhưng trước khi kịp truyền cho replica, ghi đó mất. Redis có WAIT numreplicas timeout để chờ N replica xác nhận (bán đồng bộ), nhưng đây không phải commit đồng bộ đầy đủ như RDBMS.
  • Đọc trên replica có thể trễ (stale): replica luôn chậm hơn primary một chút. Chấp nhận được cho báo cáo/analytics, nhưng dữ liệu vừa ghi đọc lại trên replica có thể chưa thấy.

Replication cho ta mở rộng đọc (nhiều replica gánh read) và dự phòng (còn bản sao khi primary chết) — nhưng bản thân nó không tự động failover. Nếu primary chết, phải có ai đó promote một replica lên làm primary mới và trỏ client sang. Làm tay thì chậm và dễ sai. Đây chính là chỗ Sentinel bước vào. Mô hình này song song với replication ở RDBMS — cùng bài toán primary-replica async, đọc mở rộng, và độ trễ replica.

Redis Sentinel — giám sát và tự động failover

Redis Sentinel là hệ thống giám sát biến cụm primary-replica thành HA (High Availability) tự động. Sentinel không lưu dữ liệu; nó là các tiến trình riêng chạy song song, làm ba việc:

  1. Giám sát (monitoring): liên tục ping primary và các replica để phát hiện node chết.
  2. Tự động failover: khi primary được xác nhận chết, Sentinel bầu một replica lên làm primary mới, cấu hình lại các replica khác trỏ về primary mới.
  3. Service discovery: client hỏi Sentinel "primary hiện tại ở đâu?" thay vì hardcode địa chỉ — nên sau failover, client tự tìm đúng primary mới.
# sentinel.conf
sentinel monitor mymaster 10.0.1.10 6379 2   # quorum = 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1

Cơ chế quyết định "primary đã chết" gồm hai mức:

  • SDOWN (Subjectively Down): một Sentinel không ping được primary quá down-after-milliseconds → nó chủ quan cho là chết.
  • ODOWN (Objectively Down): đủ quorum số Sentinel cùng đồng ý primary chết → khách quan xác nhận, kích hoạt failover.

Vì phải đạt quorum, triển khai Sentinel cần số lẻ và ≥ 3 instance (thường 3), đặt trên các máy/khu vực khác nhau, để tránh split-brain (mạng chia đôi, hai phía cùng tưởng mình đúng) và để không một node hỏng nào làm sai lệch quyết định. Sau khi ODOWN, các Sentinel bầu một leader để điều phối failover, leader chọn replica tốt nhất (ưu tiên độ trễ replication thấp nhất, priority cao) promote lên.

Sentinel phù hợp khi dataset vừa với RAM một máy và nhu cầu là HA + failover chứ chưa cần chia nhỏ dữ liệu. Khi dataset vượt RAM một máy, ta cần Cluster.

Redis Cluster — sharding ngang

Redis Cluster giải bài toán dữ liệu lớn hơn RAM một node bằng cách sharding: chia dữ liệu ra nhiều primary, mỗi primary giữ một phần. Cluster vừa scale ngang (thêm node để thêm dung lượng/thông lượng) vừa có HA sẵn (mỗi shard có replica riêng).

16384 hash slot

Cluster không băm key trực tiếp ra node. Nó chia keyspace thành 16384 hash slot cố định. Mỗi key được ánh xạ vào một slot bằng CRC16(key) mod 16384. Mỗi node primary sở hữu một dải slot; ví dụ cụm 3 node:

NodeDải hash slot
Primary A0 – 5460
Primary B5461 – 10922
Primary C10923 – 16383

Lớp gián tiếp "slot" này là điểm thiết kế then chốt: khi thêm/bớt node (resharding), ta chỉ di chuyển một số slot (kèm key trong đó) từ node này sang node khác, không phải băm lại toàn bộ keyspace. Client (client thông minh hỗ trợ cluster) giữ bản đồ slot→node; nếu gửi lệnh tới nhầm node, node trả về redirect MOVED/ASK chỉ đúng node giữ slot đó.

Cảnh báo multi-key: phải cùng slot

Đây là ràng buộc quan trọng nhất khi lập trình với Cluster. Một lệnh đụng nhiều key (MGET, SINTER, MULTI/EXEC nhiều key, Lua script nhiều key) chỉ chạy được nếu mọi key nằm trên cùng một slot. Nếu các key rơi vào slot khác nhau (do đó có thể ở node khác nhau), Redis từ chối với lỗi CROSSSLOT.

Giải pháp là hash tag: nếu key chứa một đoạn trong {...}, Redis chỉ băm phần trong ngoặc để tính slot. Nhờ đó ta ép nhiều key liên quan vào cùng slot.

# Các key này băm theo TOÀN BỘ chuỗi -> slot khác nhau -> CROSSSLOT nếu thao tác chung
SET customer:10023:profile ...
SET customer:10023:sessions ...

# Dùng hash tag {10023}: CHỈ băm "10023" -> cùng slot -> thao tác đa key OK
SET customer:{10023}:profile ...
SET customer:{10023}:sessions ...
MGET customer:{10023}:profile customer:{10023}:sessions   -- hợp lệ, cùng slot

Quy tắc thực chiến: khi thiết kế trên Cluster, xác định trước những nhóm key cần thao tác cùng nhau và gắn chung một hash tag (thường là entity id) để chúng luôn ở cùng node.

HA trong Cluster

Mỗi primary trong Cluster có thể có replica. Các node giao tiếp với nhau qua cluster bus (cổng riêng, thường port_dữ_liệu + 10000) bằng giao thức gossip, tự phát hiện node chết. Khi một primary chết, các node còn lại tự bầu một replica của nó lên primary — Cluster có failover nội tại, không cần Sentinel riêng. Đổi lại, Cluster phức tạp hơn để vận hành và có những ràng buộc như CROSSSLOT ở trên.

Sentinel hay Cluster?

Tiêu chíSentinelCluster
Bài toán chínhHA + failover cho 1 datasetSharding: dữ liệu > RAM 1 node
Sharding dữ liệuKhông (toàn bộ trên 1 primary)Có (16384 slot chia nhiều primary)
Multi-key opTự do (một node)Chỉ cùng slot (dùng hash tag)
Độ phức tạp vận hànhThấp hơnCao hơn
Chọn khiDataset vừa RAM, cần HACần scale ngang dung lượng/thông lượng

Nguyên tắc: đừng dùng Cluster khi chưa cần. Nếu dataset còn vừa RAM một máy, Sentinel đơn giản và đủ. Chỉ chuyển sang Cluster khi thực sự chạm trần RAM hoặc thông lượng một node.

Eviction: chọn cách dọn khi đầy RAM

RAM hữu hạn. Khi Redis chạm maxmemory, nó phải quyết định làm gì với lệnh ghi tiếp theo — và đó là eviction policy.

maxmemory 8gb
maxmemory-policy allkeys-lru

Các policy chính:

PolicyHành vi khi đầy RAM
noevictionTừ chối lệnh ghi (trả lỗi), lệnh đọc vẫn chạy. Không key nào bị xoá.
allkeys-lruXoá key ít được dùng gần đây nhất (LRU) trong toàn bộ keyspace
allkeys-lfuXoá key ít được dùng theo tần suất (LFU) trong toàn bộ keyspace
allkeys-randomXoá ngẫu nhiên bất kỳ key nào
volatile-lruLRU nhưng chỉ trong các key có TTL
volatile-lfuLFU chỉ trong key có TTL
volatile-ttlXoá key có TTL, ưu tiên key sắp hết hạn sớm nhất
volatile-randomNgẫu nhiên trong các key có TTL

Cách chọn theo vai trò của Redis:

  • Dùng làm cache: chọn allkeys-lru (hoặc allkeys-lfu nếu muốn dựa trên tần suất truy cập, tránh bị một đợt quét làm sai lệch). Cache đầy thì đẩy dữ liệu nguội ra là đúng ý — cache-miss chỉ khiến nạp lại từ DB.
  • Dùng làm store (không được mất tuỳ tiện): chọn noeviction. Khi đầy, Redis từ chối ghi và báo lỗi rõ ràng thay vì âm thầm xoá dữ liệu — bạn muốn biết để tăng RAM/xử lý, chứ không muốn mất session/dữ liệu ngầm.

Lưu ý: các policy volatile-* chỉ xoá key có TTL; nếu keyspace toàn key không TTL mà chọn volatile-lru, khi đầy Redis không có gì để xoá và hành xử như noeviction (từ chối ghi). LRU/LFU của Redis là xấp xỉ (lấy mẫu ngẫu nhiên một số key rồi chọn nạn nhân, để tiết kiệm chi phí), không phải LRU tuyệt đối — đủ tốt trong thực tế.

Quản lý bộ nhớ

maxmemory là hàng rào cứng, nhưng con số RAM Redis thực sự dùng phức tạp hơn "tổng kích thước value". Hai khái niệm cần nắm:

  • used_memory — bộ nhớ Redis cấp cho dataset (từ allocator, thường jemalloc).
  • used_memory_rss — bộ nhớ hệ điều hành thực sự cấp cho tiến trình (RSS).

Tỉ lệ rss / used_memorymem_fragmentation_ratio. Lớn hơn 1 nhiều nghĩa là phân mảnh bộ nhớ (fragmentation) — RAM đã cấp cho OS nhưng không dùng hết, thường do mẫu ghi/xoá nhiều kích thước khác nhau. Fragmentation cao khiến RSS vượt xa dataset thật, có thể chạm trần RAM máy dù dataset chưa lớn. Redis có activedefrag yes để chống phân mảnh chủ động.

Ngược lại, ratio nhỏ hơn 1 là dấu hiệu Redis đang bị swap ra đĩa — cực xấu, vì swap giết chết độ trễ. Nguyên tắc vận hành: tắt swap hoặc để RAM dư sao cho Redis không bao giờ chạm swap, và đặt maxmemory thấp hơn RAM vật lý (chừa chỗ cho fork lúc RDB/AOF-rewrite, buffer client, và overhead).

Giám sát

Không giám sát thì vận hành là mù. Bốn công cụ cốt lõi:

INFO — trả về hàng trăm chỉ số theo nhóm. Vài chỉ số phải theo dõi:

INFO memory        # used_memory, maxmemory, mem_fragmentation_ratio
INFO stats         # keyspace_hits, keyspace_misses, instantaneous_ops_per_sec, evicted_keys
INFO replication   # role, connected_slaves, master_repl_offset, độ trễ replica
INFO persistence   # rdb_last_save_time, aof_last_bgrewrite_status
INFO clients       # connected_clients, blocked_clients

Chỉ số quan trọng nhất cho cache là cache hit ratio = keyspace_hits / (keyspace_hits + keyspace_misses). Tỉ lệ hit thấp nghĩa là cache không hiệu quả (TTL quá ngắn, key không được dùng lại, hoặc eviction quá mạnh). Cần theo dõi thêm evicted_keys (tăng nhanh = RAM chật, đang phải xoá dữ liệu) và expired_keys.

Latency — Redis đơn luồng nên một lệnh chậm chặn tất cả. Công cụ:

CONFIG SET latency-monitor-threshold 100   -- ghi lại sự kiện > 100ms
LATENCY LATEST                             -- các đợt trễ gần nhất
LATENCY DOCTOR                             -- chẩn đoán nguyên nhân độ trễ

SLOWLOG — nhật ký các lệnh vượt ngưỡng thời gian thực thi. Đây là công cụ số một để tìm "lệnh nào đang làm chậm Redis":

CONFIG SET slowlog-log-slower-than 10000   -- log lệnh chạy > 10000 micro-giây (10ms)
SLOWLOG GET 10                             -- 10 lệnh chậm gần nhất
SLOWLOG RESET

Slowlog thường lộ ngay các thủ phạm kinh điển: KEYS *, SMEMBERS/HGETALL trên tập khổng lồ, Lua script nặng, hay lệnh xoá key lớn (nên dùng UNLINK xoá bất đồng bộ thay DEL).

An toàn: KHÔNG expose Redis ra internet

Đây là mục quan trọng nhất về bảo mật, viết in đậm vì lỗi này gây vô số vụ rò rỉ dữ liệu ngoài đời thực: Redis mặc định không có xác thực mạnh và không bao giờ được để lộ ra internet công cộng. Một Redis mở cổng 6379 ra internet không có mật khẩu = bất kỳ ai cũng đọc/xoá được toàn bộ dữ liệu, thậm chí ghi file lên máy chủ. Các biện pháp bắt buộc, xếp lớp:

  1. Bảo vệ ở tầng mạng (quan trọng nhất): đặt Redis trong mạng riêng/VPC, chỉ cho các app-server tin cậy kết nối qua firewall/security-group. bind 127.0.0.1 10.0.1.10 chỉ lắng nghe trên interface nội bộ; giữ protected-mode on. Với ngân hàng, Redis phải nằm sau nhiều lớp mạng, tuyệt đối không public.

  2. ACL (từ Redis 6): thay cho requirepass một mật khẩu chung, ACL cho phép tạo nhiều user với quyền hạn giới hạn — chỉ được chạy một số lệnh, chỉ truy cập một số pattern key. Nguyên tắc least-privilege.

# tạo user chỉ đọc, chỉ được đụng key có prefix cache:
ACL SETUSER analyst on >MatKhauManh ~cache:* +@read -@dangerous
# vô hiệu hoá các lệnh nguy hiểm cho user thường
ACL SETUSER app on >Mk ~app:* +@all -FLUSHALL -FLUSHDB -CONFIG -KEYS
  1. TLS: bật mã hoá đường truyền client↔server và giữa các node cluster để chống nghe lén — bắt buộc khi lưu lượng đi qua ranh giới mạng có rủi ro.

  2. Đổi tên/vô hiệu hoá lệnh nguy hiểm: FLUSHALL, FLUSHDB, CONFIG, KEYS, DEBUG nên bị chặn hoặc rename với user ứng dụng để một lệnh nhầm không xoá sạch dữ liệu. Nguyên tắc bảo mật xếp lớp này song song với security & SRE ở tầng hạ tầng.

Backup và nâng cấp

Backup: cách chuẩn là sao lưu file RDB — nó là một file nhị phân nhất quán tại một thời điểm. Có thể chủ động BGSAVE để sinh snapshot rồi copy dump.rdb sang lưu trữ ngoài (S3/NAS), theo lịch. Với AOF cũng có thể backup file AOF (kèm file base). Đừng copy file đang được ghi mà không qua snapshot — dùng BGSAVE để có bản nhất quán.

Khôi phục: dừng Redis, đặt file dump.rdb (hoặc bộ AOF) vào dir, khởi động lại — Redis nạp từ file. Cần kiểm thử phục hồi định kỳ, không chỉ tạo backup rồi tin là dùng được.

Nâng cấp phiên bản: với cụm HA, nâng cấp rolling để không gián đoạn: nâng cấp các replica trước từng cái một, rồi failover để một replica đã nâng cấp thành primary, cuối cùng nâng cấp node primary cũ. Với Sentinel/Cluster, cơ chế failover giúp lần lượt thay từng node mà dịch vụ vẫn liên tục. Luôn đọc release note về thay đổi định dạng RDB/AOF trước khi nhảy phiên bản lớn — RDB thường tương thích tiến chứ không lùi.

Use case thực tế

Bối cảnh: Cụm Redis phục vụ session store + cache real-time cho mobile banking NCB: giữ ~800.000 phiên đăng nhập đang hoạt động giờ cao điểm, cache tỷ giá/hạn mức, và các counter chống gian lận (rate-limit OTP). Yêu cầu: HA (mất một node không được làm sập đăng nhập), không mất session âm thầm, và độ trễ ổn định dưới 1ms. Dataset khoảng 6 GB — vẫn vừa RAM một máy.

Thiết kế đã chọn:

  • Topology: một primary + hai replica + ba Sentinel (trên ba khu vực khác nhau, quorum = 2). Vì dataset vừa RAM, chọn Sentinel thay vì Cluster để đơn giản — chưa cần sharding. App-server kết nối qua Sentinel để tự tìm primary sau failover.
  • Persistence: bật AOF everysec (session/counter mất tối đa 1 giây khi crash — chấp nhận được) kèm RDB save 900 1 để có snapshot khôi phục nhanh và làm nguồn backup.
  • Bộ nhớ: maxmemory 8gb (dưới RAM 12 GB của máy, chừa chỗ cho fork + buffer), policy noeviction vì đây là store — thà báo lỗi ghi để cảnh báo tăng RAM còn hơn âm thầm xoá session người dùng đang đăng nhập.
  • An toàn: Redis nằm trong VPC nội bộ, protected-mode on, chỉ app-server được vào qua security-group; bật ACL (user app không có quyền FLUSHALL/CONFIG) và TLS cho lưu lượng client.
  • Giám sát: cảnh báo khi mem_fragmentation_ratio > 1.5, evicted_keys tăng, cache hit ratio tụt dưới ngưỡng, hoặc độ trễ replica tăng; slowlog ngưỡng 10ms để bắt lệnh nặng.

Kịch bản failover: một sáng primary treo do sự cố phần cứng. Sentinel phát hiện down-after-milliseconds (5s) → SDOWN; hai Sentinel còn lại đồng ý → ODOWN (đủ quorum 2); bầu leader, promote replica có độ trễ replication thấp nhất lên primary; replica còn lại trỏ về primary mới; app-server hỏi Sentinel và nhận địa chỉ primary mới — toàn bộ chưa tới ~10 giây, người dùng gần như không nhận ra. Nhờ AOF, primary mới có dữ liệu tới trước thời điểm crash chỉ ~1 giây, không mất session hàng loạt.

Khi hệ thống tăng trưởng và dataset vượt RAM một máy (ví dụ thêm cache lớn cho phân tích hành vi), đây sẽ là lúc chuyển từ Sentinel sang Redis Cluster — chia dữ liệu ra nhiều shard, dùng hash tag {customer_id} để giữ các key của cùng một khách trên một node. Tổng hợp các use case ngân hàng đầy đủ nằm ở bài use case ngân hàng.

Ghi nhớ

  • Redis bền vững được dù in-memory qua hai cơ chế: RDB (snapshot định kỳ — khôi phục nhanh, file gọn, nhưng có thể mất vài phút giữa hai snapshot) và AOF (append-only log mọi lệnh ghi — bền hơn, khôi phục chậm hơn). Thực tế thường kết hợp cả hai.
  • AOF fsync policy: always (an toàn nhất, chậm) / everysec (cân bằng khuyến nghị, mất tối đa ~1s) / no (nhanh nhất, rủi ro cao). AOF rewrite nén log về tập lệnh tối thiểu.
  • Replication primary-replica là async → mở rộng đọc + dự phòng, nhưng đọc replica có thể trễ và có thể mất ghi khi primary chết trước khi truyền. Bản thân replication không tự failover.
  • Sentinel = giám sát + tự động failover + service discovery cho HA; dùng quorum (≥3 Sentinel, số lẻ) để xác nhận ODOWN và tránh split-brain. Chọn khi dataset vừa RAM một máy.
  • Redis Cluster = sharding qua 16384 hash slot (CRC16(key) mod 16384), scale ngang + HA nội tại. Cảnh báo: multi-key op phải cùng slot — dùng hash tag {...} để ép key liên quan vào một slot. Chỉ dùng khi thực sự vượt RAM/thông lượng một node.
  • Eviction policy: cache → allkeys-lru/lfu; store → noeviction (báo lỗi thay vì âm thầm xoá). volatile-* chỉ xoá key có TTL.
  • Bộ nhớ: đặt maxmemory dưới RAM vật lý; theo dõi fragmentation ratio (>1 phân mảnh, <1 đang swap — rất xấu). Không để Redis swap.
  • Giám sát: INFO (hit ratio, evicted_keys, replication), SLOWLOG (bắt lệnh nặng), LATENCY. Redis đơn luồng nên một lệnh chậm chặn tất cả.
  • An toàn: KHÔNG BAO GIỜ expose Redis ra internet. Bảo vệ ở tầng mạng (VPC/firewall, protected-mode), ACL least-privilege, TLS, vô hiệu hoá FLUSHALL/CONFIG cho user ứng dụng.
  • Backup bằng RDB snapshot (BGSAVE rồi copy ra ngoài), kiểm thử phục hồi định kỳ; nâng cấp rolling qua failover để không gián đoạn.

Bài viết liên quan

Cách index hoạt động (B-Tree), đọc EXPLAIN, seq scan vs index scan và mẫu tối ưu truy vấn.

13 thg 7, 2026 4

Khoá, ràng buộc, quan hệ và chuẩn hoá 1NF/2NF/3NF — thiết kế lược đồ đúng từ đầu.

13 thg 7, 2026 4

Kết nhiều bảng đúng cách: các loại JOIN, bẫy thường gặp và phép hợp tập.

13 thg 7, 2026 3

Truy vấn lồng, CTE (WITH), CTE đệ quy và hàm cửa sổ — vũ khí cho phân tích nâng cao.

13 thg 7, 2026 3