一褪储、dubbo是什么遭垛?
Dubbo是一個(gè)分布式RPC中間件。RPC(Remote Procedure Call)
遠(yuǎn)程過程調(diào)用協(xié)議未状,它是一種通過網(wǎng)絡(luò)從遠(yuǎn)程計(jì)算機(jī)程序上請求服務(wù)鸭限,
而不需要了解底層網(wǎng)絡(luò)技術(shù)的協(xié)議蜕径。RPC可以認(rèn)為是普通的c/s模式,服務(wù)提供方作為服務(wù)端里覆,服務(wù)調(diào)用方作為客戶端丧荐。
通常的RPC過程如下圖:
二、如何實(shí)現(xiàn)一個(gè)Rpc
服務(wù)端代碼通過監(jiān)聽一個(gè)端口暴露服務(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實(shí)現(xiàn)模型中,有一些問題:
1.服務(wù)端的狀態(tài)變化(不可用渡冻,對客戶端的權(quán)限變化)戚扳,怎么通知到客戶端?
2.服務(wù)的增減(可擴(kuò)展性)
3.調(diào)用關(guān)系拓?fù)洌?/p>
4.服務(wù)端永遠(yuǎn)不知道誰會(huì)對它提供的服務(wù)感興趣族吻。
5.服務(wù)質(zhì)量保證
.......
總之有很多可用性帽借、可擴(kuò)展性、可管理等許多問題無法解決超歌。
三砍艾、RPC改進(jìn)一點(diǎn)
普通的RPC有諸多缺陷,但我們期望的是高可用巍举、高性能脆荷、高度可擴(kuò)展的系統(tǒng)。而這些特性恰是分布式系統(tǒng)的設(shè)計(jì)目標(biāo)。
我們?nèi)绾巫龇植际降膽?yīng)用:
普通的C/S模型實(shí)現(xiàn)是一個(gè)server端蜓谋,而在分布式中梦皮,采用的多節(jié)點(diǎn)集群;不論是客戶端還是服務(wù)端,都是多節(jié)點(diǎn)集群桃焕,而且各個(gè)節(jié)點(diǎn)是動(dòng)態(tài)可增減的剑肯。為此我們引入了注冊中心的概念。注冊中心將服務(wù)端和客戶端解耦观堂,工作方式大體如下:
四退子、更具體一些
在dubbo中,其實(shí)是服務(wù)提供者在zk進(jìn)行Path的創(chuàng)建型将,Path中包含了服務(wù)相關(guān)的配置信息(服務(wù)名寂祥、消費(fèi)白名單、序列化協(xié)議七兜、服務(wù)器地址等)丸凭,如下:
同時(shí),客戶端需要上報(bào)自己引用了哪些服務(wù)腕铸。相比服務(wù)發(fā)布惜犀,訂閱服務(wù)麻煩得多,dubbo服務(wù)訂閱的實(shí)現(xiàn)方式是:通過監(jiān)聽provide目錄和configurators目錄狠裹;provide目錄虽界,就是所有注冊同一服務(wù)的提供者都會(huì)在這個(gè)目錄下創(chuàng)建Path;configurations一般由服務(wù)訂閱者初始化創(chuàng)建涛菠,控制臺(tái)來修改里面的內(nèi)容(增刪path莉御,如序列化協(xié)議、負(fù)載均衡算法俗冻、超時(shí)控制等)礁叔。具體如下:
客戶端上報(bào)服務(wù)的具體例子:
客戶端調(diào)用具體流程:
本文作者:楊濤(點(diǎn)融黑幫),就職于點(diǎn)融架構(gòu)組迄薄,JAVA程序員一枚琅关。