Chi phí của microservice (2020)
(robertovitillo.com)- Backend thường bắt đầu dưới dạng monolith, nhưng khi nhiều nhóm tính năng cùng bắt đầu động vào một codebase, mức độ phụ thuộc chặt chẽ có thể tăng lên và tốc độ thay đổi có thể chậm lại
- Microservice là cách chia dịch vụ theo từng chức năng kinh doanh để có được khả năng triển khai độc lập và sự tự chủ của các nhóm nhỏ
- Nếu dịch vụ quá nhỏ, gánh nặng vận hành sẽ lớn hơn lợi ích, khiến cái tên “micro” thậm chí có thể làm lu mờ phán đoán
- Việc áp dụng toàn diện đi kèm với nhiều chi phí rộng khắp, từ chuẩn hóa, provisioning tài nguyên, phòng vệ cho lời gọi từ xa, CI/CD, vận hành cho đến tính nhất quán cuối cùng
- Thông thường, an toàn hơn là học đủ rõ các ranh giới trong monolith rồi tách dần từng phần khi những “đau tăng trưởng” trở nên lớn; cách tiếp cận ưu tiên microservice phù hợp khi đã có kinh nghiệm và nền tảng sẵn sàng
Những giới hạn lộ ra khi monolith lớn dần
- Backend của một ứng dụng JavaScript một trang hiện đại thường bắt đầu như một dịch vụ web phi trạng thái duy nhất, cung cấp RESTful HTTP API và dùng cơ sở dữ liệu quan hệ
- Dịch vụ này được cấu thành từ các component hoặc thư viện triển khai những chức năng kinh doanh khác nhau
- Khi số nhóm tính năng tham gia cùng một codebase tăng lên, mức độ phụ thuộc giữa các component tăng và phạm vi công việc giữa các nhóm dễ chồng lấn
- Năng suất giảm, và khó dự đoán phạm vi ảnh hưởng của thay đổi
- Khi codebase đủ phức tạp, không ai hiểu hoàn toàn toàn bộ hệ thống, khiến việc triển khai tính năng mới và sửa lỗi mất nhiều thời gian
- Ngay cả khi backend được chia thành các thư viện theo từng nhóm, thay đổi thư viện cuối cùng vẫn dẫn đến triển khai lại dịch vụ
- Nếu một lỗi như rò rỉ bộ nhớ lọt vào, toàn bộ dịch vụ có thể bị ảnh hưởng
- Rollback một bản build sai sẽ ảnh hưởng đến tốc độ của tất cả các nhóm, không chỉ nhóm gây ra lỗi
Sự tự chủ mà ranh giới dịch vụ mang lại
- Một cách để giảm “đau tăng trưởng” của backend monolithic là chia backend thành tập hợp các dịch vụ có thể triển khai độc lập
- Các dịch vụ giao tiếp qua API, và API tạo ra những ranh giới khó bị xâm phạm hơn ranh giới giữa các component trong cùng một tiến trình
- Kiến trúc này được gọi là kiến trúc microservice, nhưng cách gọi
microcó thể gây hiểu lầm- Dịch vụ không nhất thiết phải nhỏ
- Một dịch vụ có quá ít chức năng có thể tạo ra gánh nặng vận hành nhiều hơn lợi ích
- Tên gọi phù hợp hơn có thể là kiến trúc hướng dịch vụ, nhưng tên này cũng mang theo những gánh nặng cũ
Tốc độ do nhóm nhỏ và dịch vụ độc lập tạo ra
- Khi chia backend thành các dịch vụ theo chức năng kinh doanh, mỗi dịch vụ có thể được phát triển và vận hành bởi một nhóm nhỏ duy nhất
- Nhóm nhỏ hiệu quả hơn vì chi phí giao tiếp tăng theo bình phương quy mô nhóm
- Khi mỗi nhóm tự quyết lịch phát hành và kiểm soát codebase của mình, việc phối hợp giữa các nhóm giảm đi và ra quyết định nhanh hơn
- Codebase của dịch vụ nhỏ giúp lập trình viên dễ hiểu hơn và cũng rút ngắn thời gian hòa nhập của nhân viên mới
- Codebase nhỏ cũng giúp giảm tình trạng IDE chậm, qua đó hỗ trợ năng suất lập trình viên
- Nhờ ranh giới dịch vụ mạnh, khi thay đổi một phần của backend, lập trình viên chỉ cần hiểu một phần nhỏ thay vì toàn bộ hệ thống
- Mỗi dịch vụ có thể mở rộng độc lập và chọn stack công nghệ phù hợp với nhu cầu riêng
- Người tiêu thụ API không cần quan tâm chức năng được triển khai nội bộ như thế nào
- Dễ thử nghiệm và đánh giá công nghệ mới mà không ảnh hưởng đến các khu vực khác của hệ thống
- Mỗi microservice có thể có mô hình dữ liệu và kho lưu trữ dữ liệu riêng
- Lập trình viên có thể thay đổi schema mà không ảnh hưởng đến dịch vụ khác
Chi phí thực sự mà microservice bổ sung
- Microservice thêm nhiều bộ phận chuyển động hơn vào toàn hệ thống, và chi phí này không miễn phí
- Chi phí để chấp nhận microservice hoàn toàn chỉ đáng trả khi có thể phân bổ khấu hao trên hàng chục nhóm phát triển
-
Trải nghiệm phát triển
- Việc mỗi dịch vụ dùng ngôn ngữ, thư viện và kho dữ liệu khác nhau là có thể, nhưng có thể khiến việc bảo trì ứng dụng khó hơn
- Nếu stack phần mềm hoàn toàn khác nhau, lập trình viên khó chuyển từ nhóm này sang nhóm khác
- Để cung cấp các chức năng chung mà mọi dịch vụ đều cần, như logging, cần hỗ trợ thư viện cho từng ngôn ngữ đã chọn
- Cần một mức độ chuẩn hóa nhất định
- Có thể khuyến khích lỏng lẻo việc dùng một số công nghệ bằng cách cung cấp trải nghiệm phát triển tốt cho các nhóm tuân theo danh mục ngôn ngữ và công nghệ được khuyến nghị
-
Provisioning tài nguyên
- Để hỗ trợ nhiều dịch vụ độc lập, cần có khả năng tạo dễ dàng máy chủ, kho dữ liệu và các tài nguyên dùng chung khác
- Không nên để mỗi nhóm tự tạo cách sinh tài nguyên riêng
- Các tài nguyên đã được provisioning cần được cấu hình lại, và để xử lý việc này cần khá nhiều tự động hóa
-
Giao tiếp
- Lời gọi từ xa có chi phí lớn và đưa vào những cách mới khiến hệ thống có thể sụp đổ
- Để chuẩn bị cho sự cố, cần các cơ chế phòng vệ như timeout, retry và circuit breaker
- Để giảm tổn thất hiệu năng của truyền thông qua mạng, cũng cần tận dụng xử lý bất đồng bộ và batching
- Những yếu tố này làm tăng độ phức tạp của hệ thống
- Monolith cũng có thể gặp vấn đề tương tự do truy cập từ client từ xa và sử dụng API bên thứ ba, nhưng quy mô nhỏ hơn
-
Tích hợp, chuyển giao và triển khai liên tục
- Tích hợp liên tục đảm bảo thay đổi mã được merge vào nhánh chính sau khi build và kiểm thử tự động chạy xong
- Khi thay đổi mã được merge, nó cần được tự động publish và triển khai vào môi trường tương tự production
- Trong môi trường đó, cần chạy kiểm thử tích hợp và kiểm thử end-to-end để xác nhận microservice không làm hỏng các dịch vụ khác phụ thuộc vào nó
- Kiểm thử từng microservice riêng lẻ không khó hơn kiểm thử monolith, nhưng kiểm thử tích hợp của tất cả microservice thì khó hơn nhiều
- Khi các dịch vụ riêng lẻ tương tác với nhau, có thể xuất hiện những hành vi rất tinh vi và ngoài dự đoán
-
Vận hành
- Khác với monolith, việc bố trí một nhóm vận hành riêng cho từng nhóm phụ trách dịch vụ tốn kém hơn nhiều
- Nhóm phát triển một dịch vụ thường cũng đảm nhận on-call cho dịch vụ đó
- Mỗi sprint, nhóm phải quyết định ưu tiên công việc phát triển hay gánh nặng vận hành, và điều này tạo ra ma sát
- Việc debug sự cố hệ thống cũng trở nên khó hơn
- Không thể đưa toàn bộ ứng dụng lên máy local rồi chạy từng bước bằng debugger
- Có nhiều bộ phận chuyển động hơn nên cũng có nhiều kiểu thất bại hơn
- Logging và monitoring tốt ở mọi cấp độ trở nên quan trọng
-
Tính nhất quán cuối cùng
- Khi chia ứng dụng thành nhiều dịch vụ, mô hình dữ liệu không còn chỉ tồn tại trong một kho dữ liệu duy nhất
- Việc cập nhật nguyên tử các bản ghi nằm ở những kho dữ liệu khác nhau và bảo đảm tính nhất quán mạnh là chậm, tốn kém và khó triển khai
- Kiến trúc kiểu này thường phải chấp nhận tính nhất quán cuối cùng
Khi nào nên tách
- Việc chia ứng dụng thành các dịch vụ làm độ phức tạp tổng thể của hệ thống tăng mạnh
- Nói chung, nên bắt đầu bằng monolith và chỉ tách ra khi có đủ lý do
- Việc xác định đúng ranh giới giữa các dịch vụ là khó, vì vậy thường dễ hơn khi dịch chuyển ranh giới bên trong monolith để tìm điểm phù hợp
- Khi monolith đã đủ trưởng thành và “đau tăng trưởng” bắt đầu lớn lên, có thể tách dần từng microservice ra
- Cách tiếp cận ưu tiên microservice chỉ nên bắt đầu khi đã có kinh nghiệm, và đã xây dựng nền tảng cho nó hoặc đã tính đến thời gian cần để xây dựng nền tảng đó
1 bình luận
Ý kiến trên Hacker News
Nhìn chung tôi đồng ý với bài viết, nhưng nhìn theo chiều ngược lại thì cũng có những trường hợp đáng chấp nhận chi phí: có thể tách các vấn đề tương thích với phụ thuộc bên thứ ba cũ thành một dịch vụ riêng để tránh refactor đau đớn hoặc tự triển khai lại, có thể ngăn các ràng buộc triển khai của hệ thống lõi có tính sẵn sàng cao chặn việc triển khai các hệ thống khác, và có thể cô lập các ràng buộc thiết kế mà khách hàng lớn không thể thay đổi
Không có nghĩa là miễn phí, mà là đó có thể là cái giá đáng trả để không biến một monolith đơn giản thành bãi rác, không khiến nó chao đảo vì các lần triển khai rủi ro, hoặc không bị trói buộc vào một đối tác kinh doanh có stack công nghệ tệ hơn
Microservices chẳng phải là cách tiếp cận trong đó các thành phần nội bộ về cơ bản được tạo thành dịch vụ thay vì thư viện hay class sao?
Nếu dịch vụ suy luận machine learning dùng Python, UI render phía server dùng Rails, còn dịch vụ nhiều I/O và concurrency dùng Go, thì chi phí bổ sung để tách ba phần này thành các dịch vụ riêng có thể là hợp lý
Tôi khá thích microservices, nhưng tối ưu hóa sớm và mở rộng sớm có thể tệ chẳng kém gì khoản nợ kỹ thuật phát sinh khi sau này phải tối ưu theo một hướng hoàn toàn khác
Thời điểm nên tách thứ gì đó thành một dịch vụ riêng là khi xuất hiện vấn đề mà nếu không làm vậy thì không thể giải quyết theo cách chấp nhận được
Tăng độ phức tạp kiến trúc để cưỡng chế ranh giới không thể là lời giải cho việc thiếu kỷ luật tổ chức, nhưng các công ty công nghệ cỡ trung cứ liên tục xem nó như vậy. Nếu vấn đề phát sinh vì ranh giới domain yếu, thì trích xuất dịch vụ có khả năng cũng không giải quyết tốt được
Trích dẫn: https://www.oreilly.com/library/view/software-architects-han...
CI/CD chặn PR cho đến khi test pass cũng là một giải pháp kỹ thuật tốn kém để giải quyết vấn đề kỷ luật tổ chức
Mọi người đều công nhận việc phân giải tên miền do dịch vụ bên ngoài thực hiện là hợp lý, và gần như không ai tích hợp resolver DNS đệ quy cùng cache vào monolith. Thế nhưng kiểu tách trách nhiệm lâu đời như vậy lại không thường được công nhận là ví dụ
Có vẻ vấn đề nằm ở chỗ nhân viên càng “giỏi” thì càng quá hăng hái chứng minh giá trị, dẫn đến over-engineering, và cuối cùng biến thành địa ngục
Microservices
grug thắc mắc vì sao những bộ não lớn lại nắm lấy bài toán khó nhất là phân rã hệ thống cho đúng, rồi còn nhét thêm lệnh gọi mạng vào đó
với grug thì chuyện này trông rất khó hiểu
https://grugbrain.dev/#grug-on-microservices
“Vì SCALE_REASONS, chúng tôi muốn hiện đại hóa cách tiếp cận FOO_TABLE bằng cách chuyển từ MySQL sang DynamoDB, nhưng 32 trong 59 đội đang truy cập trực tiếp FOO_TABLE hoặc gọi thẳng private method trong class của chúng tôi. Do ưu tiên khác nhau, các đội đó không thể chuyển sang dùng FOO_SERVICE hoặc đổi cách query để dùng bảng sharding. Giờ việc mở rộng FOO_TABLE trở thành công việc kéo dài nhiều quý, và phải cho phép các đội cập nhật từ từ. Có lẽ sau 1–2 năm nữa chúng tôi mới có thể cho nghỉ hưu cách làm cũ hiện đang bốc cháy. Trong lúc đó thì cứ tận hưởng on-call thôi”
Với microservices, đội sẽ nhận ra rằng bảng không scale được, nhưng dữ liệu được cung cấp qua API. Họ lên kế hoạch và thực hiện migration trong sprint tiếp theo, còn người dùng API sẽ cảm thấy mọi thứ nhanh hơn nhiều
Mở REPL của Ruby hiện đại lên, bạn có thể nhận được phần lớn những gì thường kỳ vọng từ IDE của ngôn ngữ static type về autocomplete và kiểm tra cú pháp
Không nên xem nhẹ sự cô lập; đó là một trong những tính năng mạnh nhất có thể đưa vào phần mềm. Nó có thể cải thiện hiệu năng, tạo ranh giới lỗi, và cung cấp ranh giới bảo mật
Điều này giống với khái niệm nền tảng của actor model. Thay vì hai thành phần chia sẻ và thay đổi bộ nhớ của nhau, hai hệ thống cô lập như actor hoặc microservice chỉ giao tiếp qua một giao thức đã định nghĩa
Tôi cho rằng mọi người đang hiểu sai về tính mô-đun. Tính mô-đun là quan trọng, nhưng tôi cũng dần nghĩ rằng còn một nguyên tắc kiến trúc quan trọng khác là nguyên tắc một xoáy duy nhất
Trong hệ thống phần mềm, xoáy là một vòng lặp của luồng dữ liệu. Nếu bạn gửi dữ liệu đi đâu đó rồi nhận lại kết quả đã xử lý, hoặc bị dữ liệu đó tác động theo cách nào đó, thì có một xoáy. Biến có thể thay đổi là một ví dụ về một xoáy rất nhỏ
Nguyên tắc một xoáy duy nhất có nghĩa là, lý tưởng thì hệ thống phần mềm chỉ nên có một xoáy, hay nói cách khác, mọi thành phần đều phải biết xoáy của mình đang quay theo hướng nào
Khi gộp các mô-đun tạo thành hai xoáy lại với nhau, nếu hướng xoáy khớp thì việc tổ hợp dễ dàng; nếu ngược hướng thì sẽ khó vì phải quyết định hướng xoáy mới sẽ như thế nào. Vì vậy tốt nhất là xoáy của mọi mô-đun có cùng hướng và tạo thành một xoáy duy nhất
Nguyên tắc này là sự khái quát hóa các ý tưởng như mẫu Flux, CQRS, event sourcing và tính bất biến
Hoặc một chuyện không lường trước ở A có thể làm C bị chặn. Lý tưởng là cha chỉ gọi con và không phụ thuộc vào cha; nếu thất bại ở điểm này thì kiến trúc cũng thất bại
Khi nhìn vào sơ đồ kiến trúc, một nửa trận chiến là xác định cái gì là bất đồng bộ/đồng bộ, push/pull, cũng như hướng và thứ tự của luồng
Enterprise Service Bus và message queue trông giống như giải pháp để tạo xoáy ở những nơi hai hướng không khớp nhau
Có đoạn nói rằng vấn đề là “số lượng thư viện phải hỗ trợ để cung cấp các chức năng chung như logging cần thiết cho mọi service, mỗi ngôn ngữ được dùng một bộ”
Đây là lý do lớn nhất khiến chúng tôi từ bỏ microservice. Với công cụ của năm 2023, đặc biệt trong môi trường cloud-native thuần túy hoặc FaaS mở rộng vô hạn, việc tốn băng thông tinh thần cho những lo lắng kiểu này là hoàn toàn lãng phí. Điều này càng đúng với nhóm khách hàng như ngân hàng và tổ chức tài chính, nơi họ soi xét cực kỳ khắt khe từng dependency bên thứ ba
Hiện chúng tôi đang vận hành bằng một bản phân phối binary .NET nguyên khối duy nhất, khoảng 250MB khi gzip, và hoàn toàn không có dấu hiệu rạn nứt. Nếu bạn đang băn khoăn tỉ mỉ kiểu “exe của tôi không còn vừa L2 nữa” với một bản phân phối SaaS 10–100MB, thì cứ yên tâm. Hành trình phần mềm nguyên khối của bạn còn chưa bắt đầu
Nếu đến lúc phải viết lại một trong những đống rác này, chẳng phải sẽ dễ hơn nhiều khi mọi commit đều nằm ở một nơi nhất quán trên toàn cục sao?
Microservice không có nghĩa là vùng vô pháp, nơi mọi team được hành động mà không cần nghĩ đến toàn bộ tổ chức. Có thể và nên có các quy tắc để duy trì một mức độ nhất quán nào đó giữa các team
Code tốt nhất là code dễ vứt đi và viết lại. Trên thực tế, code cũ đi qua tay nhiều người hơn, trở nên tệ hơn, và quan trọng nhất là cuối cùng không ai muốn bảo trì nó nữa
Phe thích microservice nói rằng vì có contract rõ ràng về cách service phải hoạt động và codebase của service đó nhỏ hơn nhiều, nên việc thay đổi hoặc viết lại sẽ dễ hơn
Phe monolith nói rằng vì mọi thứ là một cuộn chỉ lớn, nên để thay đổi một sợi chỉ, chỉ cần biết những điểm mà sợi đó đan với các sợi khác, vì vậy việc thay đổi hoặc viết lại sẽ dễ hơn
Tôi không biết ai đúng. Với những người gắn bó lâu năm đã soi codebase dưới kính hiển vi suốt nhiều năm, monolith có lẽ tốt hơn; với những người còn lại, microservice có thể tốt hơn
Nhìn từ góc độ quản lý release, việc chuyển từ monolith sang microservice thường được thực hiện vì những lý do sai
Lý do duy nhất thực sự hợp lý để thay đổi có vẻ là vấn đề khả năng mở rộng do nút thắt hiệu năng. Những lý do còn lại chỉ là chuyển độ phức tạp của phát triển phần mềm sang bảo trì hệ thống
Tất nhiên các lập trình viên sẽ thích vì giảm được gánh nặng lớn khi phải phối hợp với các team khác. Nhưng việc làm rõ tính năng được triển khai khi nào và như thế nào, được kiểm thử đúng cách trên toàn bộ microservice, được bật trong production và được quản lý tập trung ra sao sẽ khó hơn nhiều nếu giao tiếp giữa các team phát triển chưa đủ trưởng thành. Và chính sự chưa trưởng thành đó thường là lý do thực sự khiến người ta tách monolith ngay từ đầu
Ngược lại, với ít lập trình viên và bối cảnh được định nghĩa rõ ràng, việc xử lý nhiều microservice là rất đau đớn
Câu “những lý do còn lại chỉ là chuyển độ phức tạp của phát triển phần mềm sang bảo trì hệ thống” nghe có lý nếu phần mềm đang được phát triển tích cực. Phát triển rất tốn kém. Chi phí bảo trì hệ thống phân tán của một team lớn có thể thấp hơn chi phí phát triển một monolith khổng lồ, và rốt cuộc còn tùy tình huống
Bài “Chi phí của monolith” ở đâu? Ở đây tôi không thấy. Chỉ là ai cũng triển khai microservice một cách thiếu hiểu biết nên chỉ thấy vấn đề đó mà thôi
Nếu ai cũng triển khai monolith một cách thiếu hiểu biết, hẳn đã thấy vô số bài kiểu “monolith tệ” rồi
Mọi người không hiểu rằng cuối cùng hai hệ thống tạo ra cùng một lượng vấn đề. Đó là khác biệt giữa việc bắt một con voi làm việc và bắt 1000 con chuột làm việc. Cả hai đều gặp vấn đề, chỉ là vấn đề khác nhau
Chọn một trong hai không làm vấn đề biến mất. Dù chọn bên nào cũng sẽ có vấn đề, và phải chọn một để đưa ra giải pháp. Nếu “kiến trúc nào” là trở ngại lớn nhất của một công ty, tôi muốn làm việc ở đó
Nếu một monolith được tách module tốt, nó khác gì so với các microservice được đặt cùng vị trí? Có lẽ chỉ là interface. Lời gọi hàm trở thành RPC, đổi lại nhận được lợi ích của việc xử lý từng thành phần riêng lẻ, ví dụ chấp nhận một chút overhead để vá lỗi
Microservice phân tán khác gì so với microservice nằm cùng vị trí? Triển khai phức tạp hơn, nhưng có thể đặt tiến trình một cách thông minh lên phần cứng phù hợp hơn. Failure mode tăng lên, nhưng đổi lại có khả năng chịu lỗi cao hơn
Ở đây không có câu trả lời vạn năng. Nếu cần lợi ích thì trả chi phí. Tôi cho rằng những cuộc tranh luận microservice so với monolith như thế này xuất phát từ việc áp dụng sai một pattern, thiếu công cụ giúp cuộc sống dễ dàng hơn, hoặc phần lớn là do cứ tiếp tục không refactor và thiết kế lại phần mềm 10 năm tuổi, khiến nó trở nên khổ sở khi làm việc bất kể kiến trúc ban đầu là gì
Câu “lời gọi hàm trở thành RPC” nghe có vẻ đơn giản, nhưng ngay khoảnh khắc đó xảy ra, client app phải xử lý mọi đường thực thi như không truy cập được DNS server, phân giải hostname thất bại, không truy cập được host, kết nối bị từ chối, xác thực bị từ chối, chứng chỉ TLS không đáng tin cậy, vượt quá rate limit, 301 Moved Permanently, kết quả chuẩn bị chậm, timeout
Ngay cả một app được tách module tốt cũng rất có khả năng phải thiết kế lại để xử lý vững chắc các việc này: hàng đợi bất đồng bộ, giới hạn tốc độ yêu cầu, cache kết quả, retry với backoff và logging, thông tin xác thực client/cửa hàng tin cậy/resource URL có thể cấu hình, và logging khi thất bại
Với lời gọi hàm cục bộ, cũng cần thêm các hàm RPC và tham số để cung cấp dữ liệu vốn đã nằm trong context. Ngoài ra UI của monolith có thể phải truyền đạt cho người dùng độ trễ và lỗi mạng, những thứ trước đây không thể xảy ra
Ngay cả monolith được làm tốt nhất cũng cần nỗ lực đáng kể để refactor thành microservice
Có thể retry an toàn lời gọi RPC này không? Exponential backoff thì sao? API load balancer có hoạt động đúng không, và nếu có thì cũng cần monitoring. Theo dõi giữa các microservice sẽ làm thế nào, giờ lại cần những thứ như OpenTelemetry
Debug bằng breakpoint trong kiến trúc microservice khó hơn bao nhiêu? Làm sao rollback một database transaction giữa hai microservice? Một lời gọi hàm đơn giản bỗng trở nên phức tạp hơn nhiều
Mỗi khi bênh vực khái niệm này, họ bỏ qua sự phân mảnh do yêu cầu service phải rất nhỏ tạo ra. Cụ thể hơn, nếu có một monolith và một microservice thì đó không phải là các microservice. Từ microservice hàm ý mọi thứ được chia thành các service nhỏ và không có monolith
Phần lớn lập luận ủng hộ microservice sụp đổ ngay khi nhận ra rằng nó nhất thiết phải là “micro”. Và nếu từ bỏ yêu cầu đó thì chẳng còn đề xuất nào mới mẻ hay sâu sắc
Nhìn từ góc độ vận hành, nói “triển khai phức tạp hơn” là một cách nói giảm nói tránh khổng lồ. Mỗi package là một đối tượng phải quản lý riêng, với đặc tính và vấn đề riêng
Tương tự như việc các frontend developer nghĩ rằng không thể tạo “ứng dụng web hiện đại” nếu không có frontend framework hay thư viện như React/Vue/Svelte, dạo này dường như có ý nghĩ lan truyền rằng “monolith” đồng nghĩa với việc chạy một cục hắc ín khổng lồ đáng sợ trong một instance duy nhất nên “không scale được”, điều này thật vô lý
Một điểm khác tôi thấy là tổng lượng code lớn hơn nhiều, và phần lớn service gồm 20% code nghiệp vụ/domain và 80% xử lý gửi nhận thông điệp qua mạng. Dù che giấu đến đâu thì cuối cùng nó vẫn ở đó, và bằng cách này hay cách khác bạn phải xử lý mạng
Cũng như cơn điên frontend, giáo phái microservice này chỉ kết thúc khi kinh tế sụp đổ và không còn tiền để chống đỡ những tháp Babel tận thế này nữa
Nói thêm, microservice cũng có chỗ dùng. Trong một số công ty thu được giá trị lớn hơn chi phí, nó là phù hợp
Cũng có các lợi ích kỹ thuật như scale độc lập theo từng service, nhưng lợi ích lớn nhất là ranh giới sở hữu rõ ràng và ngăn chặn sự kết hợp quá mức không cần thiết
Nếu một team nhỏ xây dựng một sản phẩm đơn lẻ, rất có thể họ chưa có vấn đề tổ chức mà microservice giải quyết, nên có thể không cần. Trong trường hợp đó, microservice là tối ưu hóa quá sớm, tức là trả chi phí để giải quyết một vấn đề chưa tồn tại
Xa hơn nữa, độ phức tạp frontend đều nằm trong đầu: https://bower.sh/front-end-complexity
Bài viết dường như giả định rằng tổ chức phát triển đã hoàn toàn hỏng hóc và mất kiểm soát. Kiểu như không quyết định được sẽ làm gì trong sprint, lén đưa thư viện bên thứ ba và ngôn ngữ lạ vào, rồi âm thầm triển khai các thay đổi không tương thích lên production
Nếu các lập trình viên không ngốc thì có vẻ microservices cũng sẽ dễ hơn
Tôi tin chắc rằng nếu làm việc trong một đội gồm các lập trình viên thông minh và có năng lực, microservices sẽ dễ hơn. Tất nhiên, khi đó thì mọi thứ cũng sẽ dễ hơn