1、單體應(yīng)用介紹:
所謂單體應(yīng)用,就是一些小型的應(yīng)用,一個(gè)系統(tǒng)就是eclipse中的一個(gè)工程,然后打一個(gè)jar包或者war運(yùn)行,這個(gè)jar包或者war就是整個(gè)系統(tǒng)服務(wù)。這就叫單體應(yīng)用。
2、分布式系統(tǒng)介紹:
如果項(xiàng)目小,那么單體應(yīng)用就可以了,如果項(xiàng)目很復(fù)雜,訪問量特別多,還是打一個(gè)包的話,那可能就會(huì)崩掉了。所以就出現(xiàn)了分布式系統(tǒng)。就是把項(xiàng)目中的不同的功能模塊獨(dú)立成一個(gè)系統(tǒng),單獨(dú)部署。比如京東商城,把訂單系統(tǒng)部署到A服務(wù)器,用戶系統(tǒng)部署到B服務(wù)器……這樣的就叫分布式系統(tǒng)。說白了,就是把一個(gè)大系統(tǒng)分成各個(gè)功能模塊,然后把不同的功能模塊部署到不同的計(jì)算機(jī)上。
3、分布式和微服務(wù):
微服務(wù)是一種思想,就是上面說的把大系統(tǒng)拆分成不同的功能模塊,做成一個(gè)個(gè)的服務(wù),然后這些服務(wù)協(xié)調(diào)運(yùn)作,對(duì)外提供一個(gè)完整的大的系統(tǒng)的服務(wù)。若是把這些不同的功能模塊部署到不同的計(jì)算機(jī),那就叫分布式
1、dubbo是干嘛的?
上面說到了分布式系統(tǒng),把功能模塊獨(dú)立部署在不同的計(jì)算機(jī)上,但是這些功能模塊相互之間可能也會(huì)相互調(diào)用。比如訂單模塊部署在A計(jì)算機(jī),用戶模塊部署在B計(jì)算機(jī),訂單模塊需要調(diào)用用戶模塊查詢用戶的收貨地址等信息。dubbo就是用來治理這些不同的功能模塊的。
2、RPC是什么?
RPC中文名叫遠(yuǎn)程過程調(diào)用。上面說了不同的功能模塊部署在不同的計(jì)算機(jī)上,然后它們又要相互調(diào)用,那么就可以采用RPC。也就是A計(jì)算機(jī)上的訂單模塊要調(diào)用B計(jì)算機(jī)上的用戶模塊,我們可以采用的調(diào)用方法之一就叫RPC。RPC就是A和B兩臺(tái)計(jì)算機(jī)之間通過sockets進(jìn)行通信。上面說到dubbo就是來治理這些服務(wù),其實(shí)dubbo就是一個(gè)RPC調(diào)度框架。一個(gè)RPC框架性能如何,主要看兩點(diǎn)。第一:建立socket連接的速度快不快;第二:訂單模塊調(diào)用用戶模塊的時(shí)候要傳參數(shù),參數(shù)可能是對(duì)象,對(duì)象要在網(wǎng)絡(luò)上傳輸就要序列化。所以第二點(diǎn)就是看序列化和反序列化的速度快不快。
3、dubbo智能負(fù)載均衡:
比如用戶模塊壓力比較大,那就再多搞幾臺(tái)計(jì)算機(jī)來部署用戶模塊。假設(shè)現(xiàn)在有B、C、D、E四臺(tái)計(jì)算機(jī)運(yùn)行著用戶模塊,那么一個(gè)請(qǐng)求過來是到了這四臺(tái)計(jì)算機(jī)中的哪一臺(tái)呢?dubbo就會(huì)自動(dòng)選擇一臺(tái)請(qǐng)求比較少的計(jì)算機(jī)。這就叫智能負(fù)載均衡
1、注冊(cè)中心是什么?
上面說了dubbo會(huì)智能地選擇BCDE四臺(tái)計(jì)算機(jī)中比較空閑的一臺(tái)去響應(yīng)請(qǐng)求,那么dubbo是如何知道這四臺(tái)計(jì)算機(jī)哪一臺(tái)比較閑呢?又或者說其中有一臺(tái)計(jì)算機(jī)不能正常工作了,dubbo要如何知道這件事呢?這就引入了注冊(cè)中心。A計(jì)算機(jī)告訴注冊(cè)中心它可以提供訂單模塊的功能,BCDE計(jì)算告訴注冊(cè)中心它可以提供用戶模塊的功能。也就說,注冊(cè)中心就維護(hù)了一個(gè)清單,清單上寫著哪臺(tái)計(jì)算機(jī)可以提供什么服務(wù)。比如現(xiàn)在A服務(wù)器的訂單模塊要調(diào)用用戶模塊時(shí),dubbo就會(huì)去問注冊(cè)中心:“用戶模塊在哪些服務(wù)器上有?” 注冊(cè)中心就會(huì)告訴dubbo:“在BCDE上都有?!?dubbo就會(huì)選擇一個(gè)負(fù)載最少的去調(diào)用。dubbo支持很多注冊(cè)中心,一般使用zookeeper。
2、dubbo運(yùn)行流程:
把服務(wù)注冊(cè)到注冊(cè)中心 ------> 訂閱注冊(cè)中心的服務(wù) --------> dubbo框架進(jìn)行RPC調(diào)用。同時(shí)dubbo還有監(jiān)控中心,可以監(jiān)控各個(gè)服務(wù)狀況。
3、安裝zookeeper:
去官網(wǎng)下載zookeeper ------> 解壓后去conf目錄,復(fù)制zoo_sample.cfg文件,改名為 zoo.conf,放在conf目錄下 ------> 去bin目錄下運(yùn)行zkServer.cmd即可啟動(dòng),運(yùn)行zkCli.cmd就可啟動(dòng)客戶端
需求:現(xiàn)在訂單模塊和用戶模塊。訂單模塊在A服務(wù)器,用戶模塊在B服務(wù)器。A的訂單模塊遠(yuǎn)程調(diào)用B的用戶模塊。
上面介紹了dubbo和注冊(cè)中心,現(xiàn)在就看看在項(xiàng)目中實(shí)際應(yīng)該如何使用,話不多說,開打。
1、項(xiàng)目的結(jié)構(gòu):
根據(jù)需求,訂單服務(wù)是一個(gè)獨(dú)立的工程,用戶服務(wù)是一個(gè)獨(dú)立的工程,然后訂單服務(wù)中要調(diào)用用戶服務(wù),例如在訂單服務(wù)的某個(gè)方法中肯定要用到UserService。但是UserService是在用戶服務(wù)工程中的,怎么調(diào)用?直接把用戶工程打jar包依賴過來嗎?那這樣就不是分布式應(yīng)用了。正確的做法是:
將兩個(gè)工程中要用到的接口、實(shí)體類等抽取出來獨(dú)立成一個(gè)工程,具體的實(shí)現(xiàn)放到對(duì)應(yīng)的具體工程中去。
2、common-api 工程:
這就是用戶服務(wù)和訂單服務(wù)會(huì)共用到的一些東西,放在這個(gè)工程中,然后打jar包,讓用戶服務(wù)工程和訂單服務(wù)工程依賴即可。
UserAddress.java
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserAddress implements Serializable {
private Integer id;
private String userAddress;
private String phoneNumber;
}
OrderService.java
public interface OrderService {
public List<UserAddress> initOrder(String userId);
}
UserService.java
public interface UserService {
public List<UserAddress> getUserAddressList(String userId);
}
3、user-service 工程:
pom.xml
<!-- dubbo依賴 -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>2.7.2</version>
</dependency>
<!-- zookeeper注冊(cè)中心 -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.12.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.12.0</version>
</dependency>
UserServiceImpl.java
@Service
public class UserServiceImpl implements UserService {
@Override
public List<UserAddress> getUserAddressList(String userId) {
if (userId.equals("1")){
UserAddress userAddress1 = new UserAddress(1, "廣東省深圳市寶安區(qū)","8008208820");
UserAddress userAddress2 = new UserAddress(2, "廣東省東莞市厚街鎮(zhèn)","8008208820");
return Arrays.asList(userAddress1,userAddress2);
}
else return null;
}
}
接下來就需要在xml文件中將這個(gè)用戶服務(wù)注冊(cè)到注冊(cè)中心去。
provider.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://dubbo.apache.org/schema/dubbo"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://dubbo.apache.org/schema/dubbo
http://dubbo.apache.org/schema/dubbo/dubbo.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<context:component-scan base-package="com.zhu.study.service"/>
<!-- 1、指定當(dāng)前服務(wù)/應(yīng)用的名字(同樣的服務(wù)名字相同,不要和別的服務(wù)同名) -->
<dubbo:application name="user-service"></dubbo:application>
<!-- 2、指定注冊(cè)中心的位置 -->
<!-- <dubbo:registry address="zookeeper://127.0.0.1:2181"></dubbo:registry> -->
<dubbo:registry protocol="zookeeper" address="127.0.0.1:2181"></dubbo:registry>
<!-- 3、指定通信規(guī)則(通信協(xié)議?通信端口)服務(wù)提供者和調(diào)用者通信規(guī)則 -->
<dubbo:protocol name="dubbo" port="20882"></dubbo:protocol>
<!-- 4、暴露服務(wù) ref:指向服務(wù)的真正的實(shí)現(xiàn)對(duì)象 -->
<dubbo:service interface="com.zhu.study.service.UserService"
ref="userServiceImpl" timeout="1000" version="1.0.0">
<dubbo:method name="getUserAddressList" timeout="1000"/>
</dubbo:service>
</beans>
在這個(gè)配置文件中,首先給這個(gè)服務(wù)起個(gè)名字,然后注冊(cè)到2181端口的注冊(cè)中心去,再指定通信規(guī)則和端口,最后把用戶模塊的UserService暴露出去,同時(shí)用ref引用實(shí)現(xiàn)類。當(dāng)然這個(gè)UserServiceImpl需要加入到spring容器中。
App.java
現(xiàn)在編寫啟動(dòng)類,加載配置文件。
public class App
{
public static void main( String[] args ) throws IOException {
ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("provider.xml");
ioc.start();
System.in.read(); // 保留啟動(dòng)的狀態(tài)
}
}
運(yùn)行這個(gè)啟動(dòng)類的前提是注冊(cè)中心zookeeper啟動(dòng)起來了。運(yùn)行之后,訪問管理控制臺(tái)就可以看到服務(wù)了(去dubbo的GitHub地址,找到dubbo-admin項(xiàng)目,下載下來,然后用maven打個(gè)jar運(yùn)行,這就是管理控制臺(tái))。
可以看到user-service已經(jīng)成功注冊(cè)到zookeeper了。接下來就要在訂單服務(wù)中調(diào)用它了。
4、order-service 工程:
OrderServiceImpl.java
@Service
public class OrderServiceImpl implements OrderService {
@Resource
private UserService userService;
@Override
public List<UserAddress> initOrder(String userId) {
// 查詢用戶收獲地址
List<UserAddress> addressesList = userService.getUserAddressList(userId);
return addressesList;
}
}
consumer.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://dubbo.apache.org/schema/dubbo"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://dubbo.apache.org/schema/dubbo
http://dubbo.apache.org/schema/dubbo/dubbo.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<context:component-scan base-package="com.zhu.study.service"/>
<dubbo:application name="order-service"/>
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<dubbo:reference interface="com.zhu.study.service.UserService"
id="userService" timeout="5000" retries="3" version="*">
</dubbo:reference>
</beans>
這里的配置,第一行是開啟注解掃描,然后給訂單服務(wù)起個(gè)名字,第三步是注冊(cè)到zookeeper中去,第四步是引用UserService。這樣就完事了,然后寫個(gè)測(cè)試類試試水。
App.java
public class App
{
public static void main( String[] args ) throws IOException {
ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("consumer.xml");
OrderService orderService = ioc.getBean(OrderService.class);
List<UserAddress> userAddresses = orderService.initOrder("1");
for (UserAddress userAddress : userAddresses){
System.out.println(userAddress.toString());
}
System.in.read();
}
}
可以看到,成功地調(diào)用了UserService服務(wù)。同時(shí)在管理控制臺(tái)也可以看到調(diào)用者的信息
同樣是order模塊和user模塊,看看怎么與springboot整合起來。
1. 引入 dubbo-spring-boot-starter 依賴;
2. 在啟動(dòng)類上加上如下注解;
@EnableDubbo
@SpringBootApplication
public class SpringbootOrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootOrderServiceApplication.class, args);
}
}
3. 將provider.xml 和 consumer.xml中的配置寫在application.properties中,如下:
dubbo.application.name=springboot-user-service
dubbo.registry.address=127.0.0.1:2181
dubbo.registry.protocol=zookeeper
dubbo.protocol.name=dubbo
dubbo.protocol.port=20080
dubbo.monitor.protocol=registry
dubbo.application.name=springboot-order-service
dubbo.registry.address=127.0.0.1:2181
dubbo.registry.protocol=zookeeper
dubbo.protocol.name=dubbo
dubbo.protocol.port=20080
dubbo.monitor.protocol=registry
4. 服務(wù)提供者使用dubbo的 @Service 注解暴露服務(wù), 服務(wù)消費(fèi)者使用 @Reference 調(diào)用提供者,如下:
@Service
@Component
public class UserServiceImpl implements UserService {
@Override
public List<UserAddress> getUserAddressList(String userId) {
if (userId.equals("1")){
UserAddress userAddress1 = new UserAddress(1, "廣東省深圳市寶安區(qū)","8008208820");
UserAddress userAddress2 = new UserAddress(2, "廣東省東莞市厚街鎮(zhèn)","8008208820");
return Arrays.asList(userAddress1,userAddress2);
}
else return null;
}
}
@Service
public class OrderServiceImpl implements OrderService {
@Reference
private UserService userService;
@Override
public List<UserAddress> initOrder(String userId) {
// 查詢用戶收獲地址
System.out.println(userService);
List<UserAddress> addressesList = userService.getUserAddressList(userId);
return addressesList;
}
}
注意: @Reference(url = "dubbo://服務(wù)提供者所在的機(jī)器IP:通信端口"),如果這個(gè)注解加上url,那么就表示繞過注冊(cè)中心,使用dubbo直連的方式,即這樣寫了的話沒有zookeeper都可以
上面簡(jiǎn)單地介紹了分布式架構(gòu)的思想以及dubbo的簡(jiǎn)單使用,更多dubbo的配置規(guī)則,請(qǐng)參考dubbo官網(wǎng)的開發(fā)手冊(cè)。
聯(lián)系客服