Software Engineering hiện đại — Phần 1: Thiết kế hệ thống


Lớn lên vào cuối những năm 80 và đầu những năm 90, việc tiếp xúc với máy tính của tôi hầu như chỉ giới hạn ở các máy chơi game (tôi đã cân nhắc các máy tính chơi game Atari 800 và Commodore 64 vì tôi chỉ từng thấy các game được chạy trên chúng) hoặc các hệ thống x86 đời đầu. Mãi cho đến khi vào đại học những năm 2000, tôi mới có được máy trạm SPARC, UNIX và Slackware Linux của Sun Microsystems mà tôi có thể cài đặt trên máy Intel 486 của mình ở nhà.





Trước đó, phát triển phần mềm chủ yếu là về phần mềm chạy cục bộ trên máy của bạn hoặc, nếu bạn có quyền truy cập vào phần mềm đó, một máy tính dùng chung với sức mạnh xử lý cao hơn đáng kể có sẵn để bạn… làm những việc liên quan đến kinh doanh. Ở trường đại học, tôi nhớ đã nghe nói về một chương trình được sử dụng bởi các nhà khoa học máy tính cần một bộ xử lý đa lõi để tạo lịch học của hàng nghìn sinh viên; phải mất hàng tuần để tạo và in. Cho đến nay, tôi vẫn không chắc cái nào mất nhiều thời gian hơn – chạy chương trình hay in ra giấy.





Ngày nay, phần lớn phần mềm được phát triển chạy trên đám mây, chạy trên thiết bị yêu cầu quyền truy cập vào đám mây hoặc cung cấp sức mạnh cho phần mềm khác cũng chạy trên đám mây. Rất hiếm khi làm việc trên một hệ thống phần mềm hoạt động trong không gian hạn chế (ví dụ: hệ thống phần mềm nhúng – embedded software system) không có quyền truy cập vào nền tảng điện toán mạnh hơn ở nơi khác. Các hệ thống kế toán hiện xử lý hàng đống dữ liệu được lưu trữ trong các trang trại máy chủ tại cơ sở của công ty hoặc trong data warehouse. Các hệ thống bán hàng hiện quản lý quan hệ khách hàng do bên thứ ba quản lý với các plugin được phát triển bởi nhiều bên thứ ba hoặc nhà phát triển nội bộ hơn.





Nhưng làm thế nào để các hệ thống phần mềm này được xây dựng phục vụ hàng trăm đến hàng triệu người dùng trong khi vẫn duy trì hiệu suất và khả năng phản hồi mà chúng ta ngày càng mong đợi từ phần mềm chúng ta sử dụng ngày nay?





Là một kỹ sư phần mềm trong hơn 20 năm qua, tôi đã chứng kiến nhiều hệ thống được phát triển từ mọi cấp độ của hệ thống. Trình xử lý ngắt trong những ngày DOS cho tới hoạt ảnh dựa trên JavaScript và thậm chí tạo báo cáo không cần mã. Một vài tuần trước, tôi thậm chí đã dùng ChatGPT-4 để tạo một số mã Python dựa trên một số mô tả mà tôi đã cung cấp cho những gì tôi muốn! Nhưng đó là một câu chuyện cho một ngày khác.





Trong bài viết này, chúng ta sẽ nói về thiết kế hệ thống, cách nó trở thành một phần quan trọng trong thực tiễn software engineering hiện đại và cách nó trở thành một trong những lĩnh vực chính mà các software engineer vẫn có thể mang lại giá trị trong ngắn hạn và trung hạn.





Tầm quan trọng của thiết kế hệ thống (Systems design)





Tầm quan trọng của Thiết kế hệ thống (System Design)
Tầm quan trọng của Thiết kế hệ thống (System Design)




Ngày xưa, tôi là kỹ sư phần mềm trong một công ty gặp vấn đề trong việc xử lý gánh nặng thành công mà chính họ đã mang lại. Tôi sẽ gọi công ty này là Friendster. Khi tôi gia nhập công ty, dự án mà tôi được giao đã bị trễ và có nhiều lỗi liên quan đến quản lý bộ nhớ. Dịch vụ cốt lõi của họ (vâng, nó là một microservice trước khi chúng tôi gọi nó vào năm 2007) được viết bằng C++ nhưng bị rò rỉ bộ nhớ, mất quá nhiều thời gian để xử lý các yêu cầu và được thiết kế để lưu vào bộ đệm và cung cấp dữ liệu trong bộ nhớ của chính nó. Nó cần phải không trạng thái (stateless) nhưng cuối cùng lại trở thành trạng thái (stateful).





Một vài tuần sau khi bắt đầu dự án, tôi đã xin lãnh đạo kỹ thuật cấp cao bỏ việc lặp lại dịch vụ này và thay vào đó hãy viết một cái gì đó từ đầu đáp ứng các yêu cầu; nó sẽ là một sự thay thế của việc triển khai hiện có. Chúng tôi đã phải vượt qua thời hạn vì dịch vụ chỉ có thể xử lý thêm vài tháng tăng trưởng nữa trước khi không thể xử lý kích thước của bộ đệm theo cách cũ nữa.





Khởi động lại dịch vụ mất nhiều thời gian hơn thời gian nó có thể duy trì cho đến khi rò rỉ bộ nhớ làm nó ngừng hoạt động. Đây là khoảnh khắc “đặt cược sự nghiệp của tôi”. Chúng tôi phải làm cho nó hoạt động.





Trong thiết kế hệ thống. Điều đầu tiên chúng tôi làm là liệt kê những yêu cầu mà hệ thống phải đáp ứng, hợp đồng giữa các dịch vụ phụ thuộc (mã PHP frontend) và dịch vụ cốt lõi này và kế hoạch về cách chúng tôi sẽ đáp ứng ba yêu cầu phi kỹ thuật chính : hiệu suất (performance), hiệu quả (efficiency) và khả năng phục hồi (resilience).





Thiết kế hệ thống liên quan đến việc hiểu các ràng buộc theo đó hệ thống phải thực hiện chức năng của nó, các chức năng được yêu cầu là gì và những thuộc tính nào của hệ thống là quan trọng để giữ liên quan đến tất cả các thuộc tính khác. Khi bạn đã xác định những điều này, bạn có thể bắt đầu thiết kế một hệ thống đáp ứng các yêu cầu và lập kế hoạch phân phối giải pháp một cách có hệ thống.





Các thành phần của thiết kế hệ thống





Khi chúng ta nói về thiết kế hệ thống, thường có một số thành phần đòi hỏi điều này:





  • Kiến trúc – giải pháp tổng thể trông như thế nào? Liệu nó liên quan đến nhiều hệ thống con? Có các thành phần riêng lẻ tạo nên một tổng thể? Làm thế nào để chúng tương tác, và làm thế nào để chúng liên quan đến nhau?
  • Cấu trúc liên kết (Topology) – Có phân lớp cho giải pháp không? Nếu đây là một hệ thống phân tán, thì các dịch vụ thành phần được đặt ở đâu về mặt vật lý hoặc logic trong mối quan hệ với nhau?
  • Thiết kế cấp thấp — Bạn đã xác định những giao diện nào thông qua đó các phần khác nhau của hệ thống tương tác với nhau? Có thuật toán cụ thể nào bạn đang sử dụng để giải quyết các khía cạnh chính của giải pháp (hiệu suất, hiệu quả, thông lượng, khả năng phục hồi, v.v.) không?




Nó giúp hiểu những điều đầu tiên như: hệ thống có độc lập không (tức là sẽ không có quyền truy cập vào các tài nguyên bên ngoài) hay nó được phân tán? Nó sẽ có giao diện người dùng hay nó sẽ không tương tác (ví dụ: nó có tạo báo cáo được in ra hay nó sẽ yêu cầu đầu vào của con người hoặc hệ thống khác trong quá trình hoạt động)? Nó có cần xử lý nhiều lưu lượng truy cập không? Nó có nghĩa là chỉ được sử dụng bởi mười người tại bất kỳ thời điểm nào hay 10 triệu người dùng sẽ sử dụng nó tại bất kỳ thời điểm nào?





Khi bạn đã có câu trả lời cho một số câu hỏi này, việc đưa ra quyết định thông qua các nguyên tắc thiết kế hệ thống sẽ dễ dàng hơn.





Các nguyên tắc thiết kế hệ thống





Các nguyên tắc của thiết kế hệ thống (System Design Principles)
Các nguyên tắc của thiết kế hệ thống (System Design Principles)




Một số nguyên tắc chính để thiết kế hệ thống phần mềm trong thời đại hiện đại này đã không xuất hiện cho đến khi hệ thống cần mở rộng quy mô — từ hệ thống một người dùng thành hệ thống có thể xử lý hàng nghìn, thậm chí hàng triệu người dùng cùng một lúc. Dưới đây là một số chúng tôi sẽ đề cập trong bài viết này:





  • Khả năng mở rộng (Scalability)
  • Độ tin cậy (Reliability)
  • Khả năng bảo trì (Maintainability)
  • Khả dụng (Availability)
  • Bảo mật (Security)




Scalability (Khả năng mở rộng)





Một hệ thống có khả năng mở rộng khi nó có thể được triển khai để xử lý sự tăng trưởng về tải với sự tăng trưởng tương ứng về tài nguyên. Hệ số mở rộng của một hệ thống được định nghĩa là sự tăng trưởng về lượng tài nguyên cần thiết để phục vụ cho sự tăng trưởng về tải trên hệ thống. Chúng tôi gặp hai trường hợp mở rộng điển hình với các hệ thống phần mềm: mở rộng chiều dọc và mở rộng chiều ngang.





Mở rộng chiều dọc đề cập đến việc cung cấp thêm khoảng không hoặc tài nguyên máy đơn cho hệ thống phần mềm để xử lý sự gia tăng về yêu cầu. Hãy xem xét trường hợp của một thiết bị lưu trữ gắn mạng. Bạn cung cấp càng nhiều dung lượng lưu trữ thông qua thiết bị, thì thiết bị có thể lưu trữ càng nhiều dữ liệu. Nếu bạn cần nó xử lý nhiều kết nối đồng thời hơn và Hoạt động I/O (IOP), thông thường bạn cần bổ sung thêm sức mạnh tính toán và giao diện mạng để xử lý lượng tải tăng lên.





Mở rộng theo chiều ngang đề cập đến việc sao chép một hệ thống hoặc nhiều máy bằng các bản sao của phần mềm để xử lý sự tăng trưởng các yêu cầu. Hãy xem xét trường hợp máy chủ nội dung web tĩnh ẩn sau bộ cân bằng tải. Thêm nhiều máy chủ hơn cho phép nhiều máy khách hơn kết nối và tải xuống nội dung từ các máy chủ web và khi tải đã giảm, số lượng máy chủ web có thể được thu nhỏ xuống kích thước phù hợp với nhu cầu hiện tại.





Một số hệ thống có thể xử lý mở rộng lai hoặc chéo. Ví dụ: một số kiến trúc cơ sở dữ liệu phân tán cho phép tách các nút tính toán và lưu trữ để khối lượng công việc tính toán nặng có thể sử dụng các nút có nhiều tài nguyên tính toán hơn. Ngược lại, khối lượng công việc nặng của IOP có thể chạy trên các nút lưu trữ + tính toán. Ví dụ: các ứng dụng xử lý luồng có thể tách các khối lượng công việc yêu cầu nhiều bộ nhớ và điện toán hơn (ví dụ: khối lượng công việc tìm nguồn cung ứng sự kiện hoặc phân tích) và mở rộng những khối lượng công việc đó một cách thích hợp và độc lập khỏi khối lượng công việc nặng của IOP (ví dụ: nén và lưu trữ).





Reliability (Độ tin cậy)





Một hệ thống đáng tin cậy khi nó có thể chịu được lỗi một phần và phục hồi mà không làm giảm chất lượng dịch vụ nghiêm trọng. Một phần của độ tin cậy của hệ thống bao gồm khả năng dự đoán các hoạt động của nó về độ trễ, thông lượng và tuân thủ phạm vi hoạt động đã thỏa thuận.





Các phương pháp thông thường để đảm bảo độ tin cậy của hệ thống bao gồm:





  • Thiết lập dự phòng hệ thống để hỗ trợ chuyển đổi dự phòng minh bạch hoặc gián đoạn tối thiểu.
  • Xây dựng khả năng chịu lỗi trong trường hợp lỗi nội bộ hoặc lỗi do đầu vào gây ra.
  • Xác định rõ ràng các hợp đồng và mục tiêu về độ trễ, thông lượng và tính khả dụng.
  • Thiết lập đủ công suất dự phòng để đáp ứng sự gia tăng tải đột biến và tự nhiên.
  • Các biện pháp bảo vệ chất lượng dịch vụ để thực thi giới hạn tỷ lệ và cách ly khách hàng/hoạt động.
  • Thực hiện hạ cấp dịch vụ nhẹ nhàng trong các tình huống quá tải hoặc lỗi nghiêm trọng.




Điều quan trọng cần nhớ để tạo ra các hệ thống đáng tin cậy là xử lý các lỗi tiềm ẩn theo cách được xác định rõ ràng mà các hệ thống phụ thuộc có thể phản ứng. Điều này nghĩa là nếu có những yếu tố đầu vào có thể khiến hệ thống khả dụng cho tất cả mọi người, thì đó không phải là một hệ thống đáng tin cậy. Tương tự, nếu hệ thống phụ thuộc vào một hệ thống khác có thể không đáng tin cậy, thì nó sẽ xử lý sự không đáng tin cậy đó bằng các chiến lược để đảm bảo độ tin cậy.





Khả năng bảo trì (Maintainability)





Một hệ thống có thể bảo trì được khi được thay đổi với nỗ lực tương xứng và được triển khai với sự gián đoạn tối thiểu của người dùng. Điều này đòi hỏi phải triển khai hệ thống theo cách giả định rằng các yêu cầu sẽ thay đổi và hệ thống đủ linh hoạt để xử lý những thay đổi có thể thấy trước về hướng. Điều đó cũng có nghĩa là đảm bảo rằng mã có thể đọc được để nhóm người bảo trì tiếp theo (có thể là cùng một nhóm nhưng nhìn nó bằng con mắt mới trong tương lai) có thể bảo trì phần mềm và phát triển phần mềm để đáp ứng nhu cầu trong tương lai.





Không ai muốn bị mắc kẹt trong việc duy trì phần mềm cứng nhắc, khó thay đổi, không được tổ chức tốt, tài liệu kém, thiết kế kém, chưa được kiểm tra và lắp ráp lộn xộn.





Đảm bảo chất lượng mã cao là một phần của kỹ thuật xuất sắc phản ánh tính chuyên nghiệp và tay nghề xuất sắc. Đây không chỉ là một việc nên làm mà còn được biết là cho phép các nhóm kỹ thuật có chức năng cao và hiệu suất cao cung cấp phần mềm có thể thay đổi và mở rộng để mang lại giá trị một cách nhất quán.





Availability (Tính khả dụng)





Nếu dịch vụ của bạn không khả dụng, nó có thể không tồn tại.





Thiết kế hệ thống nên giải quyết cách hệ thống luôn sẵn sàng để duy trì sự liên quan đến khách hàng và người dùng hệ thống. Điều này có nghĩa là:





  • Giới thiệu các dự phòng để xử lý các lỗi hệ thống cơ bản.
  • Có các kịch bản sao lưu và khôi phục cũng như hướng dẫn vận hành để khôi phục hệ thống khỏi các sự cố nghiêm trọng.
  • Loại bỏ càng nhiều điểm lỗi đơn lẻ khỏi hệ thống.
  • Cùng với khả năng mở rộng theo chiều ngang, hãy có các bản sao theo khu vực và thiết lập mạng phân phối nội dung (nếu thích hợp) để cung cấp dữ liệu của bạn.
  • Giám sát tính khả dụng của hệ thống từ quan điểm của khách hàng để hiểu rõ hơn cách hệ thống của bạn đang phục vụ khách hàng.




Tôi đã sớm học được rằng một hệ thống không ổn định và không khả dụng đôi khi có thể là nguyên nhân lớn nhất khiến khách hàng của bạn mất lòng tin. Một khi bạn đã đánh mất lòng tin của khách hàng thì sẽ rất khó lấy lại được.





Security (Bảo mật)





Thiết kế hệ thống nên coi bảo mật là một khía cạnh quan trọng, đặc biệt là trong thời đại của các hệ thống kết nối internet, nơi các mối đe dọa và lỗ hổng bảo mật có thể gây hại thực sự cho khách hàng của chúng ta và người dùng hệ thống. Mục tiêu của việc xây dựng phần mềm an toàn không phải là để đạt được sự hoàn hảo mà là để hiểu những rủi ro liên quan đến vi phạm và tấn công. Có một mô hình đe dọa bảo mật thích hợp và một cách tiếp cận có hệ thống để hiểu rủi ro nằm ở đâu và loại mối đe dọa nào đáng để ưu tiên và thiết kế các biện pháp giảm thiểu là bước khởi đầu của thực tiễn kỹ thuật và thiết kế an toàn.





Ngày nay, bảo mật không còn là tùy chọn nữa khi các hệ thống phần mềm trở thành một phần của các dịch vụ quan trọng đối với nhiều bộ phận của xã hội hiện đại. Việc coi trọng vấn đề bảo mật trong các hệ thống mà chúng ta thiết kế ngay từ đầu sẽ giúp chúng ta tiến gần hơn đến khả năng tin cậy tốt hơn vào phần mềm mà chúng tôi xây dựng và triển khai để đáp ứng nhu cầu của người dùng. Giành được lòng tin của khách hàng đã đủ khó và chỉ cần vi phạm một lần là mất đi phần lớn niềm tin.





Cách hình mẫu thiết kế hệ thống hiện đại





Với các khía cạnh trên, một số hình mẫu cho các hệ thống phân tán hiện đại đã xuất hiện để giải quyết một số khía cạnh này theo những cách khác nhau. Hãy khám phá một số mẫu thiết kế phổ biến hơn mà chúng ta thấy ngày nay liên quan đến năm khía cạnh của thiết kế hệ thống.





Microservices (Vi dịch vụ)





Microservices - Hình mẫu System Design hiện đại
Microservices – Hình mẫu System Design hiện đại




Với sự gia tăng của các hệ thống phân tán tập trung vào việc xây dựng độ tin cậy và quy mô thông qua dự phòng, hiệu quả và hiệu suất thông qua mở rộng theo chiều ngang và khả năng phục hồi thông qua việc tách các bộ phận của hệ thống thành các dịch vụ hoạt động độc lập, thuật ngữ “microservice” đã trở nên phổ biến nhờ đạt được những điều sau:





  • Ràng buộc việc phát triển, triển khai, vận hành và bảo trì các dịch vụ độc lập với các nhóm sở hữu các dịch vụ này trong một hoạt động kinh doanh lớn hơn. Chúng ta có thể làm điều này bằng cách phục vụ khách hàng bên ngoài trực tiếp hoặc gián tiếp thông qua khách hàng nội bộ thông qua API.
  • Cho phép microservice mở rộng quy mô độc lập theo nhu cầu.
  • Việc cung cấp dịch vụ thông qua một hợp đồng được xác định rõ ràng cho phép việc triển khai phát triển để duy trì dưới dạng một dịch vụ độc lập hoặc một hệ thống dịch vụ.




Nhìn qua các khía cạnh của chúng ta, microservice có các thuộc tính hấp dẫn, khiến nó trở thành một mô hình tốt để tuân theo nếu nó áp dụng cho trường hợp sử dụng:





  • Khả năng mở rộng: Các vi dịch vụ phi trạng thái (stateless microservices) thường được thiết kế để có thể mở rộng theo chiều ngang và cũng có thể hưởng lợi từ việc mở rộng theo chiều dọc. Trong trường hợp các microservice được triển khai trong môi trường điều phối được đóng gói (ví dụ: cụm Kubernetes), các dịch vụ này thậm chí có thể chạy trên cùng một nút mang lại khả năng sử dụng tốt hơn phần cứng hiện có và mở rộng quy mô theo nhu cầu với dung lượng khả dụng. Một nhược điểm là sự phức tạp khi triển khai khi một microservice phát triển về quy mô và mức độ quan trọng trong biểu đồ microservice.
  • Độ tin cậy: Các vi dịch vụ phi trạng thái thường được lưu trữ phía sau bộ cân bằng tải và được phân phối theo địa lý để tránh sự cố mất điện trong khu vực chiếm toàn bộ dung lượng của hệ thống. Một nhược điểm của việc xây dựng độ tin cậy với các vi dịch vụ phi trạng thái là hệ thống lưu trữ thường sẽ cần phải đáng tin cậy bằng hoặc hơn so với việc triển khai/thực thi vi dịch vụ. Khi đó, các vi dịch vụ có trạng thái phải chịu tác động tồi tệ nhất của cả hai phương pháp, trong đó chi phí cho độ tin cậy thường ở dạng cung cấp quá mức để xử lý các sự cố ngừng hoạt động tiềm ẩn.
  • Khả năng bảo trì: Các vi dịch vụ triển khai hợp đồng ổn định và được xác định rõ ràng được cung cấp thông qua API cho phép khách hàng lập trình dựa trên API đó và quá trình triển khai phát triển độc lập. Tuy nhiên, việc điều phối các thay đổi đối với API liên quan đến việc di chuyển ứng dụng khách và phối hợp giữa các nhóm có thể tốn kém, dẫn đến một giai đoạn vi dịch vụ có nhiều phiên bản được hỗ trợ tích cực cho đến khi ứng dụng khách cuối cùng di chuyển từ triển khai cũ hơn. Điều này chỉ trở nên tồi tệ hơn khi nhiều khách hàng bắt đầu tương tác với microservice.
  • Tính khả dụng: Microservices thường dựa vào môi trường triển khai và cơ sở hạ tầng bên ngoài để đáp ứng các yêu cầu về tính khả dụng của máy khách. Nhược điểm của điều này là sự phụ thuộc vào cơ sở hạ tầng cụ thể mà microservice được triển khai để cung cấp giải pháp có tính sẵn sàng cao. Các hệ thống như lưới dịch vụ và bộ cân bằng tải phần mềm trở thành những phần quan trọng của cơ sở hạ tầng không còn được kiểm soát bởi quá trình triển khai. Đây có thể là một điều tốt nhưng cũng có thể là một nguồn bảo trì liên tục vì các hệ thống này cũng có chu kỳ cập nhật và chi phí vận hành.
  • Bảo mật: Xác thực, Ủy quyền, Quản lý danh tính và Quản lý thông tin xác thực có thể được ủy quyền cho phần mềm trung gian hoặc thông qua các cơ chế bên ngoài (ví dụ: danh tính khối lượng công việc trong Kubernetes), trong đó việc triển khai microservice có thể tập trung vào việc tích hợp logic nghiệp vụ có liên quan. Nhược điểm, cũng như tính khả dụng, là các phần bên ngoài này của giải pháp trở thành các phần quan trọng của cơ sở hạ tầng mang lại chi phí vận hành của chính chúng khi triển khai vi dịch vụ.




Microservices là một cách tuyệt vời để chia nhỏ một ứng dụng lớn, nơi có thể xác định các phân vùng logic yêu cầu các miền độ tin cậy và tỷ lệ mở rộng của riêng chúng. Tuy nhiên, khi bắt đầu từ đầu, việc thiết kế các vi dịch vụ ngay từ đầu sẽ kém lý tưởng hơn vì nguy cơ chia nhỏ các dịch vụ thành các phần quá nhỏ. Chi phí liên lạc giữa các vi dịch vụ — thường là các yêu cầu HTTP hoặc gRPC — là đáng kể và chỉ phát sinh nếu cần thiết. Một cách tốt để xác định xem chức năng có phù hợp với một dịch vụ hay không bằng cách làm theo một phương pháp như Thiết kế hướng miền (Domain driven design) hoặc Phân rã chức năng (Functional decomposition).





Serverless (Không máy chủ)





Serverless - Hình mẫu System Design hiện đại
Serverless – Hình mẫu System Design hiện đại




Giống như trong các giải pháp dựa trên vi dịch vụ, việc sử dụng các triển khai serverless sẽ ủy quyền thêm các phần chính của chức năng phục vụ các yêu cầu tới cơ sở hạ tầng bên dưới. Nếu trong Microservices, dịch vụ được phục vụ bởi một quy trình liên tục, thì các giải pháp Serverless thường chỉ triển khai một điểm đầu vào để xử lý yêu cầu tới một điểm cuối (thường là URI qua HTTP hoặc gRPC). Trong triển khai Serverless, không có máy chủ thực tế nào được định cấu hình mà thay vào đó, môi trường triển khai sẽ tạo ra các tài nguyên cần thiết để xử lý các yêu cầu khi chúng đến. Đôi khi, các tài nguyên đó duy trì một thời gian để khấu hao chi phí đưa chúng lên, nhưng điều đó có nghĩa là là một chi tiết thực hiện.





Hãy xem qua các khía cạnh của thiết kế hệ thống để xem các giải pháp Serverless sắp xếp như thế nào:





  • Khả năng mở rộng: Các giải pháp serverless có khả năng mở rộng theo chiều ngang như microservice, nếu không muốn nói là hơn thế vì chúng được thiết kế có kích thước phù hợp theo yêu cầu. Nhược điểm của phương pháp này là cần có nhiều quyền kiểm soát hơn và ủy quyền đầy đủ chức năng mở rộng quy mô cho cơ sở hạ tầng Serverless bên dưới.
  • Độ tin cậy: Độ tin cậy của Serverless phụ thuộc vào khả năng mở rộng theo chiều ngang và định tuyến lưu lượng mạng. Điều này có nhược điểm tương tự như giải pháp Microservices.
  • Khả năng bảo trì: Việc triển khai serverless dễ bảo trì hơn vi dịch vụ do tập trung vào logic nghiệp vụ để xử lý các yêu cầu với bản soạn sẵn tối thiểu. Điều này có cùng vấn đề với quá trình phát triển API mà microservice gặp phải.
  • Tính khả dụng: Các triển khai Serverless có sẵn như môi trường mà chúng được triển khai. Điều này có cùng các vấn đề, với cơ sở hạ tầng cơ bản trở nên quan trọng hơn bản thân giải pháp.
  • Bảo mật: Việc triển khai Serverless hoàn toàn phụ thuộc vào cấu hình bảo mật của cơ sở hạ tầng bên dưới. Điều này có cùng một vấn đề, với cơ sở hạ tầng cơ bản trở nên quan trọng hơn so với chính giải pháp thực tế.




Các giải pháp không có máy chủ, hay Chức năng dưới dạng Dịch vụ, là một cách rất hấp dẫn để tạo nguyên mẫu và thậm chí triển khai các giải pháp cấp sản xuất bằng cách tập trung vào giá trị và logic kinh doanh, đồng thời để cơ sở hạ tầng cơ bản xử lý khả năng mở rộng, độ tin cậy và tính khả dụng của dịch vụ. Đó là một điểm khởi đầu điển hình để có được một giải pháp với gánh nặng vận hành tối thiểu và đối với hầu hết các nguyên mẫu, đó là một cách tuyệt vời để chứng minh giả thuyết của chúng tôi. Đây cũng là một trải nghiệm điển hình khi một khi các giải pháp này đạt đến giới hạn mở rộng quy mô, chi phí liên quan đến việc vận hành các giải pháp này sẽ trở nên đủ cao. Chúng được biến thành các triển khai vi dịch vụ tối ưu hơn được điều chỉnh theo quy mô cần thiết.





Event-driven (Hướng sự kiện)





Thiết kế hệ thống hướng sự kiện - Hình mẫu System Design hiện đại
Thiết kế hệ thống hướng sự kiện – Hình mẫu System Design hiện đại




Tuy nhiên, có một số lĩnh vực sự cố nơi mà việc xử lý giao dịch trực tuyến không được yêu cầu và các triển khai vi dịch vụ và không có máy chủ không hoàn toàn phù hợp với hóa đơn. Hãy xem xét các trường hợp xử lý giao dịch có thể được thực hiện trong nền hoặc khi có sẵn tài nguyên. Một trường hợp khác dành cho các hoạt động xử lý nền trong đó kết quả không nhất thiết phải có tính tương tác.





Các hệ thống hướng sự kiện tuân theo mô hình có một nguồn sự kiện (event source) và các bồn sự kiện (event sinks) – nơi các sự kiện (tin nhắn) đến từ đó và được gửi tương ứng. Quá trình xử lý lần lượt xảy ra từ người đăng ký và nhà xuất bản đến các source và sink này. Một ví dụ về hệ thống hướng sự kiện là một chatbot có thể tham gia vào nhiều thảo luận (event source và sinks) và xử lý tin nhắn khi chúng đến.





Các hệ thống hướng sự kiện phân tán có thể có nhiều trình xử lý tin nhắn đồng thời đang chờ trên cùng một nguồn, có khả năng xuất bản nhiều sink đóng vai trò là nguồn cho các trình xử lý tin nhắn khác. Mô hình kết nối các bộ xử lý với nhau thông qua source và sink được gọi là quy trình sự kiện (event pipeline). Thông thường, có một triển khai duy nhất cho các sink và source cung cấp giao diện hàng đợi tin nhắn và mở rộng theo nhu cầu về các tin nhắn đi qua hệ thống. Nhiều hệ thống quản lý hàng đợi phân tán cũng có thể hưởng lợi từ việc mở rộng quy mô theo đường chéo một cách hiệu quả, như Apache Kafka, RabbitMQ, v.v.





Hãy xem xét các hệ thống hướng sự kiện phân tán thông qua năm khía cạnh:





  • Khả năng mở rộng: Cả triển khai trung gian tin nhắn/sự kiện và trình xử lý thông báo đều có thể mở rộng độc lập. Một số nhược điểm xuất hiện khi có quá nhiều tin nhắn/sự kiện đang được xử lý và nhu cầu về trung gian sự kiện tăng vượt xa khả năng có sẵn trong hệ thống.
  • Độ tin cậy: Việc triển khai trình môi giới thông báo tốt mang lại mức độ tin cậy cao và bạn không nên tạo triển khai trình môi giới thông báo của riêng mình. Nhược điểm là sự phụ thuộc vào giải pháp đáp ứng nhu cầu về độ tin cậy của giải pháp (ví dụ: xử lý các giao dịch tài chính rất khác so với xử lý định tuyến nhắn tin tức thì trong phòng trò chuyện).
  • Khả năng duy trì: Nếu bạn sử dụng định dạng trao đổi tin nhắn linh hoạt như Bộ đệm giao thức, thì việc phát triển các bộ viết và đọc tin nhắn trong khi sử dụng cùng một ngôn ngữ mô tả dữ liệu là điều hợp lý. Điều này vẫn yêu cầu sự phối hợp, nhưng không khó bằng việc phát triển các hợp đồng API trên các hệ thống xử lý giao dịch trực tiếp (như trong các dịch vụ vi mô và triển khai không có máy chủ).
  • Tính khả dụng: Vì các tin nhắn thường được lưu trữ trong phương tiện lâu bền nên các hệ thống hướng sự kiện thường dễ dàng cung cấp hơn, đặc biệt vì chúng thường là các ứng dụng không tương tác. Chi phí khả dụng có thể đến từ các tin nhắn cũ và độ trễ xử lý hàng đợi không giới hạn.
  • Bảo mật: Các hệ thống hướng sự kiện phải quản lý tính khả dụng của dữ liệu độc lập với danh tính và thông tin đăng nhập. Việc đảm bảo rằng chỉ một số dịch vụ hoặc bộ xử lý tin nhắn nhất định mới có thể truy cập vào hàng đợi hoặc nhật ký tin nhắn cụ thể trở thành công việc toàn thời gian khi dữ liệu đa dạng hơn được chuyển thẳng qua hệ thống.




Kết





Software engineering hiện đại đòi hỏi phải thiết kế các hệ thống có thể mở rộng, đáng tin cậy, có thể bảo trì, khả dụng và an toàn. Việc thiết kế các hệ thống phân tán đòi hỏi sự nghiêm ngặt đáng kể vì thực tế phức tạp của hệ thống hiện đại ngày càng tăng cùng với nhu cầu của xã hội về các dịch vụ phần mềm tốt hơn. Chúng ta đã xem xét ba hình mẫu thiết kế hiện đại cho các hệ thống phân tán và làm việc thông qua năm khía cạnh của các hệ thống được thiết kế tốt.





Là kỹ sư phần mềm, chúng ta chịu trách nhiệm thiết kế các hệ thống giải quyết các mối quan tâm chính của hệ thống phân tán trong thời hiện đại.





Nguồn: Dean Michael Berris