Thiết kế hệ thống microservice với Java: Một hướng dẫn toàn diện

MỤC LỤC

Load balancer

    Load balancer sử dụng thông tin ở tầng vận chuyển làm cơ sở để quyết định cách phân phối các yêu cầu của máy khách trên một nhóm máy chủ dựa trên thông tin về địa chỉ IP nguồn và đích cũng như các port được ghi trên header của packet mà không xem xét nội dung của packet. Nó đòi hỏi ít tính toán hơn so với các phương pháp cân bằng tải phức tạp hơn (chẳng hạn như Application Load Balancer), nhưng CPU và bộ nhớ hiện nay đủ nhanh và rẻ nên lợi thế về hiệu suất của Transport Load Balancer trở nên không đáng kể hoặc không còn phù hợp trong hầu hết các tình huống.

    Caching Glossary

    Các pattern trong caching 1. Local cache

    Ví dụ, sau khi người dùng xác thực vào dịch vụ của bạn, bạn có thể lưu trữ một số thông tin về ID và hồ sơ của người dùng được sử dụng để truy cập dịch vụ để tăng tốc hiển thị ứng dụng của bạn khi xem lại lần sau. • Bằng cách sử dụng bộ đệm được quản lý của nhà cung cấp dịch vụ đám mây, chúng tôi sẽ đặt tính khả dụng và bảo mật dữ liệu của dữ liệu được lưu trong bộ nhớ đệm vào tay các nhà cung cấp dịch vụ bên thứ ba.

    Các pattern truy cập trong caching 1. Cache-aside

    Cache là một bộ nhớ có độ trễ truy cập nhỏ hơn nhiều lần so với các database, nhưng đổi lại thì dung lượng của cache cũng nhỏ hơn nhiều so với các ổ đĩa cứng sử dụng để lưu trữ dữ liệu trong các database. • LFRU (Least Frequent Recently Used) - Giống như SLRU, nó có hai phân đoạn, nhưng một phân đoạn là LFU và phân đoạn khác là LRU (với nội dung phổ biến nhất).

    Microservices

    Miêu tả microservice

    Khái niệm microservice bắt đầu xuất hiện trong cộng đồng phát triển phần mềm như là một câu trả lời cho rất nhiều thử thách vướng phải (cả về mặt kỹ thuật lẫn tổ chức) khi mở rộng một ứng dụng monolithic lớn. • Khách hàng cũng yêu cầu hiệu suất đáng tin cậy và khả năng mở rộng: Các ứng dụng toàn cầu làm cho cực kỳ khó dự đoán có bao nhiêu giao dịch sẽ được xử lý bởi một ứng dụng và khi nào khối lượng giao dịch đó sẽ đạt được.

    Hình ảnh trên cho thấy cách mở rộng theo trục Y: chia nhỏ ứng dụng monolithic thành tập các  service
    Hình ảnh trên cho thấy cách mở rộng theo trục Y: chia nhỏ ứng dụng monolithic thành tập các service

    Phương thức giao tiếp giữa các service

      Một thách thức khi sử dụng REST là vì HTTP chỉ cung cấp một số lượng giới hạn các method, nên không phải lúc nào cũng dễ dàng để thiết kế một REST API hỗ trợ nhiều hoạt động cập nhật cùng lúc. Một ứng dụng dựa trên messaging thông thường sẽ có một message broker đóng vai trò trung gian giữa các service mặc dù có một số trường hợp các service sẽ giao tiếp trực tiếp với nhau.

      Hình trên cho thấy RPI hoạt động như thế nào. Logic nghiệp vụ ở client gọi proxy interface,  được triển khai bởi một RPI proxy adapter class
      Hình trên cho thấy RPI hoạt động như thế nào. Logic nghiệp vụ ở client gọi proxy interface, được triển khai bởi một RPI proxy adapter class

      Khuyết điểm của microservice

      • Triển khai tính năng trên nhiều service cần sự phối hợp cẩn thận: Một thách thức khác khi sử dụng kiến trúc microservice là việc triển khai các tính năng trải rộng trên nhiều service đòi hỏi sự phối hợp cẩn thận giữa các nhóm phát triển khác nhau. Tuy nhiên, nếu được thiết kế và triển khai đúng cách, microservices có thể mang lại nhiều lợi ích cho doanh nghiệp, chẳng hạn như khả năng mở rộng linh hoạt, availability cao và khả năng phát triển nhanh chóng.

      Service discovery & API Gateway

        • Server-side discovery pattern: Thay vì client truy vấn service registry, nó sẽ gửi yêu cầu tới DNS name và được xử lý bởi request router, request router truy vấn service registry và tự cân bằng tải các yêu cầu. • Tất cả khia cạnh của service discovery được xử lý hoàn toàn bởi nền tảng triển khai do đó cơ chế service discovery luôn có sẵn cho tất cả service và client bất kể ngôn ngữ và framework được sử dụng.

        Hình bên dưới cho thấy các hoạt động của nó. Nền tảng triển khai bao gồm service registry  nắm địa chỉ IP của các service đã triển khai
        Hình bên dưới cho thấy các hoạt động của nó. Nền tảng triển khai bao gồm service registry nắm địa chỉ IP của các service đã triển khai

        Distributed transactions

          Một vấn đề quan trọng trong Saga là đảm bảo bước thực hiện local transaction và bước gửi message được thực hiện một cách đơn nhất (atomic), để không có tình trạng service ngừng hoạt động sau khi thực hiện local transaction nhưng lại trước khi gửi message event, dẫn tới mất nhất quán giữa service đó - cũng như các service đã thực hiện local transaction trước nó - và các service còn lại trong saga. Eventuate Tram (https://github.com/eventuate-tram/eventuate-tram-. core)%E2%80%94Your Open source project sử dụng giao thức MySQL binlog, Postgres WAL hoặc đọc các thay đổi được thực hiện đối với OUTBOX table và publish chúng tới Apache Kafka.

          Consensus

          Vấn đề Consensus

          Đây là một vấn đề phổ biến khi các nút trong một hệ thống phân tán cần bầu chọn một nút từ trong số họ để hoạt động như người điều phối (leader) và điều phối hoạt động của toàn bộ hệ thống. Một vấn đề thường được đề cập là việc truyền tải nguyên tử (atomic broadcast), liên quan đến việc cho phép một tập hợp các nút truyền tải các thông điệp đồng thời, trong khi đảm bảo rằng.

          Thuật toán Raft 1. Khái quát về Raft

          • Khi người điều phối nhận được một lệnh mới, nó ghi thêm mục vào nhật ký riêng của mình và sau đó gửi một yêu cầu AppendEntries đồng thời đến các nút khác, nó sẽ lặp lại khi nó không nhận được phản hồi trong một khoảng thời gian từ một trong số các node chưa phản hồi. Nói cách khác, nhiệm kỳ của entry cuối trong log của candidate phải lớn hơn nhiệm kỳ của entry cuối trong log của follower - nếu nhiệm kỳ của 2 entry này bằng nhau thì index của entry của candidate phải lớn hơn; thỏa mãn được điều kiện này thì candidate sẽ có được phiếu bầu của follower.

          Querying in microservice

          Querying using the API composition pattern

          Nếu như sử dụng kiến trúc monolithic, vì dữ liệu của nó đặt tại một cơ sở dữ liệu duy nhất, ứng dụng có thể dễ dàng lấy thông tin đơn hàng bằng cách thực thi một câu lệnh SELECT duy nhất kết hợp thông tin từ các bảng khác nhau. Để API composer có thể được bảo trì cũng như có hiệu suất và khả năng mở rộng cao, nó nên sử dụng một reactive design dựa trên Java CompletableFutures, RxJava observables, hoặc công nghệ tương đương khác.

          Hình trên mô tả ba provider service. API composer thực hiện truy vấn bằng cách lấy dữ liệu từ  các provider service và kết hợp kết quả
          Hình trên mô tả ba provider service. API composer thực hiện truy vấn bằng cách lấy dữ liệu từ các provider service và kết hợp kết quả

          Using the CQRS pattern

          OrderService service thì có chưas status nên chúng ta có thể lọc các order dễ dàng còn KitchenService chỉ chứa orderId tham chiếu tới OrderService cho nên không có cách nào lọc các dữ liệu phù hợp ở KitchenService được. Mô hình CQRS giải quyết hạn chế này bằng cách định nghĩa một hoặc nhiều view của các aggregates, được cập nhật liên tục bằng cỏch đăng ký theo dừi cỏc luồng sự kiện được xuất bản bởi cỏc aggregates dựa trên event sourcing.

          Designing CQRS views

          Ví dụ, một ứng dụng sử dụng DynamoDB, chỉ hỗ trợ cập nhật và xóa dựa trên khóa chính, phải trước tiên truy vấn một chỉ mục phụ của DynamoDB (sẽ thảo luận sau) để xác định các khóa chính của các mục cần cập nhật hoặc xóa. Ví dụ, một event handler thao tác với Order History view có thể được gọi với chuỗi sự kiện (mặc dù nó khá là không thường xuyên) như trong hình dưới: Delivery-PickedUp, DeliveryDelivered, DeliveryPickedUp và.

          Deployment

          Virtual Machine & Container

          • Các container chia sẻ cùng một hệ thống phần cứng cơ bản dưới tầng hệ điều hành, có thể xảy ra tình huống một lỗ hổng bảo mật trong một container có thể thoát khỏi container và ảnh hưởng đến phần cứng chung. Nếu bạn có một yêu cầu cụ thể về phần cứng hoặc bạn đang phát triển ứng dụng trên một nền tảng phần cứng và mục tiêu của bạn là nhắm tới một nền tảng khác ví dụ như Windows &.

          Deploy patterns

            Trình quản lý cluster xem các máy chủ như một nguồn tài nguyên và quyết định đặt mỗi container ở đâu dựa trên tài nguyên yêu cầu của container và tài nguyên có sẵn trên mỗi máy chủ. Để triển khai dịch vụ của bạn bằng cách sử dụng phương pháp này, bạn đóng gói mã nguồn (ví dụ như một tập tin ZIP), tải lên cơ sở hạ tầng triển khai và mô tả các đặc điểm hiệu suất mong muốn.

            Docker và Docker Swarm 1. Docker

            Quá trình đóng gói một ứng dụng thành một image trong Docker sẽ tạo ra một image chứa tất cả các thành phần cần thiết để chạy ứng dụng đó, bao gồm mã nguồn, thư viện, biến môi trường và các tệp cấu hình. Giả sử ta có các hệ thống docker chạy trên các vps khác nhau thì ta có kể kết nối chúng tạo thành một cụm docker Chúng ta cần dùng Docker Swarm khi project của bạn cần phát triển, quản lý, deploy trên nhiều nhiều host thì đó là lúc cần dùng đến Docker Swarm.

            Kubernetes và Helm 1. Kubernetes

            Mỗi pod trong Kubernetes được gán một địa chỉ IP Pod duy nhất trong cụm, cho phép các ứng dụng sử dụng các port mà không có nguy cơ xung đột.Trong pod, tất cả các container có thể gọi lẫn nhau trên localhost, nhưng một container trong một pod không có cách nào connect trực tiếp một container khác trong một pod khác; vì vậy, nó phải sử dụng Địa chỉ IP Pod. "một khách hàng phát hiện danh sách các phiên bản có sẵn cho một loại dịch vụ cụ thể bằng cách truy vấn PTR record của DNS cho tên loại dịch vụ đó; máy chủ trả về không hoặc nhiều tên có định dạng <Service>.<Domain>, mỗi tên tương ứng với một cặp SRV/TXT record.

            Prometheus + Grafana

            Prometheus sử dụng mô hình pull-based, trong đó các máy chủ giám sát (prometheus server) định kỳ truy vấn các endpoints (exporters) trên các ứng dụng, máy chủ, hoặc hệ thống để thu thập dữ liệu về các chỉ số như CPU sử dụng, tài nguyên hệ thống, thời gian phản hồi, và nhiều hơn nữa. Grafana hỗ trợ nhiều nguồn dữ liệu, bao gồm các cơ sở dữ liệu thống kê như Prometheus, InfluxDB, Graphite, Elasticsearch, cũng như các dịch vụ đám mây như Amazon CloudWatch, Microsoft Azure Monitor, Google Cloud Monitoring, và nhiều nguồn dữ liệu khác.

            Elasticsearch+ Logstash + Kibana

            Nó cung cấp các API RESTful để tương tác với dữ liệu và cũng có thể tích hợp với các công cụ khác như Logstash (xử lý và chuyển đổi log), Kibana (trực quan hóa dữ liệu) và Beats (xử lý và gửi dữ liệu). Bằng cách sử dụng các bộ lọc (filters), bạn có thể chuẩn hóa, phân tích cú pháp, chuyển đổi định dạng và thực hiện các thao tác khác trên log trước khi gửi chúng đến Elasticsearch hoặc các đích khác.

            Xây dựng hệ thống với Spring Boot 10.1. Spring Boot Starter

              Với Spring Boot Starter, bạn cũng có thể sử dụng các dependency khác như Spring Data JPA cho truy vấn cơ sở dữ liệu, Spring Security cho bảo mật ứng dụng, Spring Cloud cho phát triển ứng dụng phân tán, và nhiều hơn nữa. Trong ví dụ trên, chúng ta cấu hình một khả năng Circuit Breaker với các thuộc tính như thời gian chờ trong trạng thái mở, ngưỡng tỷ lệ lỗi, kích thước bộ nhớ đệm vòng trong trạng thái mở và trạng thái đóng.

              Demo và tổng kết 11.1. Demo

              Tổng kết

              Tuy rằng còn nhiều thiếu sót, nhưng trong quá trình tìm hiểu về thiết kế và xây dựng hệ thống nhóm đã học được rất nhiều kiến thức hữu ít, được sử dụng các công nghệ phức tạp và dùng chúng cho việc xây dựng một hệ thống E-Commerce demo. Với các kiến thức nền tảng này, nhóm sẽ tiếp tục tìm tòi và học hỏi thêm các kiến thức chuyên sâu hơn về việc xây dựng hệ thống để có thể áp dụng vào các dự án thực tế.