Nói chuyện về cơ chế xử lý lỗi của Dubbo - Live Casino
Trước đây, tôi đã xem qua một số mã nguồn của Dubbo và trong quá trình học tập, tôi đặc biệt chú ý đến những nội dung "nâng cao", như SPI (Service Provider Interface) hay mở rộng tự động, nhưng lại quên đi những phần cốt lõi nhất mà một khung công tác RPC cần có, chẳng hạn như cách thức truyền thông, phương pháp phân mảnh dữ liệu, mạng lưới, và cơ chế xử lý lỗi. Thực tế thì những yếu lịch bóng đá ngoại hạng anh tố này mới là quan trọng nhất để đảm bảo rằng khung công Live Casino tác RPC hoạt động hiệu quả.
Một giao thức truyền thông phù hợp, phương pháp phân mảnh dữ liệu tốt, và cách xử lý lỗi chính xác là những yếu tố quyết định sự thành công của bất kỳ hệ thống RPC nào. Điều này khác với việc thiết kế mở rộng tự động hoặc tăng tính linh hoạt cho mã nguồn – những điều đó chỉ giúp mã dễ đọc hơn và tinh tế hơn, nhưng không ảnh hưởng trực tiếp đến hiệu suất tổng thể của hệ thống.
Hãy cùng nhìn vào sơ đồ sau: . Khi gọi các dịch vụ trong cụm và gặp lỗi, Dubbo cung cấp nhiều giải pháp xử lý lỗi khác nhau, mặc định là failover (tái thử).
Các thành phần chính:
- Invoker: Đây là một đại diện có thể gọi được của dịch vụ
Provider
. Nó bao gồm địa chỉ củaProvider
và thông tin giao diện của dịch vụ. - Directory: Đại diện cho nhiều
Invoker
, có thể hiểu nôm na là một danh sách cácInvoker
(List<Invoker>
), nhưng khác biệt ở chỗ giá trị của nó có thể thay đổi theo thời gian, ví dụ khi trung tâm đăng ký đẩy thông báo cập nhật. - Cluster: Giấu đi chi tiết nhiều
Invoker
bên trong và tạo ra mộtInvoker
duy nhất, làm cho quy trình gọi trở nên minh bạch đối với tầng trên. Quá trình này bao gồm logic xử lý lỗi, nếu một lần gọi thất bại, nó sẽ chuyển sang thử lần tiếp theo. - Router: Phụ trách chọn ra một tập con từ nhiều
Invoker
dựa trên các quy tắc định tuyến, chẳng hạn như phân chia giữa đọc và viết, hoặc cô lập ứng dụng. - LoadBalance: Chọn ra một
Invoker
cụ thể từ nhiềuInvoker
để thực hiện cuộc gọi hiện tại, sử dụng thuật toán cân bằng tải. Nếu cuộc gọi thất bại, cần phải chọn lại.
Mô hình xử lý lỗi cụm
Failover Cluster
Chế độ tự động chuyển đổi khi xảy ra lỗi, nếu một cuộc gọi thất bại, hệ thống sẽ tự động thử các máy chủ khác. Thường được sử dụng cho các hoạt động đọc, nhưng việc tái thử có thể dẫn đến độ trễ cao hơn. Số lần tái thử có thể cấu hình thông qua thuộc tính retries="2"
(không tính lần đầu tiên).
1<dubbo:service retries="2" />
Đoạn mã dưới đây mô tả cách triển khai của chế độ cụm Failover Cluster
:
1public class FailoverCluster implements Cluster {
2 public final static String NAME = "failover";
3
4 public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
5 return new FailoverClusterInvoker<T>(directory);
6 }
7}
Điểm chính nằm trong lớp FailoverClusterInvoker
, nơi mà phương thức invoke
được triển khai trong lớp trừu tượng AbstractClusterInvoker
.
1@Override
2public Result invoke(final Invocation invocation) throws RpcException {
3 checkWhetherDestroyed();
4
5 Map<String, Object> contextAttachments = RpcContext.getContext().getObjectAttachments();
6 if (contextAttachments != null && !contextAttachments.isEmpty()) {
7 ((RpcInvocation) invocation).addObjectAttachments(contextAttachments);
8 }
9
10 List<Invoker<T>> invokers = list(invocation);
11 LoadBalance loadbalance = initLoadBalance(invokers, invocation);
12 RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);
13
14 return doInvoke(invocation, invokers, loadbalance);
15}
16
17protected abstract Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance [tin tức the thao bóng đá](/post/86bc44283d5b75d2.html) loadbalance) throws RpcException;
Phương thức doInvoke
trong FailoverClusterInvoker
là phần quan trọng nhất, chứa toàn bộ logic tái thử:
1@Override
2@SuppressWarnings({"unchecked", "rawtypes"})
3public Result doInvoke(Invocation invocation, final List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
4 List<Invoker<T>> copyInvokers = invokers;
5 checkInvokers(copyInvokers, invocation);
6 String methodName = RpcUtils.getMethodName(invocation);
7 int len = getUrl().getMethodParameter(methodName, RETRIES_KEY, DEFAULT_RETRIES) + 1;
8 if (len <= 0) {
9 len = 1;
10 }
11
12 RpcException le = null; // last exception.
13 List<Invoker<T>> invoked = new ArrayList<>(copyInvokers.size());
14 Set<String> providers = new HashSet<>(len);
15
16 for (int i = 0; i < len; i++) {
17 if (i > 0) {
18 checkWhetherDestroyed();
19 copyInvokers = list(invocation);
20 checkInvokers(copyInvokers, invocation);
21 }
22
23 Invoker<T> invoker = select(loadbalance, invocation, copyInvokers, invoked);
24 invoked.add(invoker);
25 RpcContext.getContext().setInvokers((List) invoked);
26
27 try {
28 Result result = invoker.invoke(invocation);
29 if (le != null && logger.isWarnEnabled()) {
30 logger.warn("Dù đã thử lại phương thức " + methodName
31 + " trong dịch vụ " + getInterface().getName()
32 + ", nhưng vẫn còn các nhà cung cấp bị lỗi.", le);
33 }
34 return result;
35 } catch (RpcException e) {
36 if (e.isBiz()) {
37 throw e;
38 }
39 le = e;
40 } catch (Throwable e) {
41 le = new RpcException(e.getMessage(), e);
42 } finally {
43 providers.add(invoker.getUrl().getAddress());
44 }
45 }
46 throw new RpcException(le.getCode(), "Không thể gọi phương thức " + methodName, le.getCause());
47}
Failfast Cluster
Thất bại nhanh chóng, chỉ thực hiện một lần gọi, nếu thất bại ngay lập tức thông báo lỗi. Thường dùng cho các hoạt động ghi không idempotent, như thêm bản ghi mới.
Failsafe Cluster
An toàn khi thất bại, bỏ qua các ngoại lệ khi chúng xuất hiện. Thường dùng cho các hoạt động như ghi nhật ký kiểm tra.
Failback Cluster
Phục hồi tự động khi thất bại, ghi nhận yêu cầu thất bại vào nền tảng và gửi lại định kỳ. Thường được áp dụng cho các hoạt động thông báo.
Forking Cluster
Gọi đồng thời nhiều máy chủ, chỉ cần một thành công là trả về kết quả. Thường sử dụng cho các hoạt động đọc đòi hỏi thời gian thực cao, nhưng cần tiêu tốn nhiều tài nguyên dịch vụ hơn. Có thể cấu hình số lượng song song tối đa thông qua thuộc tính forks="2"
.
Broadcast Cluster
Gọi tất cả các nhà cung cấp, lần lượt từng cái một, nếu bất kỳ máy chủ nào báo lỗi thì toàn bộ quy trình sẽ báo lỗi. Thường dùng để thông báo cho tất cả các nhà cung cấp cập nhật bộ nhớ đệm hoặc tài nguyên cục bộ như nhật ký.
Hy vọng bài viết này giúp bạn hiểu rõ hơn về cơ chế xử lý lỗi của Dubbo!