Menu
ESC

Nhập từ khóa để tìm kiếm

↑↓ Di chuyển
Enter Mở
ESC Đóng

Đang tải...

Microservices vs Monoliths cho BA

API and Technical Fundamentals cho BA Bài 38/60

Mở đầu — vì sao bài này quan trọng

Hãy tưởng tượng bạn là BA đang ngồi trong một buổi họp kiến trúc hệ thống. Tech lead vừa nói: "Cái này nên tách thành microservice riêng, đừng nhét vào monolith nữa." Cả phòng gật gù, còn bạn — người đáng lẽ phải dịch những quyết định kỹ thuật này thành ngôn ngữ nghiệp vụ cho stakeholder — thì ngồi đó không hiểu vì sao chuyện "tách hay không tách" lại quan trọng đến vậy.

Đây là một trong những tình huống thật mà rất nhiều BA gặp phải. Microservices và Monolith không chỉ là chủ đề của lập trình viên. Nó ảnh hưởng trực tiếp đến những thứ bạn quan tâm hằng ngày: thời gian một tính năng ra mắt mất bao lâu, một thay đổi nhỏ có làm sập cả hệ thống không, đội ngũ cần bao nhiêu người, chi phí vận hành ra sao, và quan trọng nhất — khi bạn viết một yêu cầu nghiệp vụ, nó sẽ "chạm" vào bao nhiêu phần của hệ thống.

Là BA, bạn không cần biết viết code để triển khai microservice. Nhưng bạn cần hiểu đủ sâu để: đặt câu hỏi đúng khi review thiết kế, ước lượng được độ phức tạp của một yêu cầu, và giải thích cho business vì sao "tính năng tưởng đơn giản" lại tốn 3 sprint. Bài này sẽ trang bị cho bạn đúng lượng kiến thức đó — không nhiều hơn, không ít hơn.

Khái niệm cốt lõi

Monolith là gì

Monolith (kiến trúc khối nguyên) là cách xây dựng phần mềm "tất cả trong một". Toàn bộ chức năng — quản lý người dùng, đơn hàng, thanh toán, thông báo — nằm chung trong một codebase (mã nguồn), được đóng gói thành một ứng dụng duy nhất, deploy (triển khai) một lần, và thường dùng chung một database (cơ sở dữ liệu).

        [ Monolith App ]
        ├── User module
        ├── Order module
        ├── Payment module
        └── Notification module
                │
                ▼
          [ Single DB ]

Hãy hình dung một tòa nhà chung cư. Tất cả căn hộ nằm trong một khối bê tông. Muốn sửa hệ thống điện của tầng 5, đôi khi bạn phải cắt điện cả tòa nhà. Đó chính là tinh thần của monolith: mọi thứ gắn chặt vào nhau.

Microservices là gì

Microservices (kiến trúc vi dịch vụ) chia ứng dụng thành nhiều dịch vụ nhỏ, độc lập. Mỗi service đảm nhận một nghiệp vụ riêng, có codebase riêng, thường có database riêng, deploy độc lập, và giao tiếp với nhau qua API (thường là REST API hoặc message queue).

[User Service]   [Order Service]   [Payment Service]   [Notification Service]
     │                 │                  │                     │
  [User DB]        [Order DB]        [Payment DB]          [Notif DB]
     └─────────────────┴── gọi nhau qua API / message ──┴──────┘

Quay lại phép so sánh: thay vì một tòa chung cư, microservices giống một khu phố gồm nhiều ngôi nhà riêng. Muốn sửa điện nhà số 5 thì chỉ nhà số 5 mất điện, các nhà khác vẫn sinh hoạt bình thường. Nhưng đổi lại, để các nhà "nói chuyện" với nhau, bạn phải xây đường sá, lắp điện thoại — tức là tốn thêm hạ tầng giao tiếp.

So sánh trên những trục mà BA quan tâm

Thay vì học vẹt ưu nhược điểm, hãy nhìn qua lăng kính BA — những trục thực sự ảnh hưởng đến công việc của bạn:

Tốc độ ra mắt tính năng (time to market). Monolith ban đầu nhanh hơn — một đội, một codebase, dễ phối hợp. Khi hệ thống còn nhỏ, microservices là gánh nặng không cần thiet. Nhưng khi monolith phình to (hàng triệu dòng code, hàng chục người cùng sửa), mỗi lần deploy trở thành nỗi sợ, và lúc đó microservices lại nhanh hơn vì các đội triển khai độc lập.

Phạm vi ảnh hưởng của một thay đổi (blast radius). Đây là khái niệm cực kỳ quan trọng với BA. Trong monolith, sửa module thanh toán có nguy cơ làm hỏng module đơn hàng vì chúng chung code, chung DB. Trong microservices, mỗi service được cô lập — lỗi ở Payment Service không trực tiếp làm sập User Service. Khi bạn viết yêu cầu, hiểu blast radius giúp bạn cảnh báo rủi ro sớm.

Khả năng mở rộng (scalability). Giả sử ngày sale lớn, lượng đặt hàng tăng 10 lần nhưng lượng đăng ký mới không đổi. Với microservices, bạn chỉ cần "nhân bản" Order Service mà không động đến phần còn lại. Với monolith, bạn phải nhân bản cả khối — tốn tài nguyên hơn nhiều.

Đội ngũ và tổ chức (định luật Conway). Có một quy luật nổi tiếng: cấu trúc phần mềm phản ánh cấu trúc tổ chức. Microservices hợp với công ty có nhiều đội nhỏ, tự chủ. Monolith hợp với đội nhỏ, gọn. Là BA, nếu công ty bạn chỉ có 5 lập trình viên mà đòi chia 15 microservices, bạn nên đặt dấu hỏi.

Độ phức tạp vận hành. Microservices "dễ" với developer viết code nhưng "khó" với cả hệ thống: cần thêm monitoring, distributed tracing, service discovery, xử lý lỗi mạng giữa các service. Một yêu cầu nghiệp vụ tưởng đơn giản như "hiển thị tổng đơn hàng của khách" có thể phải gọi qua 4 service khác nhau.

Tính nhất quán dữ liệu — cái bẫy lớn nhất cho BA

Trong monolith với một DB, khi bạn ghi đơn hàng và trừ kho cùng lúc, database đảm bảo cả hai hoặc cùng thành công hoặc cùng thất bại (transaction). Trong microservices, Order Service và Inventory Service có DB riêng — không còn transaction chung. Lúc này hệ thống phải chấp nhận "eventual consistency" (nhất quán sau cùng): dữ liệu sẽ đồng bộ, nhưng có thể trễ vài giây.

Vì sao BA phải biết điều này? Vì nó ảnh hưởng trực tiếp đến yêu cầu nghiệp vụ. Nếu business yêu cầu "số dư ví phải chính xác tức thời tuyệt đối", bạn cần biết rằng yêu cầu đó rất khó (và đắt) trong kiến trúc microservices, và nên thương lượng lại với stakeholder.

Tình huống thực tế

Tình huống 1: Startup giao đồ ăn tách monolith quá sớm

Một startup giao đồ ăn tại TP.HCM (tạm gọi là FoodNow) có 6 lập trình viên. Đọc nhiều bài viết về Grab, Tiki, họ quyết định "làm chuẩn microservices từ đầu" và chia thành 12 service: nhà hàng, món ăn, đơn hàng, tài xế, thanh toán, khuyến mãi, đánh giá, thông báo...

Sau 8 tháng, đội ngũ kiệt sức. Mỗi tính năng nhỏ — ví dụ "thêm mã giảm giá vào đơn hàng" — phải sửa 4 service, viết API giữa chúng, và test sự phối hợp. Một bug khó chịu xuất hiện: thỉnh thoảng đơn hàng đã đặt nhưng tài xế không nhận được vì message giữa Order Service và Driver Service bị mất. Đội dành 40% thời gian để xử lý các vấn đề hạ tầng thay vì làm tính năng mới.

Bài học rút ra: Microservices không miễn phí. Với một đội nhỏ và sản phẩm chưa rõ hình hài, monolith (hoặc "modular monolith" — monolith chia module gọn gàng bên trong) sẽ giúp ra sản phẩm nhanh hơn nhiều. Là BA, nếu bạn thấy đội nhỏ mà kiến trúc chia vụn, hãy nêu lên rủi ro về tốc độ và chi phí vận hành. Câu hỏi vàng: "Chúng ta có thực sự cần mỗi service deploy độc lập ngay bây giờ không?"

Tình huống 2: Sàn thương mại điện tử buộc phải tách monolith

Một sàn TMĐT khu vực Đông Nam Á (tạm gọi ShopViet) khởi đầu bằng một monolith PHP gọn gàng. Hai năm đầu rất tốt. Nhưng đến năm thứ ba, codebase phình lên hơn 1 triệu dòng, 60 lập trình viên cùng làm. Mỗi lần deploy mất 2 tiếng, phải làm vào 2 giờ sáng, và chỉ một lỗi nhỏ ở phần tìm kiếm cũng khiến cả trang web — gồm cả thanh toán — phải rollback (quay lui).

Đỉnh điểm là dịp sale 12/12: lượng truy cập tìm kiếm tăng vọt làm sập máy chủ, kéo theo cả chức năng thanh toán chết theo dù thanh toán không hề quá tải. Đây chính là "blast radius" quá lớn của monolith.

Họ quyết định tách dần. Đầu tiên là Search Service (vì nó cần scale riêng), rồi Payment Service (vì nó cần ổn định và bảo mật riêng). Họ KHÔNG tách tất cả cùng lúc — chỉ tách những phần có lý do nghiệp vụ rõ ràng. Sau 1 năm, dịp sale tiếp theo: search có thể bị chậm nhưng thanh toán vẫn chạy mượt, doanh thu không bị gián đoạn.

Bài học rút ra: Tách microservices nên dựa trên nhu cầu nghiệp vụ thật, không phải trào lưu. Tách phần nào cần scale riêng, cần độ ổn định riêng, hoặc do một đội riêng sở hữu. BA đóng vai trò then chốt ở đây: bạn là người hiểu phần nào của hệ thống có đặc thù nghiệp vụ riêng để gợi ý ranh giới tách hợp lý.

Tình huống 3: Ngân hàng số và bài toán nhất quán dữ liệu

Một ngân hàng số tại Việt Nam triển khai tính năng "chuyển tiền và tích điểm thưởng tức thì". Hệ thống đã là microservices: Account Service quản lý số dư, Reward Service quản lý điểm. Business yêu cầu: "Ngay khi chuyển tiền thành công, điểm thưởng phải hiện ngay lập tức."

BA ban đầu viết yêu cầu đúng như vậy. Nhưng khi review với kiến trúc sư, vấn đề lộ ra: hai service có DB riêng, không có transaction chung. Nếu ép "tức thì tuyệt đối", hệ thống phải dùng cơ chế phức tạp (distributed transaction) làm chậm cả giao dịch chuyển tiền — thứ tối quan trọng. Sau khi BA giải thích lại cho business, họ đồng ý phương án: tiền chuyển ngay lập tức (ưu tiên cao nhất), điểm thưởng cập nhật trong vòng vài giây qua cơ chế eventual consistency. Trải nghiệm người dùng gần như không khác biệt, nhưng hệ thống đơn giản và ổn định hơn nhiều.

Bài học rút ra: Trong microservices, "nhất quán tức thời" giữa các service là một yêu cầu đắt đỏ. BA giỏi là người biết phân biệt đâu là yêu cầu "thực sự phải tức thì" và đâu là yêu cầu "có thể chấp nhận trễ vài giây", rồi thương lượng với business để có giải pháp khả thi.

Hướng dẫn từng bước

Khi bạn — với vai trò BA — tham gia một dự án và cần đánh giá hoặc đóng góp vào quyết định kiến trúc, hãy đi theo các bước sau:

Bước 1 — Xác định bối cảnh đội ngũ và sản phẩm. Hỏi: Đội có bao nhiêu người? Sản phẩm đã ổn định hay còn dò đường? Nếu đội nhỏ và sản phẩm chưa rõ, nghiêng về monolith (hoặc modular monolith). Đừng chạy theo "vì Grab làm microservices nên ta cũng phải làm".

Bước 2 — Vẽ bản đồ các năng lực nghiệp vụ (business capabilities). Liệt kê các mảng nghiệp vụ chính: người dùng, đơn hàng, thanh toán, kho, thông báo... Đây chính là ứng viên tự nhiên để trở thành ranh giới của các service. BA là người hiểu rõ nhất các ranh giới nghiệp vụ này.

Bước 3 — Đánh dấu phần nào có đặc thù riêng. Tự hỏi: Phần nào cần scale riêng (ví dụ tìm kiếm vào ngày sale)? Phần nào cần độ ổn định/bảo mật cao riêng (thanh toán)? Phần nào do một đội riêng sở hữu? Những phần này là ứng viên ưu tiên để tách thành service.

Bước 4 — Đánh giá luồng dữ liệu xuyên service. Với mỗi yêu cầu nghiệp vụ, vẽ ra nó cần "chạm" vào bao nhiêu service. Yêu cầu chạm nhiều service = phức tạp hơn, cần làm rõ về tính nhất quán dữ liệu. Đây là lúc đặt câu hỏi về "tức thời hay chấp nhận trễ".

Bước 5 — Ghi rõ yêu cầu phi chức năng (non-functional requirements). Với mỗi nghiệp vụ quan trọng, ghi rõ kỳ vọng về tính nhất quán, độ trễ chấp nhận được, mức tải dự kiến. Những thông tin này quyết định kiến trúc, và chỉ BA mới khai thác được từ business.

Bước 6 — Phối hợp với kiến trúc sư, đặt câu hỏi đúng. Bạn không quyết định kiến trúc, nhưng bạn cung cấp dữ kiện nghiệp vụ để quyết định đúng. Câu hỏi mẫu: "Nếu service này chết, nghiệp vụ nào bị ảnh hưởng?", "Yêu cầu này cần dữ liệu nhất quán tức thời hay chấp nhận trễ?"

Lỗi thường gặp & mẹo

Lỗi 1 — Tưởng microservices luôn tốt hơn monolith. Không có kiến trúc nào "tốt hơn" tuyệt đối, chỉ có "phù hợp hơn" với bối cảnh. Monolith vẫn là lựa chọn tuyệt vời cho nhiều dự án. Đừng để buzzword dẫn dắt.

Lỗi 2 — Nhầm "microservices" với "API". Một monolith vẫn có thể cung cấp API ra ngoài. Microservices là về cách chia nội bộ hệ thống thành nhiều service độc lập, không phải đơn thuần là "có API".

Lỗi 3 — Bỏ qua tính nhất quán dữ liệu khi viết yêu cầu. Đây là cái bẫy phổ biến nhất. BA viết "phải cập nhật ngay lập tức và chính xác tuyệt đối" mà không biết trong microservices điều này rất đắt. Luôn hỏi lại: yêu cầu này có thật sự cần tức thời không?

Lỗi 4 — Quên rằng microservices thêm điểm hỏng mới. Khi service gọi nhau qua mạng, mạng có thể chậm hoặc chết. Yêu cầu nghiệp vụ cần tính đến: "Nếu Notification Service chết, đơn hàng vẫn đặt được chứ?" Câu trả lời tốt thường là "có" — và đó là một yêu cầu bạn nên ghi rõ.

Mẹo 1 — Học khái niệm "modular monolith". Đây là điểm cân bằng tuyệt vời: vẫn là một ứng dụng, một deploy, nhưng bên trong chia module rõ ràng. Dễ phát triển ban đầu, và nếu sau này cần tách microservice thì đã có sẵn ranh giới.

Mẹo 2 — Dùng phép thử "tại sao tách". Mỗi lần ai đó đề xuất tách một service, hãy hỏi "tại sao". Nếu lý do là "cần scale riêng", "cần đội riêng sở hữu", "cần ổn định riêng" — hợp lý. Nếu lý do là "nghe nói nên làm vậy" — cần xem lại.

Mẹo 3 — Vẽ sơ đồ luồng để giao tiếp. Khi giải thích cho business vì sao một tính năng phức tạp, hãy vẽ ra nó chạm vào bao nhiêu service. Hình ảnh trực quan giúp stakeholder hiểu vì sao "tính năng nhỏ" lại tốn nhiều công.

Bài tập thực hành

Bài 1 — Phân loại kiến trúc. Cho ba mô tả hệ thống sau, hãy xác định đâu là monolith, đâu là microservices, đâu là modular monolith: (a) Một ứng dụng PHP, một database, deploy một lần, bên trong chia thư mục rõ ràng theo nghiệp vụ. (b) Năm dịch vụ riêng, mỗi cái có DB riêng, deploy độc lập, gọi nhau qua REST. (c) Một codebase Java khổng lồ, mọi thứ trộn lẫn, một DB chung. Giải thích lý do phân loại.

Bài 2 — Tư vấn kiến trúc. Một quán cà phê chuỗi ở Hà Nội muốn xây app đặt món với đội 4 lập trình viên, sản phẩm còn đang thử nghiệm thị trường. Bạn khuyên họ nên bắt đầu bằng kiến trúc nào? Viết 3-4 câu lập luận theo góc nhìn BA.

Bài 3 — Phát hiện rủi ro nhất quán. Cho yêu cầu: "Khi khách hủy đơn hàng, hệ thống phải hoàn tiền tức thì, cộng lại điểm thành viên tức thì, và gửi email xác nhận tức thì." Hệ thống là microservices với các service riêng cho đơn hàng, thanh toán, điểm thành viên, email. Hãy chỉ ra yêu cầu nào thực sự cần "tức thì" và yêu cầu nào có thể chấp nhận trễ. Đề xuất cách viết lại yêu cầu cho khả thi.

Bài 4 — Xác định ranh giới service. Cho một sàn TMĐT với các nghiệp vụ: tài khoản người dùng, danh mục sản phẩm, giỏ hàng, thanh toán, vận chuyển, đánh giá. Nếu phải tách microservices, bạn sẽ đề xuất tách phần nào trước và vì sao? Trả lời theo góc nhìn "phần nào cần scale/ổn định/đội riêng".

Tóm tắt

Monolith là kiến trúc "tất cả trong một": một codebase, một deploy, một database — đơn giản và nhanh khi hệ thống còn nhỏ, nhưng phạm vi ảnh hưởng của lỗi lớn và khó scale từng phần. Microservices chia hệ thống thành nhiều service độc lập, mỗi cái có nghiệp vụ và database riêng — linh hoạt, scale từng phần được, cô lập lỗi tốt, nhưng phức tạp về vận hành và đặt ra thách thức lớn về tính nhất quán dữ liệu.

Là BA, bạn không quyết định chọn kiến trúc nào, nhưng bạn là người cung cấp dữ kiện nghiệp vụ quan trọng nhất để quyết định đó đúng đắn: ranh giới các năng lực nghiệp vụ, phần nào cần scale hay ổn định riêng, và quan trọng nhất — yêu cầu nào thực sự cần nhất quán tức thời, yêu cầu nào chấp nhận trễ vài giây. Ba bài học cốt lõi cần khắc ghi: (1) không có kiến trúc tốt nhất, chỉ có kiến trúc phù hợp nhất với bối cảnh đội ngũ và sản phẩm; (2) tách microservices phải dựa trên nhu cầu nghiệp vụ thật chứ không phải trào lưu; (3) tính nhất quán dữ liệu trong microservices là một yêu cầu đắt đỏ mà BA phải biết để thương lượng đúng. Nắm vững những điều này, bạn sẽ tự tin ngồi trong mọi buổi họp kiến trúc và đóng góp giá trị thật sự.