Welcome to MikeDaDev's Blog – notes on Java, backend & system design.

Explore
MikeDaDev's Blog

#architecture

Things I've written about #architecture
  • Thiết kế hệ thống lưu trữ tài liệu trong thời đại số hoá

    Ảnh CCCD lúc mở tài khoản, hợp đồng vay ký điện tử, sao kê tháng: mỗi ngày một ngân hàng vài chục triệu khách sinh ra hàng triệu file, và file nào cũng phải giữ đúng người xem, đúng thời hạn, không được mất. Bài này dựng một kiến trúc tham chiếu cho nền tảng lưu trữ tài liệu cỡ đó: ước lượng tải, upload chia chunk, lưu theo tầng nóng ấm lạnh, phân quyền RBAC kết hợp ABAC, mã hoá envelope, và những kiểu hỏng hay gặp khi chạy thật.

  • Discord: từ Cassandra sang ScyllaDB

    Nhìn lại chặng đường Discord lưu hàng nghìn tỷ tin nhắn: từ lúc MongoDB hết chịu nổi, qua Apache Cassandra, rồi chuyển hẳn sang ScyllaDB với mô hình thread-per-core, hết JVM GC pause, p99 latency đọc còn khoảng 15ms và số node giảm từ 177 xuống 72.

  • Figma: scale PostgreSQL với Horizontal Sharding

    Figma làm Horizontal Sharding cho PostgreSQL thế nào: nhóm bảng theo colo, hash shard key để tránh hotspot, proxy DBProxy định tuyến bằng SQL AST, shard "logic" bằng view trước khi tách vật lý, và lần failover đầu tiên chỉ mất khoảng 10 giây sẵn sàng một phần.

  • Spring AI: Dynamic Tool Calling

    Dynamic Tool Calling trong Spring AI: bài toán chi phí token khi nhét hết tool vào Context Window, cách viết CallAdvisor để chọn tool theo ngữ nghĩa qua Vector Store, và cách tự động lập chỉ mục các @Tool bean.

  • jev engineering: make ai intelligent more like human

    Sao phải đốt tiền gọi LLM cồng kềnh chỉ để kiểm tra một điều kiện Boolean? Bài này nói về Jev Engineering: mô hình AI System 1 phi tự hồi quy (Non-autoregressive), rẽ nhánh theo ngữ nghĩa với độ trễ cỡ 70-500ms, rẻ hơn LLM nhiều lần theo công bố của TypeSafe, và đầu ra luôn đúng kiểu.

  • Feature Flags với Unleash & Spring Boot

    Feature Flags với Unleash trong Spring Boot 3: 4 nhóm toggle theo cách chia của Pete Hodgson, cách Unleash đánh giá flag ngay trong bộ nhớ phía client và đồng bộ qua Server-Sent Events, chuyện MurmurHash3 chia user khi gradual rollout, và dùng Strategy Pattern để thoát khỏi đống if-else.

  • Java Memory Model & happens-before

    Đào vào Java Memory Model (JSR-133): giao thức MESI, Store Buffer, 4 loại Memory Barrier, quan hệ Happens-Before, chuyện False Sharing (@Contended), và Acquire/Release với VarHandle từ Java 9.

  • cạm bẫy Virtual Threads trong production

    Bật Virtual Threads trong Java 21 xong ứng dụng production lại treo? Bài này đi qua 4 chỗ hay dính: pinning carrier thread do synchronized (và chuyện JDK 24 đã sửa nó), ThreadLocal làm phình bộ nhớ, pool thread không cần thiết và connection pool bị đè bẹp, kèm cách xử lý cho từng cái.

  • Database Sharding system design

    Lúc nào thì một node SQL không còn gánh nổi tải? Bài này nói về cách ước tính dung lượng nhanh (back-of-the-envelope), cách chọn sharding key, chuyện transaction phân tán và kinh nghiệm từ các hệ thống tài chính.

  • case study Shopify: Redis to MySQL

    Black Friday 2025 đạt đỉnh 5.1 triệu USD/phút, và đó cũng là mùa đầu tiên Shopify giữ chỗ tồn kho bằng MySQL thay cho Redis. Vì sao bỏ Redis, vì sao câu UPDATE trừ số lượng quen thuộc không đủ, và thiết kế một dòng cho mỗi đơn vị hàng với SKIP LOCKED chạy ra sao.

  • Rate Limiting với Bucket4j trong Spring Boot

    Vì sao chỉ rate limit ở Nginx là chưa đủ? Mổ xẻ thuật toán Token Bucket, cách Bucket4j xử lý concurrency không cần lock, và cách dựng rate limiting phân tán với Redis trong Spring Boot để chạy production.

  • RestClient & Fluent API trong Spring Boot 3

    Vì sao RestTemplate bị cho vào chế độ bảo trì rồi sắp bị deprecate? Bài này nói về RestClient và JdbcClient, hai món mới theo kiểu Fluent API từ Spring Framework 6.1 / Spring Boot 3.2, viết gọn hơn, đọc dễ hơn và ít chỗ truyền nhầm tham số hơn.

  • CDC với Debezium & cache invalidation

    Change Data Capture (CDC) với Debezium nhìn từ bên trong: PostgreSQL logical decoding (pgoutput) chạy ra sao, vì sao dual-write dính partial failure và race condition, cách dùng Outbox Event Router (SMT), chống cache stampede và canh replication slot trên production.

  • jOOQ vs Hibernate JPA

    Vì sao nhiều team làm hệ thống tài chính cân nhắc jOOQ bên cạnh Hibernate? Chi phí ngầm của ORM, Type-safe SQL của jOOQ, những chỗ Hibernate 6 đã bắt kịp, và kiến trúc Hybrid dùng cả hai.

  • Spring Modulith

    Trước khi chia hệ thống thành Microservices và ôm theo đủ thứ đau đầu về network, distributed transaction, observability, thử xem Spring Modulith: giải pháp chính thức từ Spring để làm Modular Monolith với ranh giới module rõ ràng, tự kiểm tra phụ thuộc và event nội bộ giữa các module.

  • map vs flatmap

    map và flatMap trong Java nhìn từ gốc là Monadic Bind: flatMap cấp phát bộ nhớ thế nào trong Stream, thay bằng mapMulti (Java 16) để đỡ GC Churn, thenCompose trong CompletableFuture, và cái bẫy mất thứ tự khi dùng flatMap trong Reactive Streams.

  • java 25 LTS

    A close look at Java 25 LTS: Compact Object Headers (JEP 519), Stream Gatherers (JEP 485), Flexible Constructor Bodies (JEP 513), Scoped Values (JEP 506) and Generational ZGC, with notes on what they change for high-throughput cloud services.

  • nâng cấp java 25 LTS

    Nhìn Java 25 LTS từ góc độ người làm kiến trúc: so với Java 21/17 thì hơn ở đâu. Compact Object Headers (JEP 519), Stream Gatherers (JEP 485), Flexible Constructor Bodies (JEP 513), Generational ZGC & Shenandoah, Scoped Values (JEP 506), và cách tính bài toán ROI khi nâng cấp hệ thống cloud-native.

  • in aws / cloud

    amazon S3

    Ghi chú dùng Amazon S3 cho hệ thống lớn: Strong Read-After-Write Consistency là gì, dùng Presigned Multipart Upload để backend khỏi gánh băng thông, bảo mật với SSE-KMS và IRSA trên Kubernetes, và cái bẫy tốn tiền mang tên AbortIncompleteMultipartUpload.

  • multi-module spring boot

    Mổ xẻ kiến trúc Multi-Module Spring Boot cho production: chia module theo Hexagonal/Clean Architecture, tách riêng JPA/DataSource cho từng module, tránh mở connection pool tràn lan, xử lý cái bẫy bytea của JDBC PostgreSQL và dùng ArchUnit để giữ ranh giới module.

  • kiến trúc RabbitMQ

    Dựng RabbitMQ cho production cần biết gì: Erlang OTP/BEAM bên dưới, ghép nhiều Channel trên một TCP Connection, bỏ Mirrored Queues để chuyển sang Quorum Queues (Raft), không mất message nhờ Producer Confirms và Manual ACK, cùng Dead Letter Queue (DLQ) kèm retry exponential backoff.

  • kiến trúc observability với grafana

    Kiến trúc Observability với Grafana và LGTM Stack (Loki, Grafana, Tempo, Mimir): 4 Golden Signals, RED/USE, cảnh báo Error Budget Multi-Window Multi-Burn-Rate theo kiểu Google SRE, và cách tránh bẫy bùng nổ Cardinality trong PromQL.

  • in sql / oracle

    tối ưu SQL trong Oracle

    Ghi chép tối ưu Oracle SQL cho Database Architect và Principal Engineer: Cost-Based Optimizer (CBO) chạy ra sao, 5 kiểu Index Access Path, Hash Join tràn PGA, cách đọc DBMS_XPLAN với ALLSTATS LAST, và cách khoá Plan bằng SQL Plan Management (SPM).

  • in sql / oracle

    oracle ROWNUM

    ROWNUM trong Oracle chạy bên trong thế nào: vì sao ROWNUM > 1 luôn ra rỗng, COUNT STOPKEY trong execution plan giúp dừng quét sớm ra sao, và nên chọn subquery ROWNUM, window function ROW_NUMBER() hay cú pháp ANSI OFFSET-FETCH của Oracle 12c+.

  • câu hỏi phỏng vấn java senior

    Các câu hỏi phỏng vấn nâng cao cho Senior & Staff Software Engineer: False Sharing & Cache Line 64-byte, bẫy Carrier Pinning trong Virtual Threads, Parent-Child Connection Starvation trong HikariCP, Zero-Allocation trên đường dẫn hiệu năng cao và thiết kế Idempotency.

  • docker & container

    Mổ xẻ container và Docker từ bên trong: Linux Namespaces, Cgroups v2, OverlayFS; viết Dockerfile multi-stage, layered, chạy distroless non-root; xử lý dứt điểm chuyện PID 1 và graceful shutdown; cấu hình JVM nhận biết container để khỏi dính OOMKilled.

  • visitor pattern

    Visitor Pattern trong Java hoạt động ra sao: cơ chế Double Dispatch để lách giới hạn Single Dispatch của JVM, dùng để duyệt cây cú pháp (AST), và đặt cạnh Pattern Matching trên Sealed Types của Java 21 xem bên nào hơn.

  • iterator pattern

    Đào sâu Iterator Pattern trong Java: fail-fast hoạt động nhờ biến modCount ra sao, CopyOnWriteArrayList đổi bộ nhớ lấy an toàn thế nào, Spliterator giúp chạy song song ra sao, và cách tự viết cursor iterator để stream hàng triệu bản ghi mà không OOM.

  • coding convention và chuẩn mực java

    Ghi chú về coding convention cho team Java: dùng chuẩn Google, bỏ package-by-layer để chuyển sang Vertical Slice, chặn NullPointer bằng JSpecify & NullAway, và kiểm tra ranh giới kiến trúc tự động trong CI/CD bằng ArchUnit.

  • adapter pattern

    Adapter Pattern trong Java, từ bản chất OOP tới kiến trúc Lục Giác (Ports and Adapters), cách dựng Anti-Corruption Layer (ACL) để bảo vệ Domain Model trước hệ thống Legacy, và phân biệt Adapter với Facade, Proxy, Decorator.

  • prototype pattern

    Prototype Pattern trong Java: vì sao Cloneable bị coi là lỗi thiết kế của JDK, khác nhau giữa Shallow Copy và Deep Copy, và so sánh 4 cách nhân bản object dùng được trên production (Copy Constructor, Jackson, Kryo, Record Withers).

  • builder pattern

    Đào sâu Builder Pattern trong Java: vì sao JavaBeans Pattern và Telescoping Constructor dễ gây lỗi, cách dùng Staged Builder để thiếu trường bắt buộc là compile không qua, và khi nào nên dùng Lombok @Builder hay Java Records.

  • multi-module Spring Boot với Gradle

    Dựng Multi-Module Spring Boot 3 với Gradle hiện đại: bỏ anti-pattern subprojects/allprojects, dùng Convention Plugins để tái sử dụng cấu hình, quản lý dependency tập trung bằng Version Catalog (libs.versions.toml), hiểu compile avoidance giữa api và implementation, và xử lý xung đột bootJar vs jar.

  • functional interfaces & lambda trong java

    Lambda và Functional Interface chạy thế nào bên trong JVM: vì sao lambda không phải Anonymous Inner Class, invokedynamic và LambdaMetafactory làm gì, tại sao biến phải effectively final, và cách dựng một Policy Engine bằng hàm.

  • arraylist vs linkedlist

    Vì sao ArrayList gần như luôn nhanh hơn LinkedList trong Java: chuyện CPU Cache Line và spatial locality, chỗ hao bộ nhớ của Node header, cái hiểu lầm sách giáo khoa về tốc độ chèn của LinkedList, và ArrayDeque, lựa chọn nên dùng thay thế.

  • hibernate ORM

    Hibernate ORM bên trong chạy thế nào: 4 trạng thái vòng đời của Entity (Transient, Persistent, Detached, Removed), Dirty Checking tự động qua Loaded Snapshots, First-Level vs Second-Level Cache, và cách tiết kiệm bộ nhớ với @Transactional(readOnly = true).

  • custom annotations trong java

    Annotation trong Java chạy thế nào bên trong JVM: bytecode attribute, dynamic proxy, meta-annotation của Spring (@AliasFor), rồi tự viết một custom annotation dùng Spring AOP và SpEL để làm rate limiting phân tán dùng được cho production.

  • Spring Security annotations

    Kiến trúc bảo mật của Spring Security: hai lớp phòng thủ FilterChain và AOP Method Security, SpEL trong @PreAuthorize, bẫy Side-Effect của @PostAuthorize, vấn đề hiệu năng của @PostFilter và cách thiết lập Role Hierarchy cho production.

  • Spring IoC & Dependency Injection

    Mổ xẻ bên trong Spring IoC Container: DIP, IoC và DI khác nhau ra sao, vòng đời của một bean trong ApplicationContext, cách Spring gỡ circular dependency bằng cache 3 tầng (three-level cache), và vì sao field injection với @Autowired bị loại khỏi code enterprise.

  • in java / jvm

    java reflection

    Mổ xẻ Java Reflection bên trong JVM: cơ chế inflation từ JNI sang bytecode accessor (tới JDK 17) và bản viết lại bằng method handle từ JDK 18, vì sao reflection khó cho JIT inline, chuyện setAccessible bị chặn từ JDK 16/17, và vì sao MethodHandles cùng code sinh lúc compile hợp với GraalVM AOT hơn.

  • java stream API

    Nhìn vào bên trong Java Stream API: pipeline được dựng thế nào, Loop Fusion chạy qua interface Sink ra sao, Stateless khác Stateful operation chỗ nào, và vì sao parallelStream xài chung ForkJoinPool có thể làm treo cả hệ thống.

  • java ThreadPoolExecutor

    Mổ ThreadPoolExecutor từ bên trong: biến ctl gói bit thế nào, vì sao mấy static factory của Executors là quả bom OOM, vì sao Worker tự dựng khoá không tái nhập trên AQS, 4 cách xử lý backpressure và quy trình graceful shutdown 2 pha để chạy production.

  • in java / jvm

    kiến trúc JVM

    Đi một vòng bên trong HotSpot JVM cho dân làm phần mềm: file bytecode 0xCAFEBABE trông ra sao, ClassLoader uỷ quyền theo Parent Delegation Model thế nào, các vùng nhớ Runtime Data Areas (Stack Frame, Metaspace, Heap), và JIT biên dịch phân tầng (Tiered Compilation C1/C2).

  • controlled concurrency with semaphores

    A practical look at backpressure and concurrency limits in Java: how java.util.concurrent.Semaphore works on top of AbstractQueuedSynchronizer (AQS), why Virtual Threads waiting on it unmount instead of pinning their carrier, how to size the limit with Little’s Law, and patterns that hold up in production.