一、dubbo是什么?
Dubbo是一個分布式RPC中間件。RPC(Remote Procedure Call)
遠(yuǎn)程過程調(diào)用協(xié)議,它是一種通過網(wǎng)絡(luò)從遠(yuǎn)程計算機(jī)程序上請求服務(wù),
而不需要了解底層網(wǎng)絡(luò)技術(shù)的協(xié)議。RPC可以認(rèn)為是普通的c/s模式,服務(wù)提供方作為服務(wù)端,服務(wù)調(diào)用方作為客戶端。
通常的RPC過程如下圖:
二、如何實現(xiàn)一個Rpc
服務(wù)端代碼通過監(jiān)聽一個端口暴露服務(wù):
public static void export(final Object service, int port) throws Exception {
ServerSocket server = new ServerSocket(port);
for (; ; ) {
try {
final Socket socket = server.accept();
new Thread(new Runnable() {
@Override
public void run() {
try {
try {
ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
try {
String methodName = input.readUTF();
Class[] parameterTypes = (Class[]) input.readObject();
Object[] arguments = (Object[]) input.readObject();
ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
try {
Method method = service.getClass().getMethod(methodName, parameterTypes);
Object result = method.invoke(service, arguments);
output.writeObject(result);
} catch (Throwable t) {
output.writeObject(t);
} finally {
output.close();
}
} finally {
input.close();
}
} finally {
socket.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
} catch (Exception e) {
e.printStackTrace();
}
}
}
客戶端根據(jù)服務(wù)提供者IP和端口,進(jìn)行服務(wù)引用
@SuppressWarnings("unchecked")
public static T refer(final Class interfaceClass, final String host, final int port)
throws Exception {
if (interfaceClass == null) {
throw new IllegalArgumentException("Interface class == null");
}
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(
"The " + interfaceClass.getName() + " must be interface class!");
}
if (host == null || host.length() == 0) {
throw new IllegalArgumentException("Host == null!");
}
if (port <= 0 || port > 65535) {
throw new IllegalArgumentException("Invalid port " + port);
}
System.out.println(
"Get remote service " + interfaceClass.getName() + " from server " + host + ":" + port);
return (T) Proxy
.newProxyInstance(interfaceClass.getClassLoader(), new Class[]{interfaceClass},
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] arguments)
throws Throwable {
Socket socket = new Socket(host, port);
try {
ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
try {
output.writeUTF(method.getName());
output.writeObject(method.getParameterTypes());
output.writeObject(arguments);
ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
try {
Object result = input.readObject();
if (result instanceof Throwable) {
throw (Throwable) result;
}
return result;
} finally {
input.close();
}
} finally {
output.close();
}
} finally {
socket.close();
}
}
});
}
可以看到,最簡單的RPC方式,不需要太多的代碼。但是在最簡單的RPC實現(xiàn)模型中,有一些問題:
1.服務(wù)端的狀態(tài)變化(不可用,對客戶端的權(quán)限變化),怎么通知到客戶端?
2.服務(wù)的增減(可擴(kuò)展性)
3.調(diào)用關(guān)系拓?fù)洌?/p>
4.服務(wù)端永遠(yuǎn)不知道誰會對它提供的服務(wù)感興趣。
5.服務(wù)質(zhì)量保證
.......
總之有很多可用性、可擴(kuò)展性、可管理等許多問題無法解決。
三、RPC改進(jìn)一點
普通的RPC有諸多缺陷,但我們期望的是高可用、高性能、高度可擴(kuò)展的系統(tǒng)。而這些特性恰是分布式系統(tǒng)的設(shè)計目標(biāo)。
我們?nèi)绾巫龇植际降膽?yīng)用:
普通的C/S模型實現(xiàn)是一個server端,而在分布式中,采用的多節(jié)點集群;不論是客戶端還是服務(wù)端,都是多節(jié)點集群,而且各個節(jié)點是動態(tài)可增減的。為此我們引入了注冊中心的概念。注冊中心將服務(wù)端和客戶端解耦,工作方式大體如下:

四、更具體一些
在dubbo中,其實是服務(wù)提供者在zk進(jìn)行Path的創(chuàng)建,Path中包含了服務(wù)相關(guān)的配置信息(服務(wù)名、消費(fèi)白名單、序列化協(xié)議、服務(wù)器地址等),如下:

同時,客戶端需要上報自己引用了哪些服務(wù)。相比服務(wù)發(fā)布,訂閱服務(wù)麻煩得多,dubbo服務(wù)訂閱的實現(xiàn)方式是:通過監(jiān)聽provide目錄和configurators目錄;provide目錄,就是所有注冊同一服務(wù)的提供者都會在這個目錄下創(chuàng)建Path;configurations一般由服務(wù)訂閱者初始化創(chuàng)建,控制臺來修改里面的內(nèi)容(增刪path,如序列化協(xié)議、負(fù)載均衡算法、超時控制等)。具體如下:
客戶端上報服務(wù)的具體例子:
客戶端調(diào)用具體流程:
本文作者:楊濤(點融黑幫),就職于點融架構(gòu)組,JAVA程序員一枚。