Thiết kế và triển khai hệ thống sử dụng Spring Boot

MỤC LỤC

GIỚI THIỆU ĐỀ TÀI

THIẾT KẾ HỆ THỐNG

  • Triển khai bộ cân bằng tải

    - Tính mở rộng theo chiều dọc (Vertical scaling/ Scaling Up): là cách mở rộng server hiện tại bằng cách nâng cấp độ mạnh (power) bằng cách nâng cấp CPU, Ram, Storage, v.v… Vertical-scaling cho phép chúng ta mở rộng năng xuất của phần cứng và phần mềm, nhưng thường bị giới hạn bởi giới hạn về cấu hình vật lý hiện đại hay độ trễ khi “chẳng may” Server bị downtime để nâng cấp hay triển khai hệ thống. 12 Lỗi Byzantine (Byzantine fault), hay còn gọi là Vấn đề các vị tướng Byzantine, là một tình trạng của một hệ thống, đặc biệt là hệ thống phân tán, trong đó các thành phần có thể bị lỗi và không có thông tin chính xác về việc liệu thành phần đó có bị lỗi hay không.

    Hình 2.8: Kĩ thuật sao chép
    Hình 2.8: Kĩ thuật sao chép

    CƠ SỞ DỮ LIỆU

    Các loại cơ sở dữ liệu

      Cơ sở dữ liệu đồ thị “Graph” sử dụng cấu trúc dữ liệu đồ thị để lưu trữ dữ liệu, trong đó các nút (nodes) đại diện cho các thực thể (entities), và các cạnh (edges) biểu thị mối quan hệ giữa các thực thể. Trường hợp sử dụng: Cơ sở dữ liệu đồ thị cho phép biểu diễn dữ liệu theo các mối quan hệ phức tạp, như mô hình hóa mạng xã hội, quan hệ tương tác giữa người dùng trên mạng, và nhiều ứng dụng khác. Không yêu cầu ACID (Atomicity, Consistency, Isolation, Durability) Không thường cần tích hợp dữ liệu Không thường cần tích hợp dữ liệu Thích hợp cho dữ liệu có kích thước tương đối nhỏ.

      Hình 4.2: Các loại cơ sở dữ liệu không quan hệ
      Hình 4.2: Các loại cơ sở dữ liệu không quan hệ

      GIAO DỊCH PHÂN TÁN

      • Xác nhận 2 pha “2-Phase Commit” (2PC)
        • Xác nhận 3 pha “3-Phase Commit”

          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, 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. - Transactional outbox: ghi message vào một table trong database (table outbox), table này dùng để ghi nhớ các message được phát đi bởi service; khi này, ta hoàn toàn có thể gói gọn các thao tác của local transaction và thao tác ghi message trong cùng một database transaction. Đồng thời, saga cũng đảm bảo availability cao hơn so với 2PC/3PC do client chỉ cần đợi service đang thực hiện local transaction mà không cần phải chờ tất cả các service tham gia transaction - các service khác vẫn có thể xử lý yêu cầu trên các dữ liệu transaction, cũng như không cần phải áp dụng các cơ chế khóa đọc - ghi trong cả thời gian thực hiện transaction.

          Hình 5.1: Minh họa 2PC
          Hình 5.1: Minh họa 2PC

          BỘ NHỚ ĐỆM

          • Nguyên lý xóa bỏ

            - Xác định máy chủ bộ đệm trong một hệ thống bộ đệm phân tán để lưu trữ và truy xuất dữ liệu: Trong tình huống này, ta thường sử dụng các thuật toán băm khác nhau để xác định máy chủ bộ đệm cụ thể mà dữ liệu nên được lưu trữ và truy xuất. - Most recently used (MRU): loại bỏ các dữ liệu được sử dụng gần đây nhất, ưu tiên các dữ liệu chưa được sử dụng; thuật toán này thường được ứng dụng trong các hệ thống gợi ý dữ liệu mới, chẳng hạn như Tinder. Chương trình luôn đọc dữ liệu từ bộ nhớ đệm trước, nếu bộ nhớ đệm không có dữ liệu đó thì chương trình sẽ đọc từ cơ sở dữ liệt rồi ghi vào bộ nhớ đệm để hỗ trợ những lần đọc sau; ngược lại, bộ nhớ đệm sẽ trả kết quả ngay lập tức cho chương trình.

            Hình 6.4: Mô hình bộ nhớ đệm “read-through”
            Hình 6.4: Mô hình bộ nhớ đệm “read-through”

            SERVICE DISCOVERY & API GATEWAY

            Phân loại Service Discovery

              - Cần có sự chặt chẽ của client với registry dịch vụ, điều này có nghĩa là service discovery phải được triển khai cho mỗi ngôn ngữ lập trình và framework được sử dụng bởi các service clients. - Nó làm cho quản lý ứng dụng phức tạp khi kiến trúc microservices làm việc với các công nghệ, framework và công cụ đa dạng của các ngôn ngữ khác nhau. - Server side Service Discovery cần được thiết lập và quản lý trừ khi được cung cấp sẵn một giải pháp hoặc công cụ service discovery Server side.

              Hình 7.1: Ảnh minh họa Client side Service Discovery
              Hình 7.1: Ảnh minh họa Client side Service Discovery

              API Gateway

                Trong một hệ thống chúng ta chỉ thường giải quyết một sự cố khi một thành phần gặp lỗi và phải ngừng hoạt động, đơn giản chúng ta chỉ cần điều hướng đến các thành phần đang hoạt động xung quanh nó. 54 Mô hình phần mềm Client Resiliency là một phương pháp thiết kế và triển khai trong phát triển phần mềm, nhằm đảm bảo rằng khi một tài nguyên từ xa (như một cuộc gọi đến một dịch vụ mạng hoặc truy vấn cơ sở dữ liệu) gặp sự cố, ứng dụng khách hàng không gặp phải sự chết đột ngột (crash) hay mất mát dữ liệu. 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 tất cả các điểm đến đều phân phối chúng theo cùng một tuần tự mặc dù có thể có sự xuất hiện của các nút bị lỗi.

                Thuật toán Raft

                  Bất kỳ người điều phối từ các nhiệm kỳ trước đây sẽ không thể sao chép các mục nhật ký (log entries) mới đến các nhóm vì những người bỏ phiếu cho người điều phối mới sẽ từ chối các yêu cầu của người điều phối cũ, và cuối cùng nó sẽ phát hiện mình đã bị thay thế. - 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.

                  Hình 8.3: Cấu trúc của Replicated log
                  Hình 8.3: Cấu trúc của Replicated log

                  Các mẫu triển khai

                    - Monitoring: Khi triển khai hệ thống microservices thì ta sẽ phải triển khai thêm một hệ thống monitoring phức tạp để có thể thu thập đủ các metrics cần thiết cho việc vận hành hệ thống. - Nếu nhiều instance được triển khai trong cựng một quỏ trỡnh, việc theo dừi việc tiêu thụ tài nguyên của mỗi instance là khó khăn. - Hạn chế và ràng buộc đáng kể - Môi trường triển khai serverless thường có nhiều hạn chế hơn so với cơ sở hạ tầng dựa trên máy ảo hoặc container.

                    Hình 9.1. Mô hình mẫu Multiple Service Instances per Host
                    Hình 9.1. Mô hình mẫu Multiple Service Instances per Host

                    Docker

                      67 trạng thái chạy dựa trên yêu cầu thay vì triển khai ứng dụng lưu trạng thái hoạt động lâu dài như database hoặc message broker. - Hạn chế nguồn đầu vào – Lambda chỉ có thể phản ứng với yêu cầu từ một số nguồn đầu vào hạn chế. 68 - An toàn và bảo mật: Docker cung cấp các công cụ để kiểm tra và cung cấp môi.

                      Kubernetes & Helm

                        - Kho lưu trữ chart: Helm cung cấp một kho lưu trữ trực tuyến để chia sẻ và tìm kiếm các charts có sẵn, giúp cộng đồng Kubernetes chia sẻ các mô hình triển khai ứng dụng tiện lợi và dễ dàng hơn. Spring Boot là một trong số những module của Spring Framework chuyên cung cấp các tính năng Rapid Application Development (RAD) để tạo ra và phát triển nhanh các ứng dụng độc lập dựa trên Spring. Bằng cách này, các nhà phát triển Spring Boot bắt đầu xây dựng ứng dụng của họ ngay lập tức, tập trung nhiều hơn vào logic nghiệp vụ vì phần lớn công việc được thực hiện bởi chính framework.

                        Hình 9.4. Kiến trúc Cluster Kubernetes
                        Hình 9.4. Kiến trúc Cluster Kubernetes

                        Spring Config Server Khái niệm

                        - Tương thích Đa Ngôn Ngữ: Mặc dù được thiết kế chủ yếu để tích hợp với ứng dụng Spring, nhưng Spring Cloud Config cũng có thể sử dụng được với các ứng dụng chạy bằng bất kỳ ngôn ngữ lập trình nào. Phần chính của ứng dụng là một lớp cấu hình (config class), cụ thể là một lớp được đánh dấu bằng @SpringBootApplication, nó chọn lựa tất cả các cài đặt cần thiết thông qua chú thích tự động cấu hình @EnableConfigServer. Ở config server, bản triển khai mặc định của EnvironmentRepository sử dụng một hệ thống lưu trữ Git, điều này rất thuận tiện để quản lý việc nâng cấp, môi trường vật lý và để kiểm tra các thay đổi.

                        Spring Boot với Eureka

                        Vì vậy chúng ta cần cấu hình cho config server để có thể kết nối đến repository chúng ta đã tạo trên Github. Dịch vụ Eureka giúp giải quyết một số vấn đề trong môi trường Microservices, như quản lý và theo dừi cỏc dịch vụ, khỏm phỏ dịch vụ tự động, và đảm bảo khả năng mở rộng của hệ thống. Tại thành phần đảm nhiệm việc Service Discovery chúng ta sẽ thêm chú thích để Spring Boot có thể tự hiểu và khai báo đây chính là Eureka Server.

                        Sping Cloud Gateway

                        - Global Filters: Là các lọc được áp dụng trên tất cả các routes, giúp thực hiện các chức năng chung như đăng nhập, quản lý lỗi, và đo lường thời gian xử lý. Trong hệ thống, Discovery Service giải quyết vấn đề đặt tên cho các dịch vụ thay vì hardcode địa chỉ IP của chúng. 80 Để sử dụng Spring Cloud Gateway, bạn cần thêm dependency tương ứng vào file pom.xml (cho Maven) hoặc build.gradle (cho Gradle) của dự án.

                        Hình 10.10: Kiến trúc của Spring Cloud Gateway
                        Hình 10.10: Kiến trúc của Spring Cloud Gateway

                        Spring Boot Cache

                        - Cache: Là một vùng lưu trữ dữ liệu tạm thời với khóa và giá trị, nơi mà dữ liệu có thể được lưu trữ và truy xuất nhanh chóng. - @Cacheable: Là một chú thích được sử dụng để báo cho Spring rằng kết quả của một phương thức nên được lưu trữ trong cache để tái sử dụng trong các lần gọi sau đó. - @CacheEvict: Chú thích này được sử dụng để xóa các mục khỏi cache, có thể được áp dụng trước hoặc sau khi phương thức được gọi.

                        Spring Boot Actuator

                          Như tất cả các dự án Spring khác, sức mạnh thực sự của Spring Security nằm ở khả năng mở rộng một cách dễ dàng để đáp ứng các yêu cầu tùy chỉnh. 83 - Xác thực người dùng: Spring Boot Security cung cấp nhiều phương pháp xác thực người dùng khác nhau, bao gồm xác thực bằng username và password, xác thực bằng LDAP, xác thực bằng OAuth2, v.v. - Bảo vệ chống lại các cuộc tấn công phổ biến: Spring Boot Security cung cấp cách để bảo vệ ứng dụng của bạn khỏi các cuộc tấn công phổ biến, chẳng hạn như tấn công CSRF, tấn công XSS,….

                          Spring Cloud Resilience4j

                          85 - Các ứng dụng của bên thứ ba có thể xác minh mã thông báo JWT bằng cách sử. - Sử dụng JwtTokenFilter để xác minh mã thông báo JWT trong các yêu cầu HTTP.

                          Tổng kết

                          Mặc dù nhóm nhận thấy vẫn còn một số điểm cần cải thiện, nhưng quá trình tìm hiểu về thiết kế và xây dựng hệ thống đã mang lại cho nhóm rất nhiều kiến thức quý báu. Nhóm đã áp dụng các công nghệ phức tạp vào việc phát triển demo một hệ thống đặt đồ ăn, đồng thời tiếp tục khỏm phỏ và nghiờn cứu sõu hơn để hiểu rừ hơn về cỏch xõy dựng hệ thống. Những kiến thức cơ bản này sẽ là nền tảng vững chắc, sẽ giúp nhóm áp dụng chúng một cách hiệu quả trong các dự án thực tế tiếp theo.

                          Hình 11.1: Tổng quan hệ thống
                          Hình 11.1: Tổng quan hệ thống