dubbo官網:http://dubbo.io前端
Dubbo開始於電商系統,所以在這裏先從電商系統的演變講起。java
單一應用框架(ORM)
當網站流量很小時,只需一個應用,將全部功能以下單支付等都部署在一塊兒,以減小部署節點和成本。
缺點:單一的系統架構,使得在開發過程當中,佔用的資源愈來愈多,並且隨着流量的增長愈來愈難以維護 nginx
垂直應用框架(MVC)
垂直應用架構解決了單一應用架構所面臨的擴容問題,流量可以分散到各個子系統當中,且系統的體積可控,必定程度上下降了開發人員之間協同以及維護的成本,提高了開發效率。
缺點:可是在垂直架構中相同邏輯代碼須要不斷的複製,不能複用。 git
分佈式應用架構(RPC)
當垂直應用愈來愈多,應用之間交互不可避免,將核心業務抽取出來,做爲獨立的服務,逐漸造成穩定的服務中心 github
流動計算架構(SOA)
隨着服務化的進一步發展,服務愈來愈多,服務之間的調用和依賴關係也愈來愈複雜,誕生了面向服務的架構體系(SOA),也所以衍生出了一系列相應的技術,如對服務提供、服務調用、鏈接處理、通訊協議、序列化方式、服務發現、服務路由、日誌輸出等行爲進行封裝的服務框架算法
從以上是電商系統的演變能夠看出架構演變的過程: spring
單一應用架構apache
垂直應用架構服務器
在這裏插播一條關於RPC的簡介:
RPC(Remote Procedure Call Protocol):遠程過程調用:
兩臺服務器A、B,分別部署不一樣的應用a,b。當A服務器想要調用B服務器上應用b提供的函數或方法的時候,因爲不在一個內存空間,不能直接調用,須要經過網絡來表達調用的語義傳達調用的數據。
說白了,就是你在你的機器上寫了一個程序,我這邊是沒法直接調用的,這個時候就出現了一個遠程服務調用的概念。網絡
RPC是一種經過網絡從遠程計算機程序上請求服務,而不須要了解底層網絡技術的協議。RPC協議假定某些傳輸協議的存在,如TCP或UDP,爲通訊程序之間攜帶信息數據。在OSI網絡通訊模型中,RPC跨越了傳輸層和應用層。RPC使得開發包括網絡分佈式多程序在內的應用程序更加容易。
RPC採用客戶機/服務器模式。請求程序就是一個客戶機,而服務提供程序就是一個服務器。首先,客戶機調用進程發送一個有進程參數的調用信息到服務進程,而後等待應答信息。在服務器端,進程保持睡眠狀態直到調用信息到達爲止。當一個調用信息到達,服務器得到進程參數,計算結果,發送答覆信息,而後等待下一個調用信息,最後,客戶端調用進程接收答覆信息,得到進程結果,而後調用執行繼續進行。
RPC須要解決的問題:
(能夠稍做了解,詳情可查看別的博文)
Dubbo是:
天天爲2千多個服務提供大於30億次訪問量支持,並被普遍應用於阿里巴巴集團的各成員站點以及別的公司的業務中。
Provider: 暴露服務的服務提供方。
Consumer: 調用遠程服務的服務消費方。
Registry: 服務註冊與發現的註冊中心。
Monitor: 統計服務的調用次數和調用時間的監控中心。
調用流程
0.服務容器負責啓動,加載,運行服務提供者。
1.服務提供者在啓動時,向註冊中心註冊本身提供的服務。
2.服務消費者在啓動時,向註冊中心訂閱本身所需的服務。
3.註冊中心返回服務提供者地址列表給消費者,若是有變動,註冊中心將基於長鏈接推送變動數據給消費者。
4.服務消費者,從提供者地址列表中,基於軟負載均衡算法,選一臺提供者進行調用,若是調用失敗,再選另外一臺調用。
5.服務消費者和提供者,在內存中累計調用次數和調用時間,定時每分鐘發送一次統計數據到監控中心
對於服務提供方,它須要發佈服務,並且因爲應用系統的複雜性,服務的數量、類型也不斷膨脹;
對於服務消費方,它最關心如何獲取到它所須要的服務,而面對複雜的應用系統,須要管理大量的服務調用。
並且,對於服務提供方和服務消費方來講,他們還有可能兼具這兩種角色,即既須要提供服務,有須要消費服務。
經過將服務統一管理起來,能夠有效地優化內部應用對服務發佈/使用的流程和管理。服務註冊中心能夠經過特定協議來完成服務對外的統一。
Dubbo提供的註冊中心有以下幾種類型可供選擇:
優勢:
缺點:
Dubbo Demo:
新建項目dubbo-demo,新建3個子項目:
dubbo-demo-common 公共項目(包含公共接口、公共domain,由於provider項目和consumer項目都有這些,因此抽出來放入另外一個項目)
dubbo-demo-provider 服務提供者(依賴dubbo-demo-common項目 )
dubbo-demo-consumer 服務消費者(依賴dubbo-demo-common項目 )
公共項目
User: 在dubbo 2.6,必須實現Serializable接口,不然會報錯:java.lang.IllegalStateException: Serialized class com.atyang.dubbo.domain.User must implement java.io.Serializable
public class User implements Serializable{ private int id; private String name; public User() { } public User(int id, String name) { this.id = id; this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + '}'; } }
UserService
public interface UserService { User getUser(int id); }
UserUtil : 獲取用戶的工具類
public class UserUtil { private static Map<Integer, User> map = new HashMap<Integer, User>(10); static { for(int i=1;i<=10;i++){ map.put(i, new User(i, "我是用戶-" + i)); } } public static User getUser(int id){ User user = map.get(id); if(null == user){ user = new User(0, "----用戶不存在----"); } return user; } }
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>com.atyang.dubbo</artifactId> <groupId>dubbo-demo</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>dubbo-demo-provider</artifactId> <dependencies> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>2.6.0</version> </dependency> <!--zk客戶端,不依賴的話,會報錯:Caused by: java.lang.ClassNotFoundException: org.I0Itec.zkclient.IZkStateListener--> <dependency> <groupId>com.github.sgroschupf</groupId> <artifactId>zkclient</artifactId> <version>0.1</version> </dependency> <!--公共項目--> <dependency> <groupId>dubbo-demo</groupId> <artifactId>dubbo-demo-common</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> </project>
spring.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"> <dubbo:application name="demo-provider"/> <!-- 註冊中心地址 --> <dubbo:registry address="zookeeper://localhost:2181"/> <!-- dubbo暴露的服務端口 --> <dubbo:protocol name="dubbo" port="20880"/> <!--註冊服務到註冊中心--> <dubbo:service interface="com.atyang.dubbo.service.UserService" ref="userService"/> <bean id="userService" class="com.atyang.dubbo.service.impl.UserServiceImpl"/> </beans>
Service實現
public class UserServiceImpl implements UserService { public User getUser(int id) { System.out.println("--------用戶服務被消費--------- id=" + id); return UserUtil.getUser(id); } }
啓動類
public class ProviderStart { public static void main(String[] args) throws IOException { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( new String[] {"classpath:provider-spring.xml"}); context.start(); System.out.println("--------消費端服務已啓動-----"); // press any key to exit System.in.read(); } }
spring.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"> <dubbo:application name="demo-consumer"/> <dubbo:registry address="zookeeper://localhost:2181"/> <dubbo:reference id="userService" interface="com.atyang.dubbo.service.UserService"/> </beans>
啓動類
public class ConsumerStart { public static void main(String[] args) throws IOException { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( new String[]{"classpath:consumer-spring.xml"}); context.start(); // obtain proxy object for remote invocation UserService userService = context.getBean("userService", UserService.class); // execute remote invocation User user = userService.getUser(3); // show the result System.out.println(user); // press any key to exit System.in.read(); } }
代碼完成後,先啓動zookeeper,用zkCli.cmd鏈接後,查看zk節點: ls /
目前只有默認的 zookeeper節點
啓動服務提供者
再查看zk節點,多了個dubbo
而後再啓動服務消費者,獲取到了用戶信息。消費端調用服務,就像調用本地方法同樣。dubbo的rpc就這麼方便