Dubbo
分布式是指多個獨立計算機不同的服務;而這些計算機對于使用者而言就是一個單獨的系統
例如:一個使用者使用京東商城購買物品。一系列操作對于使用者來說就是一個單獨的系統,而對于計算機就是多個服務的整合。
單體架構 --> 垂直架構 --> SOA架構 --> 微服務架構
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsISPrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdsATOfd3bkFGazxCMx8VesATMfhHLlN3XnxCMwEzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-cmbw5iZxgjNjRTZ1UzYkVTNwUmY4AzYzM2MiJzY1YTN2UTZw8CXxIzLcdDMxIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjL0M3Lc9CX6MHc0RHaiojIsJye.png)
架構說明:全部功能集中在一個項目中。
架構優點:架構簡單;前期開發成本低;開發周期短,适合小型項目
架構缺點:
全部功能集中在一個工程裡面,對于大型項目不易開發、擴充和維護
技術棧受限;隻能使用一種語言開發
系統性能擴充隻能通過擴充叢集節點,成本高。
架構說明:按照業務進行切割,不利于開發、擴充、維護。
架構優點:技術棧可擴充(不同的系統可以用不同的程式設計語言編寫)
功能集中在一個項目中,不利于開發、擴充、維護
系統擴張隻能通過叢集的方式
項目之間功能備援、資料備援、耦合性強。
SOA是面向服務的架構,它可以根據需求通過網絡對松散耦合的粗粒度應用元件(服務)進行分布式部署、組合和使用。
架構說明:将重複功能或子產品抽取元件的形式、對外提供服務,在項目與服務之間使用ES8(企業服務總線)的形式作為通信的橋梁
架構優點:
重複功能或子產品抽取為服務,提高開發效率
可重用性高
可維護性高
各系統之間業務不同,很難确認功能或子產品是重複的
抽取服務粒度大
系統和服務之間的耦合度高
架構說明:
将系統服務層完全獨立出來,抽取為一個個的微服務
抽取的粒度更細,遵循單一原則
采用輕量級架構協定傳輸
架構優點
服務拆分粒度更細,有利于提高開發效率
可以針對不同服務制定對應的優化方案
适用于網際網路時代,産品疊代周期更短
粒度太細導緻服務太多,維護成本高
分布式系統開發的技術成本高,對團隊的挑戰大
RPC是指遠端過程調用,是一種程序間的通信方式,是一種技術的思想,而不是規範
RPC兩個核心子產品:通訊、序列化
第一步:A伺服器想要調用B伺服器方法,并傳入一個對象。
第二步:首先通過A伺服器的小助手,知道了要掉别的伺服器
第三步:小助手将對象序列化,然後建立soket連接配接;發送消息
第四步:B伺服器的小助手接收到傳輸的對象,先進行反序列化
第五步:B伺服器方法接收到對象,然後執行方法體,再将值傳回,同時B伺服器小助手再次序列化結果對象
第六步:A伺服器小助手接收到值,反序列化,最後傳給A伺服器方法輸出
示例圖:
dubbo、gRPC、Thrift、HSF(High Speed Service Framework)
Apache Dubbo是一款高性能、輕量級的開源Java RPC架構,它提供了三大核心能力:面向接口的遠端方法調用,智能容錯和負載均衡,以及服務自動注冊和發現
https://dubbo.apache.org/zh/
虛線代表的都是異步通路,實作都是同步通路
藍色虛線:在啟動時完成的功能
紅色虛線(實作)都是程式運作過程中執行的功能
第一步:Zookeeper官網下載下傳https://zookeeper.apache.org
選取版本下載下傳
![
第二步:下載下傳完成以後解壓後的樣子
第三步:點開bin目錄;
第四步:第一次運作會報錯誤;找不到zoo.cfg檔案
第五步:在解壓目錄的conf目錄下複制zoo_sample.cfg檔案改名成zoo.cfg
第六步:修改zoo.cfg的配置
第七步:再次啟動zkServer.cmd檔案
注意:安裝了Oracle的人;8080端口會被占用;導緻Dubbo啟動引導不起tomcat;端口占用;
步驟一:運作cmd,輸入sqlplus / as sysdba;
步驟二:輸入exec dbms_xdb.sethttpport(8088)。(其中8088為更改後的端口)
新版本的啟用了前後端分離式設計:
啟動步驟
第一步:先找到Dubbo官網;進入github
第二步:下載下傳Dubbo admin
第三步:解壓完成以後;找到Dubbo-admin-server;然後執行打包 mvn package -Dmaven.test.skip=true;打好的包在target下面。
第四步:保證此檔案裡面的端口和zookeeper一緻
第五步:完成以後;找到jar包;再執行java -jar啟動jar包
第六步:執行完成以後不要關閉視窗,找到Dubbo-admin-ui;執行npm install 下載下傳前端依賴
第七步:執行npm run dev
最後便可以通過以下位址通路Dubbo的背景頁面
Registry(服務注冊中心)在dubbo當中起着至關重要的作用。
Zookeeper是Apache Hadoop的子項目;是一個樹型的目錄服務,支援變更推送,是和作為Dubbo服務的注冊中心。
樹型目錄服務:其實我們的檔案系統也是一個樹型目錄結構
服務提供者(Provider)啟動時: 向 <code>/dubbo/com.foo.BarService/providers</code> 目錄下寫入自己的 URL 位址
服務消費者(Consumer)啟動時: 訂閱 <code>/dubbo/com.foo.BarService/providers</code> 目錄下的提供者 URL 位址。并向 <code>/dubbo/com.foo.BarService/consumers</code> 目錄下寫入自己的 URL 位址
監控中心(Monitor)啟動時: 訂閱 <code>/dubbo/com.foo.BarService</code> 目錄下的所有提供者和消費者 URL 位址
第一步:使用idea建立maven項目;需勾選webapp的線上模闆
建立項目
建立子產品的配置
maven的本地配置
建立好的目錄結構
補齊目錄
第二步:建立消費者子產品;步驟同上
第三步:建立好了兩個子產品之後;就該書寫配置檔案
第一個:服務提供方的配置
pom依賴
<code><?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"> <modelVersion>4.0.0</modelVersion> <groupId>com.itheima</groupId> <artifactId>dubbodemo_provider</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <name>dubbodemo_provider Maven Webapp</name> <!-- FIXME change it to the project's website --> <url>http://www.example.com</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <spring.version>5.0.5.RELEASE</spring.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jms</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <!-- dubbo相關 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>2.6.0</version> </dependency> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.4.7</version> </dependency> <dependency> <groupId>com.github.sgroschupf</groupId> <artifactId>zkclient</artifactId> <version>0.1</version> </dependency> <dependency> <groupId>javassist</groupId> <artifactId>javassist</artifactId> <version>3.12.1.GA</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.47</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.6</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.2</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <configuration> <!-- 指定端口 --> <port>8089</port> <!-- 請求路徑 --> <path>/</path> </configuration> </plugin> </plugins> </build> </project></code>
首先,web.xml
<code><!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app> <display-name>Archetype Created Web Application</display-name> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext*.xml</param-value> </context-param> <!-- spring的監聽器 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> </web-app></code>
編寫Service接口
<code>package com.xiaoyu.service; public interface HelloService { public String sayHello(String name); }</code>
編寫Service的實作類
<code>package com.xiaoyu.service.ServiceImpl; import com.alibaba.dubbo.config.annotation.Service; import com.xiaoyu.service.HelloService; /** * 注意這個Service的包;這個service是Dubbo所擁有的的Service;而不是spring的;把服務注冊到注冊中心 */ @Service(interfaceClass = HelloService.class,protocol = "dubbo") // 釋出服務必須使用Dubbo提供的Service注解 public class HelloServiceImpl implements HelloService { @Override public String sayHello(String name) { return "Hello" + name; } }</code>
配置ApplicationContext.xml
<code><?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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <!--每個dubbo應用(服務提供方和服務消費方)都必須指定一個唯一的名稱--> <dubbo:application name="demo_dubbo"></dubbo:application> <!--指定服務的注冊中心--> <dubbo:registry address="zookeeper://192.168.2.60:2181"></dubbo:registry> <!--配置協定和端口--> <dubbo:protocol name="dubbo" port="20880"></dubbo:protocol> <!--指定包掃描,用于釋出dubbo服務--> <dubbo:annotation package="com.xiaoyu.service.ServiceImpl"></dubbo:annotation> </beans></code>
第二:服務消費方配置
首先Pom依賴坐标
<code><?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"> <modelVersion>4.0.0</modelVersion> <groupId>com.itheima</groupId> <artifactId>dubbodemo_consumer</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <name>dubbodemo_consumer Maven Webapp</name> <!-- FIXME change it to the project's website --> <url>http://www.example.com</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <spring.version>5.0.5.RELEASE</spring.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jms</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <!-- dubbo相關 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>2.6.0</version> </dependency> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.4.7</version> </dependency> <dependency> <groupId>com.github.sgroschupf</groupId> <artifactId>zkclient</artifactId> <version>0.1</version> </dependency> <dependency> <groupId>javassist</groupId> <artifactId>javassist</artifactId> <version>3.12.1.GA</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.47</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <configuration> <!-- 指定端口 --> <port>8088</port> <!-- 請求路徑 --> <path>/</path> </configuration> </plugin> </plugins> </build> </project></code>
其次Web.xml配置
<code><!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app> <display-name>Archetype Created Web Application</display-name> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- 指定加載的配置檔案,通過參數contextConfigLocation加載--> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext-web.xml</param-value> </init-param> <!-- 指定項目啟動的時候會掃描配置檔案 --> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <!-- 配置過濾--> <url-pattern>*.do</url-pattern> </servlet-mapping> </web-app></code>
編寫Service
編寫Controller
<code>package com.xiaoyu.controller;import com.alibaba.dubbo.config.annotation.Reference;import com.xiaoyu.service.HelloService;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody;@Controller@RequestMapping("/hello")public class HelloController { // 此注解類似Autowried注入;隻不過是從服務提供方來把ServiceImpl的實作給注入;到注冊中心查找服務提供方所注冊的服務 @Reference // dubbo 提供的查找服務注解 private HelloService helloService; @RequestMapping("/sayHello") @ResponseBody public String sayHello(String name){ return helloService.sayHello(name); }}</code>
最後是ApplicationContext的配置
<code><?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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--每個dubbo應用(服務提供方和服務消費方)都必須指定一個唯一的名稱--> <dubbo:application name="demo_dubboConsumer"></dubbo:application> <!-- 配置Zookeeper注冊中心的位址和端口--> <dubbo:registry address="zookeeper://192.168.2.60:2181"></dubbo:registry> <!-- 配置掃描包--> <dubbo:annotation package="com.xiaoyu.controller"></dubbo:annotation> <dubbo:consumer check="false"></dubbo:consumer></beans></code>
最後啟動兩個項目
通路服務消費方的url會出現;提供方在ServiceImpl中出現的值(注意配置的Zookeeper注冊中心的那台電腦一定要啟動Zookeeper服務;啟動步驟看上面)
安裝步驟:
将dubbo-admin-server打成war包
然後将War包丢到Tomcat的Webapps下面
啟動Tomcat會自動解壓War包
修改WEB-INF下的dubbo,properties檔案,注意dubbo.registry.address對應的值需要對應目前使用的Zookeeper的ip位址和端口号
重新開機Tomcat
打包前端項目;dubbo-admin-ui
然後使用nginx進行代理
連通背景項目即可
服務提供者和服務消費者都需要配置,表示包掃描,作用是掃描指定包(包括子包)下的類。
如果不使用包掃描,也可以通過如下配置的方式來釋出服務:
作為服務消費者,可以通過如下配置來引用服務:
上面這種方式釋出和引用服務,一個配置項(dubbo:service、dubbo:reference)隻能釋出或者引用一個服務,如果有多個服務,這種方式就比較繁瑣了。推薦使用包掃描方式。
一般在服務提供者一方配置,可以指定使用的協定名稱和端口号。
其中Dubbo支援的協定有:dubbo、rmi、hessian、http、webservice、rest、redis等。
推薦使用的是dubbo協定。
dubbo 協定采用單一長連接配接和 NIO 異步通訊,适合于小資料量大并發的服務調用,以及服務消費者機器數遠大于服務提供者機器數的情況。不适合傳送大資料量的服務,比如傳檔案,傳視訊等,除非請求量很低。
也可以在同一個工程中配置多個協定,不同服務可以使用不同的協定,例如:
上面這個配置需要配置在服務消費者一方,如果不配置預設check值為true。Dubbo 預設會在啟動時檢查依賴的服務是否可用,不可用時會抛出異常,阻止 Spring 初始化完成,以便上線時,能及早發現問題。可以通過将check值改為false來關閉檢查。
建議在開發階段将check值設定為false,在生 産環境下改為true。
負載均衡(Load Balance):其實就是将請求分攤到多個操作單元上進行執行,進而共同完成工作任務。
在叢集負載均衡時,Dubbo 提供了多種均衡政策(包括随機、輪詢、最少活躍調用數、一緻性Hash),預設為random随機調用。
配置負載均衡政策,既可以在服務提供者一方配置,也可以在服務消費者一方配置,如下:
可以通過啟動多個服務提供者來觀察Dubbo負載均衡效果。
注意:因為我們是在一台機器上啟動多個服務提供者,是以需要修改tomcat的端口号和Dubbo服務的端口号來防止端口沖突。
在實際生産環境中,多個服務提供者是分别部署在不同的機器上,是以不存在端口沖突問題。
已經完成了Dubbo的入門,通過入門可以看到通過Dubbo提供的标簽配置就可以進行包掃描,掃描到@Service注解的類就可以被釋出為服務。
但是如果在服務提供者類上加入@Transactional事務控制注解後,服務就釋出不成功了。原因是事務控制的底層原理是為服務提供者類建立代理對象,而預設情況下Spring是基于JDK動态代理方式建立代理對象,而此代理對象的完整類名為com.sun.proxy.$Proxy42(最後兩位數字不是固定的),導緻Dubbo在釋出服務前進行包比對時無法完成比對,進而沒有進行服務的釋出。
在案例的服務提供者demo-dubbo工程基礎上進行展示
操作步驟
在pom.xml檔案中增加maven坐标
(2)在applicationContext-service.xml配置檔案中加入資料源、事務管理器、開啟事務注解的相關配置
上面連接配接的資料庫可以自行建立
(3)在HelloServiceImpl類上加入@Transactional注解
(4)啟動服務提供者和服務消費者,并通路
上面的錯誤為沒有可用的服務提供者
檢視dubbo管理控制台發現服務并沒有釋出,如下:
可以通過斷點調試的方式檢視Dubbo執行過程,Dubbo通過AnnotationBean的postProcessAfterInitialization方法進行處理
通過上面的斷點調試可以看到,在HelloServiceImpl類上加入事務注解後,Spring會為此類基于JDK動态代理技術建立代理對象,建立的代理對象完整類名為com.sun.proxy.$Proxy35,導緻Dubbo在進行包比對時沒有成功(因為我們在釋出服務時掃描的包為com.itheima.service),是以後面真正釋出服務的代碼沒有執行。
解決方式操作步驟:
(1)修改applicationContext-service.xml配置檔案,開啟事務控制注解支援時指定proxy-target-class屬性,值為true。其作用是使用cglib代理方式為Service類建立代理對象
(2)修改HelloServiceImpl類,在Service注解中加入interfaceClass屬性,值為HelloService.class,作用是指定服務的接口類型
此處也是必須要修改的,否則會導緻釋出的服務接口為SpringProxy,而不是HelloService接口,如下: