Thiết kế và xây dựng hệ thống cân bằng tải sử dụng Net Core

MỤC LỤC

Phân loại

Hardware & Software

Hardware load balancer: là các thiết bị phần cứng máy tính chạy trên các phần mềm mã nguồn đóng, được xây dựng đặc biệt để có thể vận hành trên các bộ xử lý tùy chỉnh. Chúng ta chỉ cần cài đặt phần mềm cân bằng tải vào trong hệ thống của mình, vẫn đảm bảo lưu lượng truy cập mà hệ thống chịu tải trong khi không cần bỏ một mức chi phí rất lớn cho việc sử dụng và vận hành các hệ thống cân bằng tải vật lý.

Tầng xử lý

Với càng nhiều lưu lượng truy cập, số lượng các thiết bị cân bằng tải phải tăng lên theo tỷ lệ thuận để có thể đáp ứng nhu cầu dịch vụ của khách hàng. Layer 3/4 load balancer: hoạt động ở tầng network và tầng transport trong mô hình OSI, sử dụng thông tin về địa chỉ IP và cổng TCP/UDP để đưa ra quyết định định tuyến.

Patterns

Client-side load balancing: là phương pháp trong đó việc phân phối lưu lượng mạng được thực hiện ở phía client. Client sẽ nhận thông tin về các máy chủ backend từ một dịch vụ danh mục (registry service) và sử dụng một thuật toán để chọn một máy chủ backend để gửi yêu cầu.

Tăng availability của hệ thống

Sau đó, client sẽ gửi yêu cầu trực tiếp đến máy chủ backend được chọn và nhận kết quả trả về.

Caching

  • Các pattern trong caching
    • Các pattern truy cập trong caching

      Đây là sự kết hợp giữa Reverse-proxy và Sidecar cache, được tạo bằng cách chạy Reverse-proxy container và cache data container trên cùng một Pod. Cache eviction là quá trình loại bỏ các dữ liệu cũ, không được sử dụng thường xuyên hoặc có dung lượng quá lớn ra khỏi cache nhằm tạo ra không gian trống cho các tệp mới. Ngoài ra còn phụ thuộc vào việc dữ liệu trả về có thay đổi hay không (truy vấn theo primary key thì thường hiếm khi thay đổi).

      Chiến lược này khá giống với cache-aside, thay vì application phải kết nối với cache và database, giờ đây application chỉ cần giao tiếp với cache còn cache sẽ tự lấy dữ liệu ở chính nó hoặc lấy dữ liệu từ database. Với cache-aside, việc cache bị chết thì ứng dụng vẫn chạy được, nhưng với read through cache, nếu cache chết thì ứng dụng chết.

      Microservices

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

      Domain-specific protocol: trong một vài trường hợp đặc biệt chúng ta không thể sử dụng RPI hay Messaging mà thay vào đó cần dùng domain-specific protocol cho việc giao tiếp giữa các services.

      Service discovery & API Gateway

      • Sử dụng service
        • Envoy

          Khi này việc phát hiện ra service và register và của một phần khác của hệ thống và service sẽ không cần phải biết bất cứ thứ gì về registry. Mặt khác các request sẽ trở nên phức tạp hơn vì ta sẽ cần phải tổng hợp lại các thông tin mà ta thu thập từ nhiều service khác nhau, ta phải biết service nào cung cấp thông tin nào. ● Thêm tác nhân gây lỗi: để sử dụng API Gateway thì chúng ta sẽ phải config, chỉnh sửa code, quản lý server gateway… Khiến cho chúng ta có thêm việc phải làm, nhiều trường hợp gateway có lỗi thì requests sẽ không thể tới được phía server.

          ● Phát sinh thêm chi phí: tiền server, tiền điện, tiền quản lý hệ thống API Gateway, với hệ thống lớn cần các tính năng xịn sò thì phải tốn thêm chi phí mua bản Enterprise với giá không hề rẻ. Envoy có thể hoạt động với bất kỳ ngôn ngữ lập trình nào, với một lần triển khai Envoy duy nhất có thể tạo thành một mạng lưới giữa Java, C++, Go, PHP, Python….

          Distributed transactions

            Giải pháp được đưa ra như sau: ta sẽ coi mỗi một transaction trải rộng trên nhiều services là một Saga và mỗi một Saga là một chuỗi các transaction cục bộ trên từng service khác nhau. Nếu một transaction cục bộ thất bại thì Saga sẽ thực hiện một loạt các transactions để rollback lại các thay đổi đã được thực hiện trước đó. Transaction phân tán kết thúc khi service cuối cùng thực hiện transaction cục bộ của nó và không publish bất kỳ event nào hoặc event được publish không được nghe thấy bởi bất kỳ services nào của saga.

            Two-phase commit và Three-phase commit sẽ đảm bảo tính nhất quán hơn so với Saga do bản chất Saga chỉ là một chuỗi các local transaction nối tiếp nhau, kết quả của cả Saga sẽ không nhất quán cho đến khi toàn bộ local transaction hoàn tất thành công. Nhưng ngược lại, Saga dễ thực hiện, dễ triển khai và có độ tương thích cao hơn nhiều so với Two-phase commit và Three-phase commit.

            Consensus

            Thuật toán Raft

              Cluster đảm bảo tính nhất quán giữa đa số node, các node thiểu số cũng sẽ trở nên nhất quán sau một khoảng thời gian ngắn. Cluster có khả năng chịu lỗi (fault tolerant), chịu phân vùng (network partition tolerance) và tự sửa lỗi (self-correcting). Vì mọi thao tác ghi đều thông qua leader và chỉ có thể có 1 leader trong một cluster tại một thời điểm, nên các thao tác ghi về cơ bản không có khả năng scale horizontal.

              Leader và follower phải liên tục giao tiếp thông qua heartbeat, dẫn đến lưu lượng truy cập lớn giữa các server. Đây là thách thức lớn trong hệ thống có các server đặt ở các vị trí cách xa nhau về địa lý và tạo ra độ trễ nhất định.

              Deployment

              • Deploy patterns
                • Kubernetes và Helm
                  • Prometheus + Grafana

                    ● Deploy và quản lý các ứng dụng: Kubernetes cho phép deploy và quản lý các ứng dụng được đóng gói trong các container một cách dễ dàng và hiệu quả. ● Tự phục hồi: Kubernetes có thể tự động khôi phục lại các container bị lỗi hoặc bị ngắt kết nối để đảm bảo tính sẵn sàng cao cho các ứng dụng. Helm là một trình quản lý gói và công cụ quản lý ứng dụng cho Kubernetes, đóng gói nhiều tài nguyên Kubernetes vào một đơn vị triển khai logic duy nhất được gọi là Chart.

                    Là một phần mềm monitoring có tích hợp chức năng alert, các phần mềm chỉ cần expose path/metrics và có định dạng đúng là có thể dùng Prometheus để pull metris. Với sự hỗ trợ rất nhiều cách thức để trực quan, thể hiện dữ liệu khác nhau, chúng ta có thể tạo một dashboard thể hiện đầy đủ thông tin như dưới đây.

                    Xây dựng hệ thống với .NET Core

                    ASP.NET Core

                      ORM (Object-Relational Mapping) là một kỹ thuật cho phép query và thực hiện các thao tác với cơ sở dữ liệu quan hệ bằng cách sử dụng mô hình lập trình hướng đối tượng. Entity Framework Core (EF Core) là một ORM framework giúp dễ dàng truy xuất và lưu trữ dữ liệu trong database thông qua việc ánh xạ database thành các objects tương ứng trong code. Dapper và EF Core có thiết kế và phương pháp tiếp cận khác nhau và tùy trường hợp, mục đích, yêu cầu khác nhau của dự án mà chúng ta sẽ sử dụng.

                      EF Core cho phép chúng ta abstract đi phần SQL bên dưới và chỉ tập trung vào logic bên trên, điều này giúp lập trình viên không cần phải tập trung quá nhiều vào việc viết cỏc cõu lệnh truy vấn. EF Core là một black box và nếu chỳng ta khụng hiểu rừ được quy tắc hoạt động của nú thỡ cú thể dẫn đến các câu lệnh truy vấn kém hiệu quả gây lãng phí tài nguyên.

                      Clean architecture

                      Framework & Drivers là tầng ngoài cùng, tổ hợp các công cụ cụ thể phục vụ cho từng nhu cầu của end user như: thiết bị (devices), web, application, databases,. ● Rất dễ maintain và mở rộng: việc tìm kiếm bug và các lỗi logic sẽ trở nên dễ dàng và nhanh hơn, file code sẽ không nhiều vì chỉ làm đúng việc của nó. ● Rất dễ làm Unit Test: các logic business của các tầng trong Clean Architecture chính là các Unit Test cần được kiểm thử rất cẩn thận.

                      Trong trường hợp ứng dụng đơn giản, ít tính năng, vòng đời ngắn thì chọn lựa kiến trúc này có thể mang lại những rắc rối không cần thiết. Nguyờn tắc Dependency Inversion rất dễ bị xâm phạm vì sự hạn chế kiến thức, sự bất cẩn hoặc vì thời gian cần triển khai tính năng quá ít.

                      Thiết kế hệ thống lớn

                      Interface Adapters chính là layer phụ trách việc chuyển đổi các format dữ liệu để phù hợp với từng Use Case và Entities. Trong kiến trúc Clean Architecture thì ở tầng này là "nhẹ" nhất vì chúng ta không cần phải viết quá nhiều code. Vì các tầng độc lập với nhau thông qua các Interfaces nên việc mở rộng hoặc thay đổi các tầng sẽ không ảnh hưởng tới nhau.

                      ● Cồng kềnh và phức tạp: điều dễ thấy nhất là Clean Architecture không hề dễ sử dụng, phải viết nhiều lớp (class/object) hơn. ● Khó tuyển developer có trình độ tốt: sử dụng Clean Architecture sẽ cần tuyển dụng developer hiểu rừ về kiến trỳc này.