Trong hướng dẫn này, bạn sẽ tìm hiểu microservices Java là gì, cách thiết kế và tạo chúng. Nó cũng bao gồm các câu hỏi về thư viện microservice Java và tính khả thi của việc sử dụng microservice. Dịch và điều chỉnh các vi dịch vụ Java: Hướng dẫn thực hành .
Vi dịch vụ Java: Cơ bản
Để hiểu microservice, trước tiên bạn phải xác định chúng không phải là gì. Nó không phải là “monolith” - Java monolith: nó là gì và ưu điểm hay nhược điểm của nó là gì?Một khối Java là gì?
Hãy tưởng tượng bạn làm việc cho một ngân hàng hoặc một công ty khởi nghiệp về công nghệ tài chính. Bạn cung cấp cho người dùng một ứng dụng di động mà họ có thể sử dụng để mở tài khoản ngân hàng mới. Trong mã Java, điều này sẽ dẫn đến sự hiện diện của một lớp trình điều khiển. Đơn giản hóa, nó trông như thế này:@Controller
class BankController {
@PostMapping("/users/register")
public void register(RegistrationForm form) {
validate(form);
riskCheck(form);
openBankAccount(form);
// etc..
}
}
Bạn cần bộ điều khiển để:
- Đã xác nhận mẫu đăng ký.
- Đã kiểm tra rủi ro về địa chỉ của người dùng để quyết định có cung cấp tài khoản ngân hàng cho anh ta hay không.
- Đã mở tài khoản ngân hàng.
BankController
sẽ được đóng gói cùng với các nguồn còn lại của bạn thành tệp Bank.jar hoặc Bank.war để triển khai - đây là một khối nguyên khối cũ tốt chứa tất cả mã cần thiết để chạy ngân hàng của bạn. Theo ước tính sơ bộ, kích thước ban đầu của tệp .jar (hoặc .war) sẽ nằm trong khoảng từ 1 đến 100 MB. Bây giờ bạn có thể chỉ cần chạy tệp .jar trên máy chủ của mình... và đó là tất cả những gì bạn cần làm để triển khai ứng dụng Java của mình. Hình ảnh, hình chữ nhật trên cùng bên trái: triển khai ngân hàng mono(lithic) java -jarbank.jar (cp .war/.ear vào máy chủ ứng dụng). Hình chữ nhật bên phải: mở trình duyệt.
Vấn đề với nguyên khối Java là gì?
Vốn dĩ không có gì sai với các khối nguyên khối của Java. Tuy nhiên, kinh nghiệm đã chỉ ra rằng nếu trong dự án của bạn:- Có rất nhiều lập trình viên/nhóm/tư vấn viên đang làm việc...
- ...trên cùng một khối nguyên khối dưới áp lực từ khách hàng với những yêu cầu rất mơ hồ...
- trong vòng vài năm nữa...
Làm cách nào để giảm kích thước của một khối Java?
Một câu hỏi tự nhiên được đặt ra: làm thế nào để làm cho tảng đá nguyên khối nhỏ hơn? Hiện tại, ngân hàng.jar của bạn đang chạy trên một JVM, một quy trình trên một máy chủ. Không nhiều không ít. Và ngay bây giờ một ý nghĩ hợp lý có thể xuất hiện trong đầu bạn: “Nhưng dịch vụ xác minh rủi ro có thể được các bộ phận khác trong công ty của tôi sử dụng! Nó không liên quan trực tiếp đến ứng dụng ngân hàng nguyên khối của tôi! Có lẽ nó nên được cắt ra khỏi nguyên khối và triển khai như một sản phẩm riêng biệt? Nghĩa là, về mặt kỹ thuật, chạy nó như một quy trình Java riêng biệt.”Dịch vụ vi mô Java là gì?
Trong thực tế, cụm từ này có nghĩa là bây giờ lệnh gọi phương thứcriskCheck()
sẽ không được thực hiện từ BankController: phương thức này hoặc thành phần Bean cùng với tất cả các lớp phụ trợ của nó sẽ được chuyển sang dự án Maven hoặc Gradle của chính nó. Nó cũng sẽ được triển khai và đặt dưới sự kiểm soát phiên bản độc lập với khối ngân hàng nguyên khối. Tuy nhiên, toàn bộ quá trình trích xuất này không biến mô-đun RiskCheck mới của bạn thành một vi dịch vụ thực sự vì định nghĩa về vi dịch vụ có thể được giải thích. Điều này dẫn đến các cuộc thảo luận thường xuyên trong các nhóm và công ty.
- Có phải 5-7 lớp trong một dự án vi mô hay không?
- 100 hay 1000 lớp... vẫn còn vi mô?
- Microservice có liên quan chung đến số lượng lớp học hay không?
- Hãy gọi tất cả các dịch vụ được triển khai riêng biệt là microservice, bất kể quy mô hoặc ranh giới miền của chúng.
- Hãy suy nghĩ về cách sắp xếp liên lạc giữa các dịch vụ. Các vi dịch vụ của chúng ta cần có cách để giao tiếp với nhau.
Làm cách nào để thiết lập liên lạc giữa các dịch vụ vi mô Java?
Nói chung và nói chung, có hai lựa chọn - giao tiếp đồng bộ và không đồng bộ.Giao tiếp đồng bộ: (HTTP)/REST
Thông thường, giao tiếp được đồng bộ hóa giữa các vi dịch vụ diễn ra thông qua các dịch vụ giống như HTTP và REST trả về XML hoặc JSON. Tất nhiên, có thể có các tùy chọn khác - ít nhất hãy lấy Bộ đệm giao thức của Google . Nếu bạn cần phản hồi ngay lập tức, tốt hơn nên sử dụng giao tiếp REST. Trong ví dụ của chúng tôi, đây chính xác là những gì cần phải làm vì cần phải xác minh rủi ro trước khi mở tài khoản. Nếu không có kiểm tra rủi ro thì không có tài khoản. Chúng ta sẽ thảo luận về các công cụ bên dưới, trong phần “ Thư viện nào tốt nhất cho lệnh gọi Java REST đồng bộ ”.Nhắn tin - Giao tiếp không đồng bộ
Giao tiếp microservice không đồng bộ thường được thực hiện bằng cách trao đổi tin nhắn với triển khai JMS và/hoặc sử dụng giao thức như AMQP . Chúng tôi viết “thường” ở đây vì một lý do: giả sử không thể đánh giá thấp số lượng tích hợp email/SMTP. Hãy sử dụng nó khi bạn không cần phản hồi ngay lập tức. Ví dụ: người dùng nhấp vào nút “mua ngay” và đến lượt bạn, bạn muốn tạo hóa đơn. Quá trình này chắc chắn không nên xảy ra trong chu kỳ phản hồi yêu cầu mua hàng của người dùng. Dưới đây chúng tôi sẽ mô tả những công cụ nào là tốt nhất cho việc nhắn tin Java không đồng bộ .Ví dụ: Lệnh gọi API REST trong Java
Giả sử chúng ta chọn giao tiếp microservice đồng bộ. Trong trường hợp này, mã Java của chúng tôi (mã chúng tôi đã trình bày ở trên) ở cấp độ thấp sẽ trông giống như thế này. (ở mức độ thấp ở đây, chúng tôi muốn nói đến thực tế là đối với giao tiếp vi dịch vụ, các thư viện máy khách thường được tạo để giúp bạn tránh xa các lệnh gọi HTTP thực tế).@Controller
class BankController {
@Autowired
private HttpClient httpClient;
@PostMapping("/users/register")
public void register(RegistrationForm form) {
validate(form);
httpClient.send(riskRequest, responseHandler());
setupAccount(form);
// etc..
}
}
Dựa trên mã, có thể thấy rõ rằng bây giờ chúng ta cần triển khai hai dịch vụ Java (vi mô) là Bank và RiskCheck. Kết quả là chúng ta sẽ có hai tiến trình JVM đang chạy. Đó là tất cả những gì bạn cần để phát triển một dự án vi dịch vụ Java: chỉ cần xây dựng và triển khai các phần nhỏ hơn (tệp .jar hoặc .war) thay vì một khối nguyên khối. Câu trả lời cho câu hỏi vẫn chưa rõ ràng: chúng ta nên cắt nguyên khối thành microservice như thế nào? Những mảnh này nên nhỏ đến mức nào, làm thế nào để xác định kích thước chính xác? Hãy kiểm tra.
Kiến trúc vi dịch vụ Java
Trên thực tế, các công ty phát triển các dự án microservice theo nhiều cách khác nhau. Cách tiếp cận này phụ thuộc vào việc bạn đang cố gắng chuyển đổi một khối nguyên khối hiện có thành một dự án vi dịch vụ hay bắt đầu dự án từ đầu.Từ nguyên khối đến microservice
Một trong những ý tưởng hợp lý nhất là trích xuất các dịch vụ vi mô từ một khối nguyên khối hiện có. Lưu ý rằng tiền tố "micro" ở đây không thực sự có nghĩa là các dịch vụ được trích xuất sẽ thực sự nhỏ; điều này không nhất thiết phải như vậy. Chúng ta hãy nhìn vào nền tảng lý thuyết.Ý tưởng: chia khối thành microservice
Cách tiếp cận microservice có thể được áp dụng cho các dự án cũ. Và đó là lý do tại sao:- Thông thường, những dự án như vậy rất khó duy trì/thay đổi/mở rộng.
- Mọi người, từ nhà phát triển đến quản lý, đều muốn sự đơn giản hóa.
- Bạn có (tương đối) ranh giới tên miền rõ ràng, nghĩa là bạn biết chính xác phần mềm của mình nên làm gì.
- Vì vậy, sẽ hợp lý nếu tách việc xử lý dữ liệu người dùng (như tên, địa chỉ, số điện thoại) thành một microservice riêng “Quản lý tài khoản”.
- Hoặc "Mô-đun kiểm tra rủi ro" đã nói ở trên giúp kiểm tra mức độ rủi ro của người dùng và có thể được sử dụng bởi nhiều dự án khác hoặc thậm chí các bộ phận của công ty.
- Hoặc mô-đun lập hóa đơn gửi hóa đơn ở định dạng PDF hoặc qua thư.
Thực hiện ý tưởng: để người khác thực hiện
Cách tiếp cận được mô tả ở trên trông tuyệt vời trên giấy và các sơ đồ giống UML. Tuy nhiên, mọi thứ không đơn giản như vậy. Việc triển khai thực tế của nó đòi hỏi phải có sự chuẩn bị kỹ thuật nghiêm túc: khoảng cách giữa sự hiểu biết của chúng ta về những gì sẽ tốt khi trích xuất từ một tảng đá nguyên khối và bản thân quá trình trích xuất là rất lớn. Hầu hết các dự án doanh nghiệp đều đạt đến giai đoạn mà các nhà phát triển ngại nâng cấp phiên bản Hibernate 7 năm tuổi lên phiên bản mới hơn. Các thư viện sẽ được cập nhật cùng với nó, nhưng có nguy cơ thực sự phá vỡ thứ gì đó. Vì vậy, những nhà phát triển đó giờ đây phải tìm hiểu mã kế thừa cổ xưa với ranh giới giao dịch cơ sở dữ liệu không rõ ràng và trích xuất các dịch vụ vi mô được xác định rõ ràng? Thông thường, vấn đề này rất phức tạp và không thể “giải quyết” được trên bảng trắng hoặc trong các cuộc họp kiến trúc. Trích lời nhà phát triển Twitter @simon brown: Tôi sẽ nói đi nói lại điều này... nếu mọi người không thể xây dựng nguyên khối một cách chính xác thì microservice sẽ không giúp ích được gì. Simon BrownDự án từ đầu dựa trên kiến trúc microservice
Đối với các dự án Java mới, ba mục được đánh số từ phần trước trông hơi khác một chút:- Bạn bắt đầu với một bảng xếp hạng sạch sẽ, do đó không có “hành lý” nào để duy trì.
- Các nhà phát triển muốn giữ mọi thứ đơn giản trong tương lai.
- Vấn đề: Bạn có một bức tranh mờ nhạt hơn nhiều về ranh giới miền: bạn không biết phần mềm của mình thực sự phải làm gì (gợi ý: linh hoạt ;))
Kiến trúc microservice kỹ thuật
Điểm đầu tiên có vẻ là rõ ràng nhất đối với các nhà phát triển, nhưng cũng có những người cực lực phản đối nó. Hadi Hariri khuyến nghị tái cấu trúc "Trích xuất microservice" trong IntelliJ. Và mặc dù ví dụ sau đây rất đơn giản, nhưng thật không may, việc triển khai được quan sát trong các dự án thực tế lại không đi quá xa so với nó. Trước microservice@Service
class UserService {
public void register(User user) {
String email = user.getEmail();
String username = email.substring(0, email.indexOf("@"));
// ...
}
}
Với microservice Java chuỗi con
@Service
class UserService {
@Autowired
private HttpClient client;
public void register(User user) {
String email = user.getEmail();
//теперь вызываем substring microservice via http
String username = httpClient.send(substringRequest(email), responseHandler());
// ...
}
}
Vì vậy, về cơ bản bạn đang gói một lệnh gọi phương thức Java trong một lệnh gọi HTTP mà không có lý do rõ ràng nào để làm như vậy. Tuy nhiên, một trong những lý do là: thiếu kinh nghiệm và cố gắng áp dụng cách tiếp cận dịch vụ vi mô Java. Khuyến nghị: Đừng làm điều này.
Kiến trúc microservice định hướng quy trình làm việc
Cách tiếp cận phổ biến tiếp theo là chia các dịch vụ vi mô Java thành các mô-đun dựa trên quy trình công việc. Ví dụ thực tế: ở Đức, khi bạn đến gặp bác sĩ (công), ông ấy phải ghi lại chuyến thăm của bạn vào hệ thống CRM y tế của mình. Để nhận thanh toán từ bảo hiểm, anh ta sẽ gửi dữ liệu về việc điều trị của bạn (và việc điều trị cho những bệnh nhân khác) cho người trung gian thông qua XML. Nhà môi giới sẽ xem xét tệp XML này và (được đơn giản hóa):- Sẽ kiểm tra xem có nhận được tệp XML chính xác hay không.
- Nó sẽ kiểm tra tính hợp lý của các quy trình: chẳng hạn, một đứa trẻ một tuổi nhận được ba quy trình làm sạch răng trong một ngày từ bác sĩ phụ khoa trông có vẻ hơi nghi ngờ.
- Sẽ kết hợp XML với một số dữ liệu quan liêu khác.
- Sẽ chuyển tiếp tệp XML đến công ty bảo hiểm để bắt đầu thanh toán.
- Và nó sẽ gửi kết quả đến bác sĩ, cung cấp cho anh ta thông báo “thành công” hoặc “vui lòng gửi lại bản ghi này ngay khi thấy có ý nghĩa”.
- Có cần thiết phải triển khai sáu ứng dụng để xử lý một tệp XML không?
- Những microservice này có thực sự độc lập với nhau không? Chúng có thể được triển khai độc lập với nhau không? Với các phiên bản và sơ đồ API khác nhau?
- Microservice đáng tin cậy sẽ làm gì nếu microservice xác minh không hoạt động? Hệ thống vẫn hoạt động chứ?
- Các vi dịch vụ này có chia sẻ cùng một cơ sở dữ liệu không (chúng chắc chắn cần một số dữ liệu chung trong bảng DB) hay mỗi vi dịch vụ đều có dữ liệu riêng?
- … và nhiều hơn nữa.
- Bạn không chỉ cần triển khai một ứng dụng mà ít nhất là sáu ứng dụng.
- Bạn thậm chí có thể cần triển khai nhiều cơ sở dữ liệu, tùy thuộc vào mức độ bạn muốn đi sâu vào kiến trúc vi dịch vụ.
- Bạn cần đảm bảo rằng mỗi hệ thống đều trực tuyến và hoạt động bình thường.
- Bạn cần đảm bảo rằng các lệnh gọi giữa các vi dịch vụ của bạn thực sự có khả năng linh hoạt (xem Cách làm cho một vi dịch vụ Java có khả năng linh hoạt?).
- Và mọi thứ khác mà thiết lập này ngụ ý - từ cài đặt phát triển cục bộ đến thử nghiệm tích hợp.
- Nếu bạn không phải Netflix (rất có thể bạn không phải Netflix)...
- Trừ khi bạn có kỹ năng làm việc siêu mạnh khi bạn mở môi trường phát triển và nó gọi một con khỉ hỗn loạn đến vứt bỏ cơ sở dữ liệu sản xuất của bạn, cơ sở dữ liệu này có thể dễ dàng khôi phục sau 5 giây.
- hoặc bạn cảm thấy giống như @monzo và sẵn sàng dùng thử 1500 dịch vụ vi mô chỉ vì bạn có thể.
GO TO FULL VERSION