筆記簡述
本學習筆記主要是介紹了dubbo的基礎內容,簡單說明了dubbo、rpc、soa、zk等概念,并沒有直接貼出dubbo的組件調用圖等內容,而是利用實際的代碼介紹dubbo的服務提供方以及調用方的配置,對dubbo有一個感性的認識并通過dubbo-admin以及telnet查看dubbo的運行數據
后續會深入學習和分析dubbo spi以及暴露服務等等源碼
更多內容可看[目錄]Dubbo 源碼學習
目錄
Dubbo 介紹和使用 學習
1、前言
1.1、Dubbo 簡介
1.2、RPC 簡介
1.3、SOA 簡介
1.4、Zookeeper 簡介&安裝
2、Dubbo 服務提供方
3、Dubbo 服務調用方
4、參考鏈接
1、前言
1.1、Dubbo 簡介
Dubbo是由阿里巴巴基于java開發的一個RPC框架,經歷過了長時間的停止維護后又重新開始維護,現在(2018年04月17日)已經劃入了Apache孵化項目中,github地址:https://github.com/apache/incubator-dubbo,在國內屬于一個應用廣泛的RPC框架,接下來就一起來學習Dubbo是如何使用的,其原理又是如何。
TODO 提個問題那么Dubbo和Spring Cloud又有什么同異呢?
1.2、RPC 簡介
RPC全稱Remote Procedure Call,中文名叫遠程過程調用,通過網絡利用TCP或者UDP協議實現的不同機器之間的數據傳輸協議,A機器想調取B機器提供的服務,A機器拼接好自身請求的參數之后由RPC框架包裝成為特定格式的數字,序列化后后通過網絡發送到B機器上,B機器的RPC框架反解析出參數數據后去invoke調用自身機器的服務,最后按照原路返回到A機器上。
RPC是C/S模式,而且屏蔽了傳輸層和應用層,再基于特定的協議,使得用戶只需要關注自身的業務即可。
1.3、SOA 簡介
SOA全稱Service-Oriented Architecture,中文名叫面向服務編程,另一個常用的名稱是服務發現。業務繁多而且復雜就需要有一種統一的管理服務的機制,在分布式架構中,新加入的機器或者宕掉的機器后系統如何自動調整,一方面使得流量分發均衡,另一方面能夠及時發現出現異常的服務;控制服務與服務的調用關系等,確保服務合理正常的運行,例如zookeeper可以統一管理各機器以及機器上的服務運行情況。
在我們介紹的dubbo也會使用zookeeper作為其服務注冊中心
1.4、Zookeeper 簡介&安裝
zookeeper是為分布式應用提供一致性服務的軟件,提供的功能包括:配置維護、域名服務、分布式同步、組服務等。
進入到http://mirrors.hust.edu.cn/apache/zookeeper/頁面選擇一個合適的版本,進入下載其tar.gz包,隨便解壓到一個本地目錄,如下圖
進入到conf文件夾,可以看到zoo_sample.cfg
文件,直接cp一個名字為zoo.cfg
的文件,可以把內容修改為如下內容
$ cat zoo.cfg
tickTime=2000
dataDir=../data // 工作路徑,表示為conf的上一級目錄的data文件夾
dataLogDir=../logs // 日志的路徑
clientPort=2182 // zk啟動的端口
現在就可以啟動zk了,進入到bin目錄,Windows環境選擇zkServer.cmd
,Unix類環境選擇zkServer.sh
$ ./zkServer.sh
JMX enabled by default
Using config: ./../conf/zoo.cfg
Usage: ./zkServer.sh {start|start-foreground|stop|restart|status|upgrade|print-cmd}
如上述執行結果,很明顯已經確實加載了之前配置的zoo.cfg文件,但是需要加上啟動參數,其中有{start|start-foreground|stop|restart|status|upgrade|print-cmd}
- start-foreground 前臺啟動,可以看到實時日志
- start 后臺啟動
在這遇到一個,當前臺啟動之后,執行stop命令時,會提示沒有發現對應的服務pid,可是如果以start方式啟動,就可以正常使用stop關閉zk服務
zk服務已經正常啟動了,如下圖,1896端口的服務就是zk啟動的java進程服務
2、Dubbo 服務提供方
整個的文件目錄結構
spring-product.xml
<context:property-placeholder location="pro.properties" />
<!-- 消費方應用名 -->
<dubbo:application name="${dubbo.application.name}" owner="${dubbo.application.owner}" />
<dubbo:provider loadbalance="random" default="true"/>
<dubbo:registry protocol="zookeeper" address="${dubbo.zk.servers}" client="zkclient" group="${dubbo.zk.group}"/>
<dubbo:protocol name="${dubbo.application.protocol.name}" port="${dubbo.application.protocol.port}"/>
<!--<dubbo:monitor address="${dubbo.monitor.address}" />-->
<dubbo:consumer check="false" />
<bean class="com.jwfy.dubbo.product.ProductServiceImpl" id="productService" />
<!-- 基礎的bean 配置-->
<dubbo:service interface="com.jwfy.dubbo.product.ProductService" ref="productService" />
<!-- dubbo 對外暴露的接口,映射到的實體bean是productService-->
pro.properties
# dubbo
dubbo.application.name=dubbo-demo
dubbo.application.owner=jwfy
dubbo.application.protocol.name=dubbo
dubbo.application.protocol.port=20880
# dubbo.monitor.address=dubbo://127.0.0.1:20888
dubbo.zk.servers=127.0.0.1:2182
dubbo.zk.group=dubbo-demo
dubbo的相關配置,包含了使用的協議以及端口還有zk的配置情況,這里就使用了2182端口,到時候就會連上上文啟動的zk服務
ProductService 接口
public interface ProductService {
void print();
String getStr();
}
dubbo對外暴露的時候都是通過動態代理反射的,必須存在相關接口
ProductServiceImpl 實現類
public class ProductServiceImpl implements ProductService {
public void print() {
System.out.println("print");
}
public String getStr() {
return "Hello World Product";
}
}
ProductBootstrap 啟動類
public class ProductBootstrap {
/**
* 其實這個函數是用硬編碼的形式代替xml配置,xml配置最后都會變成如下的數據以及參數進行處理
*/
public static void runProduct(){
ProductService demo = new ProductServiceImpl();
ApplicationConfig config=new ApplicationConfig("simple-spring-dubbo");
RegistryConfig reg=new RegistryConfig("127.0.0.1:2182");
reg.setProtocol("zookeeper");
ProtocolConfig protocol = new ProtocolConfig();
protocol.setName("dubbo");
protocol.setPort(20880);
ServiceConfig<ProductService> service=new ServiceConfig<ProductService>();
service.setApplication(config);
service.setRegistry(reg);
service.setProtocol(protocol);
service.setInterface(ProductService.class);
service.setRef(demo);
service.setVersion("1.0");
service.export();
// export是最關鍵的函數,對外暴露服務
// 包括了向zk注冊以及啟動netty服務等待接受調用
try {
Thread.sleep(Integer.MAX_VALUE);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void runDubboProduct(){
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(
new String[]{"spring-product.xml"});
while (true){
// 為了讓服務不會自己終止,加個死循環
}
}
public static void main(String[] args){
//runProduct();
runDubboProduct();
}
}
如下圖dubbo-admin顯示的數據,服務提供方已經正常啟動,同時可以看到該服務的具體情況
可以通過Telnet查看當前機器上dubbo服務提供方的一些數據,當線上服務提供方添加了新的接口就可以通過該方法確認
3、Dubbo 服務調用方
調用方文件目錄結構
spring-consume.xml 文件
<context:property-placeholder location="application.properties" />
<!-- 消費方應用名 -->
<dubbo:application name="${dubbo.application.name}" owner="${dubbo.application.owner}" />
<dubbo:provider loadbalance="random" default="true"/>
<dubbo:registry protocol="zookeeper" address="${dubbo.zk.servers}" client="zkclient" group="${dubbo.zk.group}"/>
<dubbo:protocol name="${dubbo.application.protocol.name}" port="${dubbo.application.protocol.port}"/>
<!--<dubbo:monitor address="${dubbo.monitor.address}" />-->
<dubbo:consumer check="false" />
<dubbo:reference interface="com.jwfy.dubbo.product.ProductService" id="productService" />
application.proerties 文件
# dubbo
dubbo.application.name=dubbo-consume
dubbo.application.owner=jwfy
dubbo.application.protocol.name=dubbo
dubbo.application.protocol.port=20880
dubbo.monitor.address=dubbo://127.0.0.1:20888
dubbo.zk.servers=127.0.0.1:2182
dubbo.zk.group=dubbo-consumer-demo
public class ConsumeBootstrap {
private static final Logger logger = LoggerFactory.getLogger(ConsumeBootstrap.class);
public static void runDubboConsume(){
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(
new String[]{ "spring-consume.xml" });
ProductService productService = (ProductService)applicationContext.getBean("productService");
System.out.println(productService.getStr());
while (true){
}
}
public static void main(String[] args){
runDubboConsume();
}
}
直接啟動,顯示連接拒絕錯誤
Exception in thread "main" com.alibaba.dubbo.rpc.RpcException: Forbid consumer 192.168.10.123 access service com.jwfy.dubbo.product.ProductService from registry 127.0.0.1:2182 use dubbo version 2.5.3, Please check registry access list (whitelist/blacklist).
at com.alibaba.dubbo.registry.integration.RegistryDirectory.doList(RegistryDirectory.java:579)
at com.alibaba.dubbo.rpc.cluster.directory.AbstractDirectory.list(AbstractDirectory.java:73)
at com.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker.list(AbstractClusterInvoker.java:260)
at com.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker.invoke(AbstractClusterInvoker.java:219)
at com.alibaba.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker.invoke(MockClusterInvoker.java:72)
at com.alibaba.dubbo.rpc.proxy.InvokerInvocationHandler.invoke(InvokerInvocationHandler.java:52)
at com.alibaba.dubbo.common.bytecode.proxy0.getStr(proxy0.java)
at com.jwfy.dubbo.consume.ConsumeBootstrap.runDubboConsume(ConsumeBootstrap.java:22)
at com.jwfy.dubbo.consume.ConsumeBootstrap.main(ConsumeBootstrap.java:30)
拒絕鏈接到遠程服務,這時候需要核對服務提供方以及服務調用方的配置是否不同
經過觀察發現是服務調用方的zk組寫錯了,調用方在使用不存在的zk注冊的時候,會被禁止掉,從而提示該錯誤
把application.proerties 中的dubbo.zk.group=dubbo-consumer-demo
修改為dubbo.zk.group=dubbo-demo
,再啟動,就恢復正常了,再看看dubbo-admin的顯示