Skip to content

Ma trận so sánh các pattern

Một số pattern trông giống nhau nhưng phục vụ mục đích khác. Hướng dẫn này so sánh các cặp dễ nhầm lẫn để giúp bạn chọn đúng công cụ.

Cache vs Pool

Khía cạnhLRU CacheObject Pool
Mục đíchTăng tốc tra cứu lặp lạiTránh chi phí cấp phát/GC
Loại bỏPhần tử ít dùng gần nhất bị bỏNgười dùng trả lại, tái sử dụng
Nội dungGiá trị cache chỉ đọcObject mutable, có thể tái dùng
Tỉ lệ hitPhụ thuộc mẫu truy cập100% (cấp phát trước)
Ví dụDNS cache, HTTP cachePool kết nối DB, thread pool
Khi nhầm lẫnNếu bạn đang "cache" object để dùng lại→ đó là pool

Arena Allocator vs Free List

Khía cạnhArena AllocatorFree List
Cấp phátO(1) bump pointerO(1) pop từ chuỗi free
Giải phóngChỉ tất cả một lầnTrả từng cái O(1)
Phân mảnhKhông (liền kề)Có thể (không liền kề)
Vòng đờiTheo pha (parse, render)Từng object
Ví dụArena của compiler mỗi queryTái chế entity game
Khi nhầm lẫnNếu cần giải phóng riêng→ dùng free list

Observer vs Actor Model

Khía cạnhObserverActor Model
Giao tiếpCallback đồng bộThông điệp bất đồng bộ
Liên kếtBộ nhớ chung, cùng threadTrạng thái cô lập, ở bất kỳ vị trí nào
Mở rộngMột processHệ phân tán
Cô lập lỗiMột observer hỏng chặn tất cảActor crash độc lập
Ví dụDOM event, React stateErlang/OTP, Akka
Khi nhầm lẫnNếu observer cần cô lập→ dùng actor

Skip List vs B+ Tree

Khía cạnhSkip ListB+ Tree
Cân bằngTheo xác suất (tầng ngẫu nhiên)Xác định (split/merge)
ConcurrencyCó thể lock-freeKhoá phức tạp
I/O đĩaKém (đuổi con trỏ)Xuất sắc (fanout cao)
Triển khaiĐơn giản (~100 dòng)Phức tạp (~500+ dòng)
Ví dụSorted set của Redis, memtable LevelDBInnoDB của MySQL, chỉ mục filesystem
Khi nhầm lẫnDữ liệu sắp xếp trong bộ nhớ → skip listTrên đĩa → B+ tree

Ring Buffer vs Queue (FIFO)

Khía cạnhRing BufferQueue chuẩn
Sức chứaCố định, cấp phát trướcĐộng, tăng theo nhu cầu
TrànGhi đè cái cũ nhất (hoặc chặn)Cấp phát thêm bộ nhớ
Bộ nhớO(sức chứa), không cấp phátO(n), có thể gây GC
Trường hợp dùngBuffer giới hạn, luồng audioQueue task không giới hạn
Ví dụio_uring của Linux, loggingMessage queue, BFS
Khi nhầm lẫnNếu biết sức chứa → ring bufferNếu không giới hạn → queue

Copy-on-Write vs Double Buffering

Khía cạnhCopy-on-WriteDouble Buffering
Số buffer1 (clone khi ghi)2 (luôn cấp phát)
Kích hoạt copyKhi sửa đổiKhông bao giờ (đổi con trỏ)
Chi phí đọcO(1) luônO(1) luôn
Chi phí ghiO(n) clone ở lần ghi đầuO(ghi) vào back buffer
Bộ nhớO(n) chỉ khi đã ghiO(2n) luôn
Ví dụLinux fork(), Rc<T>Render GPU, vòng lặp game
Khi nhầm lẫnNếu ghi hiếm → CoWNếu ghi liên tục → double buffer

Circuit Breaker vs Rate Limiter

Khía cạnhCircuit BreakerRate Limiter
Bảo vệBên gọi khỏi downstream hỏngServer khỏi traffic quá tải
Kích hoạtNgưỡng số lần lỗiNgưỡng số request
HướngĐi ra (cuộc gọi của bạn tới người khác)Đi vào (cuộc gọi của người khác tới bạn)
Phục hồiTự khôi phục sau timeoutRefill token theo thời gian
Ví dụMicroservice → databaseAPI gateway, login attempt
Khi nhầm lẫnBảo vệ chính mình → circuit breakerBảo vệ server → rate limiter

State Machine vs Strategy/Vtable

Khía cạnhState MachineVtable
Dispatch theoTrạng thái hiện tạiKiểu object
Chuyển tiếpRõ ràng, có guardKhông áp dụng
Số trạng tháiThay đổi lúc runtimeCố định lúc compile
Kiểm tra"Chuyển này có hợp lệ không?""Triển khai nào sẽ gọi?"
Ví dụTrạng thái kết nối TCPTrait object, interface
Khi nhầm lẫnNếu hành vi thay đổi theo thời gian → state machineNếu khác theo kiểu → vtable

Bloom Filter vs Hash Set

Khía cạnhBloom FilterHash Set
Dương tính giảCó (điều chỉnh được)Không
Âm tính giảKhôngKhông
Bộ nhớ~10 bit/phần tử~50+ byte/phần tử
XoáKhông hỗ trợO(1)
Trường hợp dùngKiểm tra nhanh "chắc chắn không có trong tập"Kiểm tra thành viên chính xác
Ví dụChrome Safe Browsing, filter đọc LSMKhử trùng lặp, URL đã thăm
Khi nhầm lẫnNếu chấp nhận 1% dương tính giả + cần tiết kiệm bộ nhớ→ Bloom filter

Write-Ahead Log vs Checkpointing

Khía cạnhWrite-Ahead LogCheckpointing
Mức chi tiếtMỗi thao tácSnapshot định kỳ
Khôi phụcReplay từ checkpoint cuốiTải snapshot + replay phần WAL còn lại
Dung lượng đĩaTăng không giới hạn (nếu không cắt)Cố định mỗi snapshot
Chi phí ghiO(1) append mỗi thao tácO(kích thước state) mỗi snapshot
Dùng chung? — WAL đảm bảo bền vữngCheckpoint giới hạn độ dài replay
Ví dụWAL của PostgreSQL, AOF của RedisBase backup PostgreSQL, RDB Redis

Backpressure vs Rate Limiter

Khía cạnhBackpressureRate Limiter
HướngProducer → Consumer (tín hiệu ngược lên)Bên ngoài → Server (thi hành tại gateway)
Cơ chếLàm chậm/tạm dừng producerBỏ hoặc xếp hàng request thừa
Phạm viKiểm soát luồng nội bộ pipelineBiên API bên ngoài
Thích nghiĐộng (điều chỉnh theo tốc độ consumer)Ngưỡng tĩnh (token/giây)
Ví dụNode.js stream .pipe(), Reactive StreamsAPI Stripe 25 req/giây, Nginx limit_req
Khi nhầm lẫnNếu bạn kiểm soát producer → backpressureNếu không kiểm soát được bên gửi → rate limiter

Tombstone vs Dirty Flag

Khía cạnhTombstoneDirty Flag
Đánh dấu"Item này đã bị xoá""Item này cần tính lại"
Vòng đờiVĩnh viễn cho đến khi compactionXoá sau khi tính lại
Mục đíchHoãn xoá vật lýHoãn tính lại tốn kém
Hiển thịReader phải bỏ qua item có tombstoneReader thấy giá trị cũ-cho-đến-khi-tính-lại
Ví dụTombstone Cassandra, marker xoá LevelDBInvalidation layout Chromium, transform game
Khi nhầm lẫnNếu đánh dấu "đã mất" → tombstoneNếu đánh dấu "cần update" → dirty flag

Interning vs Flyweight

Khía cạnhInterningFlyweight
Chia sẻCác giá trị giống nhau dùng chung một instanceTrạng thái nội tại chung, trạng thái ngoại tại khác
Tra cứuBảng toàn cục (hash map)Factory với cache
Định danhSo sánh bằng con trỏ thay vì so giá trịObject vẫn so sánh theo giá trị
Khả năng đổiBất biến (bắt buộc)Nội tại bất biến, ngoại tại có thể đổi
Ví dụsys.intern() Python, Symbol Rust, string pool JavaGlyph font, sprite tile game, object CSS rule
Khi nhầm lẫnNếu mọi instance đều giống hệt → interningNếu các instance chia sẻ trạng thái một phần → flyweight

Event Loop vs Work Stealing

Khía cạnhEvent LoopWork Stealing
ThreadMột thread + ghép kênh I/ONhiều thread, mỗi cái một deque
Tốt nhất choI/O-bound, nhiều kết nốiCPU-bound, đệ quy/song song
Lập lịchCooperative (callback/promise)Preemptive lấy trộm từ các deque khác
Độ trễMột callback chậm chặn tất cảThread rảnh lấy việc, giữ cân bằng
Ví dụNode.js, Nginx, RedisScheduler Go, ForkJoinPool Java, Tokio
Khi nhầm lẫnNếu chủ yếu là I/O + ít CPU → event loopNếu nặng CPU + nhiều core → work stealing

Visitor vs Middleware Chain

Khía cạnhVisitorMiddleware Chain
DuyệtĐi qua cây/đồ thị các node có kiểuĐi qua pipeline tuyến tính
DispatchTheo kiểu node (double dispatch)Theo thứ tự đăng ký
Thêm thao tácVisitor mới = thao tác mớiMiddleware mới = lớp mới
Luồng dữ liệuVisitor tích luỹ kết quảRequest/response chảy qua
Ví dụPass LLVM IR, biến đổi ASTExpress.js, Django, interceptor gRPC
Khi nhầm lẫnNếu xử lý cây không đồng nhất → visitorNếu xử lý pipeline request/response → middleware

Chọn pattern phù hợp: Flowchart quyết định

?Need to store/retrieve data?
?Need to manage concurrency?
?Need resilience?
?Need memory efficiency?

Released under the MIT License.