ServiceConfigdoExportUrlsFor1Protocol - bong da doi thuong bang the cao
Trong môi trường hiện tại, việc triển khai ứng dụng Java bằng cách sử dụng container đã trở nên khá phổ biến. Tuy nhiên, cùng với sự tiện lợi đó cũng đi kèm một số thách thức cần được giải quyết, chẳng hạn như vấn đề đăng ký dịch vụ Dubbo trong container. Trong các phiên bản cũ của Dubbo, quy trình này chỉ đơn giản là lấy địa chỉ IP từ card mạng của máy.
Cụ thể, đoạn mã thực hiện việc này nằm trong phương thức sau: com.alibaba.dubbo.config.ServiceConfig#doExportUrlsFor1Protocol
.
1private void doExportUrlsFor1Protocol(ProtocolConfig protocolConfig, List<URL> registryURLs) {
2 String name = protocolConfig.getName();
3 if (name == null || name.length() == 0) {
4 name = "dubbo";
5 }
6 String host = protocolConfig.getHost();
7 if (provider != null && (host == null || host.length() == 0)) {
8 host = provider.getHost();
9 }
10 boolean anyhost = false;
11 if (NetUtils.isInvalidLocalHost(host)) {
12 anyhost = true;
13 try {
14 host = InetAddress.getLocalHost().getHostAddress();
15 } catch (UnknownHostException e) {
16 logger.warn(e.getMessage(), e);
17 }
18 if (NetUtils.isInvalidLocalHost(host)) {
19 if (registryURLs != null && registryURLs.size() > 0) {
20 for (URL registryURL : registryURLs) {
21 try {
22 Socket socket = new Socket();
23 try {
24 SocketAddress addr = new InetSocketAddress(registryURL.getHost(), registryURL.getPort());
25 socket.connect(addr, 1000);
26 host = socket.getLocalAddress().getHostAddress();
27 break;
28 } finally {
29 try {
30 socket.close();
31 } catch (Throwable e) {}
32 }
33 } catch (Exception e) {
34 logger.warn(e.getMessage(), e);
35 }
36 }
37 }
38 if (NetUtils.isInvalidLocalHost(host)) {
39 host = NetUtils.getLocalHost();
40 }
41 }
42}
Tuy nhiên, cách tiếp cận này sử dụng phương pháp tự nhiên của JDK java.net.InetAddress#getLocalHost
để lấy địa chỉ của máy chủ. Điều này gây ra vấn đề cho container vì địa chỉ IP nội bộ của container sẽ không thể được truy cập từ bên ngoài.
May mắn thay, trong các phiên bản mới hơn như Dubbo 2.6.5, bạn có thể khắc phục vấn đề này bằng cách cài đặt biến môi trường trong Docker để đưa vào địa chỉ của máy chủ vật lý mà container đang chạy trên đó. Đoạn mã xử lý điều này vẫn nằm trong phương thức com.alibaba.dubbo.config.ServiceConfig#doExportUrlsFor1Protocol
, nhưng lần này logic lấy host đã được chuyển sang phương thức com.alibaba.dubbo.config.ServiceConfig#findConfigedHosts
.
1private String findConfigedHosts(ProtocolConfig protocolConfig, List<URL> registryURLs, Map<String, String> map) {
2 boolean anyhost = false;
3 String hostToBind = getValueFromConfig(protocolConfig, Constants.DUBBO_IP_TO_BIND);
4 if (hostToBind != null && hostToBind.length() > 0 && isInvalidLocalHost(hostToBind)) {
5 throw new IllegalArgumentException("Đã chỉ định địa chỉ IP không hợp lệ từ thuộc tính:" + Constants.DUBBO_IP_TO_BIND + ", giá trị:" + hostToBind);
6 }
7 // Nếu không tìm thấy địa chỉ IP được liên kết trong môi trường, hãy tiếp tục kiểm tra
8 if (hostToBind == null || hostToBind.length() == 0) {
9 hostToBind = protocolConfig.getHost();
10 if (provider != null && (hostToBind == null || hostToBind.length() == 0)) {
11 hostToBind = provider.getHost();
12 }
13 if (isInvalidLocalHost(hostToBind)) {
14 anyhost = true;
15 try {
16 hostToBind = InetAddress.getLocalHost().getHostAddress();
17 } catch (UnknownHostException e) {
18 logger.warn(e.getMessage(), e);
19 }
20 if (isInvalidLocalHost(hostToBind)) {
21 if (registryURLs != null && !registryURLs.isEmpty()) {
22 for (URL registryURL : registryURLs) {
23 if (Constants.MULTICAST.equalsIgnoreCase(registryURL.getParameter("registry"))) {
24 // Bỏ qua đăng ký đa điểm vì chúng ta không thể kết nối thông qua Socket
25 } else {
26 try {
27 Socket socket = new Socket();
28 try {
29 SocketAddress addr = new InetSocketAddress(registryURL.getHost(), registryURL.getPort());
30 socket.connect(addr, 1000);
31 hostToBind = socket.getLocalAddress().getHostAddress();
32 break;
33 } finally {
34 try {
35 socket.close();
36 } catch (Throwable e) {
37 }
38 }
39 } catch (Exception e) {
40 logger.warn(e.getMessage(), e);
41 }
42 }
43 }
44 }
45 if (isInvalidLocalHost(hostToBind)) {
46 hostToBind = getLocalHost();
47 }
48 }
49 }
50 map.put(Constants.BIND_IP_KEY, hostToBind);
51 // Địa chỉ IP đăng ký không được sử dụng làm địa chỉ IP liên kết theo mặc định
52 String hostToRegistry = getValueFromConfig(protocolConfig, Constants.DUBBO_IP_TO_REGISTRY);
53 if (hostToRegistry != null && hostToRegistry.length() > 0 && isInvalidLocalHost(hostToRegistry)) {
54 throw new IllegalArgumentException("Đã chỉ định địa chỉ IP đăng ký không hợp lệ từ thuộc tính:" + Constants.DUBBO_IP_TO_REGISTRY + ", giá trị:" + hostToRegistry);
55 } else if (hostToRegistry == null || hostToRegistry.length() == 0) {
56 // Địa chỉ IP liên kết được sử dụng làm địa chỉ IP đăng ký theo mặc định
57 hostToRegistry = hostToBind;
58 }
59 map.put(Constants.ANYHOST_KEY, String.valueOf(anyhost));
60 return hostToRegistry;
61}
Phương thức này hỗ trợ việc lấy địa chỉ IP chơi trò chơi bắn cá từ cấu hình hoặc biến môi trường. Ví dụ:
1private String getValueFromConfig(ProtocolConfig protocolConfig, String key) {
2 String protocolPrefix = protocolConfig.getName().toUpperCase() + "_";
3 String port = ConfigUtils.getSystemProperty(protocolPrefix + key);
4 if (port == null || port.length() == 0) {
5 port = ConfigUtils.getSystemProperty(key);
6 }
7 return port;
8}
Nói cách khác, nếu bạn cấu hình biến môi trường DUBBO_IP_TO_REGISTRY
, nó sẽ ưu tiên sử dụng địa chỉ IP này khi đăng ký dịch vụ. Điều này giúp đảm bảo rằng dịch vụ được đăng ký đúng và có thể truy cập từ bên ngoài container.
Với cách tiếp cận này, bạn có thể dễ dàng quản lý và tối ưu hóa việc triển khai ứng dụng trong môi trường container mà không gặp phải những vấn đề về mạng trước đây.