Speed up Microservices 1: Tác dụng phụ và một số chiến lược cơ bản

trong danh mục DevOps


Chào mọi người, nếu như các bạn cũng biết thì dự án Teamcrop của mình xây dựng và chạy hoàn toàn trên kiến trúc Microservices và sau hơn 2 năm triển khai thì có một số vấn đề liên quan đến kiến trúc này, thiết nghĩ cần chia sẻ thêm với mọi người để mọi người thấy được rằng Microservices không phải là chìa khóa vạn năng như vẫn hay nghe quảng cáo, dụ dỗ. Mọi kiến trúc đều có đánh đổi và Microservices cũng vậy.

Mình sẽ viết một loạt bài (5, 6 bài gì đó) về việc tăng tốc cho kiến trúc Microservices mà đã rút tỉa được trong quá trình triển khai dự án Teamcrop, bởi tốc độ luôn là yếu tố hàng đầu khi xây dựng các ứng dụng web, và với kiến trúc mới này thì tăng tốc là một kỹ thuật cần xem xét khi triển khai.

Microservices là gì?

Nếu mọi người chưa biết Microservices thì nên tìm hiểu trước khi quay lại đọc bởi phải hiểu, thậm chí đã triển khai rồi thì mới thấy được những vấn đề mà mình đề cập.

Trong kiến trúc Microservices, các service (dự án) tồn tại độc lập nhau về xử lý (process), lưu trữ (database) và request (client/server model). Hình minh họa bên dưới là minh họa 1 thành phần trong kiến trúc microservices (lưu ý là nó không liên quan đến phần bài toán đề cập bên dưới).

Ví dụ bạn xây dựng một hệ thống bán hàng dựa trên Microservices (như Teamcrop chẳng hạn) thì giả sử một đơn hàng được mô tả với các thông tin sau “Hôm nay có nhân viên A tạo một đơn hàng B tại cửa hàng C và xuất từ kho D” thì bạn cần tối thiểu 4 service (project) với database độc lập:

  • Employee service (sử dụng table tc_employee)
  • Store service (sử dụng table tc_store)
  • Inventory service (sử dụng table tc_warehouse)
  • Order service (sử dụng table tc_order). Trong đó table tc_order chỉ chứa khóa ngoại – tức ID của Nhân viên, ID của cửa hàng, ID của nhà kho theo đúng tinh thần thiết kế chuẩn hóa database.

Bởi vì theo kiến trúc Microservices nên hệ thống bạn sẽ chạy 4 dịch vụ khác nhau như trên và chạy ở tối thiểu 4 instance (container, server) khác nhau.

Lợi ích của Microservices

Nếu đọc đến đây thì bạn sẽ thấy được việc tách ra như thế sẽ làm cho mô hình Microservices phát huy thế mạnh như đã quảng cáo là:

  • Source code tinh gọn: bởi vì hệ thống cấu thành từ những dự án nhỏ, mỗi dự án sẽ đơn giản và tập trung vào 1 hoặc 1 vài nghiệp vụ chính nên code base và độ phức tạp cũng không cao. Giúp mang lại tính gọn nhẹ, dễ bảo trì và mở rộng.
  • Bảo mật source code: vì nhân viên nào làm việc ở dự án nào thì chỉ truy cập được source code của dự án đó.
  • Tồn tại độc lập: vì đây là 4 dự án khác nhau và có thể có cách deploy riêng, và một service nào đó chết thì service khác vẫn hoạt động bình thường.
  • Scale độc lập: tùy theo nhu cầu sử dụng của hệ thống mà có thể scale riêng service đó, ví dụ như service đơn hàng sử dụng thường xuyên nên có thể chạy 2, 3 server (container) để tăng performance.

Tác dụng phụ của Microservices

Các điểm bên trên đúng là các ưu điểm của microservices, tuy nhiên, hãy nghĩ đến ngữ cảnh ở trên. Nếu ở website bạn hiện 1 table view với thông tin sau:

Invoice ID Nhân viên Cửa hàng Kho xuất
123456 Võ Duy Tuấn Cropcom Kho HCM

thì bạn sẽ làm như thế nào và tối ưu nhất? Có thể trong đầu các bạn đã nghĩ đến JOIN, nhưng xin thưa, đây không phải là ứng dụng Monolithic, mà đây là microservice và 4 database table này ở 4 database server khác nhau nên không có chuyện JOIN gì cả, và ở table đơn hàng (tc_order) bạn chỉ có EmployeeID, StoreIDWarehouseID.

Chào mừng đến với tác dụng phụ của Microservices.

Một số chiến lược cơ bản

Để giải quyết bài toán hiển thị ở trên, bạn chỉ có thể tiếp cận theo hướng lấy dữ liệu trực tiếp từ service liên quan. Từ EmployeeID, gọi sang service Employee, từ StoreID thì gọi sang service Store…để lấy các thông tin cần hiển thị. Việc này sẽ dẫn đến giao tiếp liên service (inter-service communication).

Trong kiến trúc Microservices, càng hạn chế gọi liên service càng tốt vì các service sinh ra để phục vụ bên ngoài chứ không phải để phục vụ liên service, dẫn đến performance hệ thống sẽ bị giảm, vì nếu thiết kế không tốt, các service bị die hầu như do các service gọi lẫn nhau gây quá tải chứ từ client chưa chắc quá tải :).

Ngoài ra, gọi liên service sẽ có overhead vì vẫn có giao thức kết nối đi kèm (như HTTPS, Protobuf..) nên phải hạn chế. Do đó, cách dễ dàng tiếp cận nhất là sử dụng cache để không phải request nhiều đến các service mà chỉ cần mò vào cache. Có thể sử dụng Redis hoặc memcache cho tính năng này. Nhiệm vụ còn lại của bạn chỉ là làm sao clear cache một cách hiệu quả mà thôi.

Như vậy, với 1 đơn hàng, bạn sẽ cần thêm 3 request đến cache để fetch thêm thông tin (employee, store và warehouse) trước khi trả về client để hiển thị đầy đủ thông tin.

Teamcrop đã làm thế nào?

Ở trên là cách mình đề xuất và mọi người cũng nghĩ ra dễ dàng vì nó khá cơ bản cho các ứng dụng web hiện đại. Tuy nhiên, dự án Teamcrop không theo cách này và theo 1 cách “phức tạp” hơn nhiều và tất nhiên nó sẽ nhanh hơn cách ở trên.

Trong bài tiếp theo, mình sẽ chia sẻ chi tiết cách Teamcrop đã giải quyết bài toán này như thế nào, tận dụng web socket, service worker của trình duyệt để tăng tốc tối đa cho việc hiển thị dạng này.

Hy vọng bạn sẽ thích các thông tin này và sẽ tiếp tục theo dõi loạt bài chia sẻ kỹ thuật tăng tốc cho kiến trúc Microservices.

P.S: Teamcrop.com là hệ thống ERP dành cho chuỗi bản lẻ và luôn tìm kiếm lập trình viên PHP, nếu bạn biết PHP, yêu thích xây dựng các dự án web lớn, phức tạp trên những kiến trúc mới như Microservices, công nghệ mới như Docker thì đừng ngần ngại liên hệ với Tuấn (qua email tuanmaster2012@gmail.com) để tham gia cùng mình xây dựng những sản phẩm thú vị.

9 bình luận

  1. […] Speed up Microservices 1: Tác dụng phụ và một số chiến lược cơ bản […]

  2. Thành says:

    Mong bạn sớm ra phần 2 ^^. Cảm ơn bạn về bài viết

    [Reply]

  3. huy says:

    Cám ơn vì bạn đã chia sẽ bài viết. Mong bạn sớm ra phần 2.

    [Reply]

  4. Tùng says:

    Cám ơn anh đã chia sẻm Mong anh sớm ra phần 2

    [Reply]

  5. Kevin says:

    Chào bạn,

    Mình thấy Microservice không phải áp dụng ở đâu cũng phù hợp.

    Đối với các hệ thống TMĐT và bán hàng thông thường do có mối quan hệ giữa các model rất chặt chẽ nên dùng giải pháp truyền thống, sau đó triển khai scale bình thường là tốt nhất.

    Microservice nên được hiểu là một ứng dụng độc lập trong một hệ sinh thái ứng dụng (kiểu như Google Apps), nếu chia nhỏ model ra lại hóa dở.

    Thân.

    [Reply]

  6. Linh says:

    Anh Tuấn có dùng GraphQL + Data Loader chưa anh ? Mình thấy là nó cũng gỉai quyết được việc gọi các query liên quan với nhau khá tốt.

    [Reply]

  7. Polygon Worls says:

    Cám ơn bạn đã chia sẽ kiến thức, trông ngóng phần 2

    [Reply]

  8. Phong Nguyen says:

    Cảm ơn bạn đã chia sẻ kiến thức.
    Bài viết rất hay và thực tế.
    Mong chờ phần 2 cách giải quyết của các bạn sử dụng websocket và service worker

    [Reply]

  9. Bang Andre says:

    Bài viết khá hay. Với các web application hay các ứng dụng lớn nên chia nhỏ để cân bằng tài và xử lý tinh gọn như Microservices của anh.

    Thanks & Regards
    Bang

    [Reply]

Gởi bình luận