5 điểm bởi GN⁺ 2025-12-14 | 2 bình luận | Chia sẻ qua WhatsApp
  • Twilio Segment từng vận hành cấu trúc microservices với hàng trăm dịch vụ, nhưng đã chuyển sang một dịch vụ duy nhất (monolithic) do độ phức tạp và gánh nặng bảo trì
  • Ban đầu, công ty tách riêng từng Destination API để bảo đảm cô lập sự cố và khả năng mở rộng, nhưng khi số lượng dịch vụ tăng lên hơn 140, chi phí vận hành tăng vọt
  • Việc quản lý nhiều repository và thư viện dùng chung trở nên khó khăn, đồng thời phát sinh vấn đề ảnh hưởng đến toàn bộ dịch vụ trong quá trình kiểm thử và triển khai
  • Để giải quyết, công ty đưa vào hệ thống Centrifuge và cấu trúc monorepo, đồng thời xây dựng Traffic Recorder để tự động hóa kiểm thử
  • Kết quả là tốc độ phát triển và độ ổn định được cải thiện đáng kể, và Twilio Segment hiện duy trì cấu trúc monolithic để tối ưu năng suất và hiệu quả vận hành

Việc áp dụng microservices và những giới hạn

  • Twilio Segment đã chọn kiến trúc microservices cho hạ tầng dữ liệu khách hàng, thiết kế để từng dịch vụ theo mục đích riêng có thể xử lý sự kiện một cách độc lập
    • Truyền dữ liệu đến hàng trăm server-side destinations (ví dụ: Google Analytics, Optimizely, v.v.)
    • Ban đầu dùng một hàng đợi duy nhất, nhưng khi một destination gặp sự cố thì phát sinh vấn đề head-of-line blocking, khiến toàn bộ hệ thống bị chậm trễ
  • Để giải quyết, công ty xây dựng dịch vụ và hàng đợi riêng cho từng destination, từ đó đạt được cô lập sự cố và khả năng mở rộng độc lập
  • Tuy nhiên, khi số lượng dịch vụ tăng lên, độ phức tạp vận hành và chi phí bảo trì cũng tăng mạnh, dẫn đến tốc độ phát triển chậm lại và tỷ lệ lỗi cao hơn

Vấn đề của repository riêng lẻ và thư viện dùng chung

  • Mỗi destination sử dụng định dạng API khác nhau nên cần mã chuyển đổi tùy chỉnh
    • Ban đầu được quản lý trong một repository duy nhất, nhưng do lỗi kiểm thử ảnh hưởng đến toàn bộ hệ thống nên công ty đã tách repository
  • Sau đó, khi bổ sung hơn 50 destination mới, số lượng repository cũng tăng lên hơn 50
    • Để phục vụ các chức năng chung, công ty đưa vào thư viện dùng chung, nhưng điều này lại làm tăng gánh nặng do lệch phiên bản và triển khai
  • Do mô hình tải của từng dịch vụ khác nhau, việc cấu hình auto scaling trở nên khó khăn, thậm chí đôi khi người vận hành phải điều chỉnh thủ công

Chuyển sang monolithic và đưa vào Centrifuge

  • Công ty quyết định hợp nhất hơn 140 dịch vụ thành một dịch vụ duy nhất
    • Để thay thế các hàng đợi riêng lẻ, họ phát triển hệ thống Centrifuge để chuyển mọi sự kiện vào một dịch vụ duy nhất
    • Về sau, Centrifuge đã phát triển thành hạ tầng backend Connections của Twilio Segment
  • Khi chuyển sang cấu trúc một dịch vụ duy nhất, công ty đã giảm được gánh nặng vận hànhđơn giản hóa việc ứng phó sự cố

Monorepo và tự động hóa kiểm thử

  • Toàn bộ mã nguồn destination được gộp vào một repository duy nhất, thống nhất hơn 120 dependency về một phiên bản duy nhất
    • Việc quản lý phiên bản trở nên đơn giản hơn và hiệu quả bảo trì được cải thiện
  • Để tự động hóa kiểm thử, công ty đưa vào Traffic Recorder
    • Ghi lại rồi phát lại các yêu cầu/phản hồi HTTP thực tế để loại bỏ phụ thuộc vào mạng bên ngoài
    • Tốc độ kiểm thử được rút ngắn từ vài phút xuống mức mili giây, đồng thời độ ổn định tăng mạnh
  • Tỷ lệ kiểm thử thất bại giảm xuống và năng suất của lập trình viên được cải thiện đáng kể

Hiệu quả và đánh đổi của cấu trúc monolithic

  • Sau khi hợp nhất thành một dịch vụ duy nhất, tốc độ triển khai và hiệu quả phát triển được cải thiện rõ rệt
    • Trong 1 năm, số lần cải tiến thư viện dùng chung tăng từ 32 lên 46
    • Một kỹ sư duy nhất có thể triển khai chỉ trong vài phút
  • Hiệu quả vận hành cũng được cải thiện, nhờ đó ngay cả khi tải tăng đột biến vẫn có thể hấp thụ bằng một worker pool quy mô lớn
  • Tuy nhiên, vẫn tồn tại các nhược điểm như khó cô lập lỗi, giảm hiệu quả cache, và rủi ro khi cập nhật dependency
    • Một phần tổn thất này được bù lại bằng sự đơn giản trong vận hành và năng suất tăng cao

Kết luận

  • Microservices đã giải quyết các vấn đề hiệu năng ban đầu, nhưng không phù hợp với mở rộng ở quy mô lớn và cập nhật hàng loạt
  • Việc chuyển sang monolithic đã cải thiện cả độ ổn định vận hành lẫn tốc độ phát triển
  • Để chuyển đổi thành công, cần có hệ thống kiểm thử vững chắcchấp nhận các đánh đổi
  • Twilio Segment vẫn duy trì microservices ở một phần hạ tầng, nhưng với server-side destinations thì monolithic được đánh giá là cấu trúc phù hợp hơn

2 bình luận

 
yangeok 2025-12-16

Có vẻ như việc chia nhỏ và chuẩn hóa mọi thứ đều tiềm ẩn rủi ro.

 
GN⁺ 2025-12-14
Ý kiến trên Hacker News
  • Khi gom mã của mọi đích đến vào một repo, họ có thể hợp nhất thành một dịch vụ duy nhất
    Kết quả là năng suất phát triển tăng lên đáng kể. Giờ đây không còn phải triển khai hơn 140 dịch vụ mỗi khi sửa một thư viện dùng chung
    Một kỹ sư giờ có thể triển khai chỉ trong vài phút
    Nếu mỗi lần thay đổi thư viện lại phải triển khai lại tất cả dịch vụ, thì đó không phải dịch vụ thực thụ mà là một distributed monolith
    Bản thân ý tưởng phải cưỡng ép đồng bộ một thư viện dùng chung trên toàn bộ dịch vụ đã không phù hợp với triết lý của kiến trúc dịch vụ

    • Ý bạn có lý, nhưng trong thực tế tình huống phức tạp hơn nhiều
      Cái này giống một hệ thống build và triển khai dùng chung kiểu Amazon hơn là “mỗi lần cập nhật thư viện là redeploy toàn bộ”
      Thư viện được lấy từ một nguồn duy nhất do trung tâm quản lý, và nếu khác phiên bản thì phải migrate hết vì vấn đề tương thích
      Khi cần loại bỏ một phiên bản cụ thể vì lỗ hổng bảo mật thì phải redeploy toàn bộ, nhưng lợi ích của quản trị tập trung vẫn lớn hơn nhiều
      Kiểu hệ thống này vẫn được xếp vào microservices, nhưng về mặt chi phí và hiệu quả vận hành thì hoạt động như một môi trường dùng chung
      Gọi nó là distributed monolith thì là diễn giải quá mức
    • Nói thì dễ, nhưng trên thực tế rất dễ phát sinh bug tinh vi hoặc không tương thích giữa các dịch vụ
      Khi đi theo mô hình microservices, rủi ro triển khai tăng lên nhưng ban đầu không dễ nhận ra
      Ví dụ nếu bạn sửa bug trong một thư viện liên quan đến tiền bạc, thì thực tế sẽ phải cân nhắc có nên redeploy mọi dịch vụ hay không
    • Việc phải nâng cấp thư viện trên diện rộng không nhất thiết có nghĩa là ghép nối sai cách
      Thư viện có lỗ hổng bảo mật thì dù thiết kế hệ thống thế nào cũng phải thay thế toàn diện
      Trong trường hợp như vậy, monolith lại dễ xử lý hơn
    • Bản thân khái niệm thư viện dùng chung đã khiến mọi dịch vụ ghép nối chặt với nhau
      Nếu là microservices thực thụ thì chúng nên trao đổi thông điệp với nhau và dùng JSON
      Chỉ cần biết API chứ không cần biết mã nguồn. Như vậy mỗi bên mới có thể triển khai và mở rộng độc lập
    • Vậy ý bạn là phải viết lại mã logging cho từng dịch vụ trong số 140 dịch vụ sao?
      Tận dụng module dùng chung chẳng phải hợp lý hơn sao?
  • Ở công ty trước, mọi thứ đều chạy bằng microservices, còn công ty trước đó nữa thì dùng AWS serverless
    Trong cả hai trường hợp, giao tiếp giữa các dịch vụ là vấn đề lớn nhất. Khó đồng bộ contract, và triển khai cũng phức tạp
    Ban đầu mọi thứ tiến triển rất nhanh, nhưng theo thời gian độ phức tạp bùng nổ. Xuất hiện phát triển dựa trên nỗi sợ, và có quá nhiều cuộc họp
    Công ty hiện tại của tôi dùng monolith và dễ xử lý hơn hẳn. Kiểu dữ liệu rõ ràng, refactor cũng đơn giản
    Thật thú vị khi thấy các AI agent xây trên nền tảng nội bộ tự cải thiện ngay trong codebase
    Điểm yếu duy nhất là thời gian build dài, nhưng với tiến bộ của toolchain, tôi kỳ vọng đến 2026 sẽ có triển khai nhanh gấp 10 lần
    Kết luận của tôi là, nhờ kiến trúc monolith mà chúng tôi có thể tăng trưởng và mở rộng nhanh hơn nhiều

    • Trải nghiệm của tôi thì hoàn toàn ngược lại. Tôi làm ở SendGrid 10 năm, mở rộng từ 12 người lên 500 người, và điều đó có được là nhờ kiến trúc dịch vụ
      Với monolith, tách biệt mối quan tâm luôn bị phá vỡ và mức độ ghép nối giữa các nhóm rất nặng
      Tốc độ và khả năng mở rộng thực sự chỉ có khi các nhóm được tách rời
      Việc chuyển từ ORM sang DTO cần 2 năm, 50 nhóm và hơn 150 người
      Loại công việc phức tạp như vậy là không thể nếu không có microservices
  • Nhìn vào bài này, cốt lõi vấn đề không nằm ở lựa chọn kỹ thuật microservices vs monolith
    mà nằm ở chất lượng và cấu trúc của tổ chức kỹ thuật
    Cấu trúc repo và cách tổ chức test phản ánh đúng trình độ của tổ chức

    • Nhiều nhóm thiếu kỷ luật kỹ thuật
      Nếu không có ai có thể nói “đừng làm vậy”, độ phức tạp sẽ bùng nổ
      Cần có người lãnh đạo đủ thẩm quyền để cả nhóm dừng lại và suy nghĩ
    • Tôi từng làm cùng dự án Twilio này, và nó thực sự là một đống hỗn độn
      Khi có sự cố API, họ không phân tích nguyên nhân mà chỉ sửa dữ liệu rồi đóng ticket
      Dù cùng một vấn đề lặp lại, họ cũng không giải quyết tận gốc nguyên nhân
    • Định luật Conway lại được chứng minh thêm một lần nữa
      Thậm chí chỉ cần phỏng vấn thôi cũng có thể phần nào đoán được cấu trúc codebase của công ty
  • Cái này không hẳn là chuyển sang monolith thực sự, mà vẫn là kiến trúc SOA
    Chỉ là phạm vi của dịch vụ đã lớn hơn
    Nếu một nhóm quản lý 140 dịch vụ, thì SOA là cấu trúc để mở rộng nhóm chứ không phải để mở rộng dịch vụ
    Khi một nhóm quản lý mọi thư viện dùng chung, sẽ nảy sinh lệch phiên bản và hỗn loạn API
    Cuối cùng, cấu trúc tổ chức quyết định kiến trúc. Một nhóm đã hợp nhất chúng để giảm độ phức tạp
    Đây không phải “monolith” mà là mức dịch vụ được điều chỉnh phạm vi hợp lý theo đơn vị nhóm
    Tôi nghĩ cấu trúc này là lý tưởng nhất. Khi nhóm lớn lên thì lại cần tách ra

  • Tôi không phải người ủng hộ microservices, nhưng sự đối lập giả tạo giữa “monorepo vs microservices” khá dễ thấy
    Quá nhiều công cụ mặc định coi dịch vụ và repo là quan hệ 1:1
    Nhưng bạn vẫn có thể đặt mọi thứ trong một repo mà triển khai độc lập
    Sẽ rất hay nếu ở những nơi như GitHub có thể coi từng thư mục là một dịch vụ độc lập

    • Ở công ty trước tôi đã tự triển khai cách này
      Dùng Bazel để quản lý cây phụ thuộc, rồi dùng bazel query để tìm các target bị ảnh hưởng và tự động chạy test
      Chúng tôi tạo workflow chặn PR bằng cách tích hợp với GitHub Actions
      Nó hoạt động tốt, nhưng mất vài tháng để xây dựng
    • Câu “chuyển từ microservices sang monolith thì vấn đề biến mất” làm tôi thấy khó chịu
      Vấn đề thực sự là do thiếu vận hành và công cụ — CI, autoscaling, quy trình on-call đều còn yếu
  • Cả hai cách tiếp cận đều có thể thất bại
    Trong các môi trường như Node.js hay Python, có giới hạn về lượng mã mà event loop có thể xử lý
    Tôi từng quản lý 200 dịch vụ với 6–8 người, và cũng từng thấy 80 người quản lý một monolith duy nhất
    Microservices có lợi cho thay đổi nhỏ, nhưng khó với thay đổi toàn cục, còn
    monolith thì ngược lại
    Cuối cùng điều quan trọng không phải kiến trúc mà là cách trừu tượng hóa, kiểm thử và tách ghép

    • “Nếu là phần mềm giải quyết một bài toán kinh doanh duy nhất, thì đúng ra nên gói vào một microservice
      Tiêu chí của “micro” không phải là công nghệ mà là đơn vị kinh doanh
      Nhỏ hơn mức đó thì sẽ thành nanoservice
    • Kiểu hợp lý hóa này rốt cuộc chỉ giống một giải pháp tạm để che đi giới hạn của runtime
      Trong các môi trường như Beam, JVM, Rust hay Go thì đây là vấn đề đã được giải quyết
    • Tôi tò mò cụ thể “giới hạn về lượng mã mà event loop xử lý được” là theo đơn vị nào
      Có phải là vấn đề cache CPU không?
    • Tôi cũng nghi ngờ liệu ở môi trường quy mô lớn người ta có thực sự dùng Node.js hay Python không
      Tôi cứ nghĩ thường sẽ dùng Go, Java hoặc C#
  • Ở phần lớn công ty, microservices thực ra là nguyên nhân của 90% vấn đề
    Nếu không phải tổ chức khổng lồ như AWS, Google hay Netflix thì nó không phù hợp
    Việc tự thân chia hệ thống thành các đơn vị có thể lắp ghép đã là khó, lại còn thêm ranh giới mạng vào thì càng ngớ ngẩn
    Tôi nghĩ xu hướng tiếp theo sẽ là rời khỏi React hay SPA để quay sang mô hình lấy server làm trung tâm

  • Lý do chuyển sang microservices lại là “vì test hay bị vỡ”, nghe như một cách tiếp cận ngược đời
    Test bị vỡ mà đi thay đổi hoàn toàn cấu trúc codebase thì thật kỳ lạ

    • Chúng tôi cũng từng gặp vấn đề tương tự, nhưng giải quyết bằng cách cấp môi trường phát triển độc lập cho từng nhóm
      Tách riêng VM và cấu hình CI/CD theo nhóm thì xung đột test biến mất
      Nhược điểm là không phát hiện ngay xung đột giữa các tính năng, nhưng vì quyền sở hữu mã rõ ràng nên không phải vấn đề lớn
  • Có người yêu cầu thêm [2018] vào tiêu đề

    • Không biết liệu bây giờ họ có quay lại microservices nữa hay không
    • Tôi thấy việc đào lại một bài từ 7 năm trước hơi không ổn. Trong thế giới công nghệ thì nó đã là cổ sử rồi
  • Họ nói đã tách repo vì “nếu test vỡ thì phải sửa cả những đoạn mã không liên quan”, nhưng
    có vẻ vẫn có những cách giải quyết khác như thay đổi cách chạy test hoặc cho phép triển khai thủ công
    Tách repo không phải là lời giải duy nhất