很久之前在做微服務(wù)架構(gòu)選型的時候就聽說阿里的微服務(wù)RPC框架dubbo,當(dāng)時與Spring Cloud以http協(xié)議調(diào)用的架構(gòu)做對比。發(fā)現(xiàn)dubbo的rpc框架學(xué)習(xí)成本較高,代碼入侵性強(qiáng),本身生態(tài)不完整,需要整合多個外部組件,故選擇了相對性能弱一點(diǎn)的Spring Cloud全家桶。
直到Spring Cloud Alibaba的出現(xiàn),使用Nacos作為服務(wù)發(fā)現(xiàn)與注冊,同時兼容使用Feign的http方式和使用Dubbo的rpc方式調(diào)用。
Spring Cloud 為什么需要RPC
在Spring Cloud構(gòu)建的微服務(wù)系統(tǒng)中,大多數(shù)的開發(fā)者使用都是官方提供的Feign組件來進(jìn)行內(nèi)部服務(wù)通信,這種聲明式的HTTP客戶端使用起來非常的簡潔、方便、優(yōu)雅,并且和開發(fā)平臺、語言無關(guān),但是通常情況下,HTTP并不會開啟KeepAlive功能,即當(dāng)前連接為短連接,短連接的缺點(diǎn)是每次請求都需要建立TCP連接,這使得其效率變的相當(dāng)?shù)拖隆?/p>
對外部提供REST API服務(wù)是一件非常好的事情,但是如果內(nèi)部調(diào)用也是使用HTTP調(diào)用方式,就會顯得顯得性能低下,Spring Cloud默認(rèn)使用的Feign組件進(jìn)行內(nèi)部服務(wù)調(diào)用就是使用的HTTP協(xié)議進(jìn)行調(diào)用,這時,我們?nèi)绻麅?nèi)部服務(wù)使用RPC調(diào)用,對外使用REST API,將會是一個非常不錯的選擇。
引用至:Dubbo 與 Spring Cloud 完美結(jié)合
使用Dubbo Spring Cloud使用內(nèi)部的RPC協(xié)議調(diào)用幾乎是零成本的改造。
一、系統(tǒng)結(jié)構(gòu)

-
cloud-gateway作為cloud集群的網(wǎng)關(guān),外部的路由轉(zhuǎn)發(fā)使用http協(xié)議,內(nèi)部的服務(wù)調(diào)用使用dubbo協(xié)議 -
cloud-user和cloud-mq之間的遠(yuǎn)程調(diào)用使用dubbo協(xié)議 - 使用
Nacos作為服務(wù)注冊與發(fā)現(xiàn)和配置中心的服務(wù) - 使用
Sentinel作為服務(wù)間http和dubbo調(diào)用的流量控制服務(wù)
目錄結(jié)構(gòu)
├── cloud-admin # 服務(wù)監(jiān)控
├── cloud-gateway # 服務(wù)網(wǎng)關(guān)
├── cloud-mq # mq服務(wù)
├── cloud-provider # 服務(wù)接口
└── cloud-user # user服務(wù)
二、服務(wù)接口提供方實現(xiàn)
1. 服務(wù)接口定義
public interface UserProvider {
UserDTO checkUser(String userName, String password);
UserDTO findByUserName(String userName);
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UserDTO implements Serializable {
String userName;
String realName;
String password;
}
- 服務(wù)接口是服務(wù)提供方和消費(fèi)方的契約,包含服務(wù)的方法傳輸對象DTO。由于涉及多個應(yīng)用服務(wù)的引入,最好是將其獨(dú)立成Module
- DTO對象必須實現(xiàn)
Serializable接口
2. 引入dubbo包
POM
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-dubbo</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
spring-boot-starter-actuator 也是必須的
3. 服務(wù)接口實現(xiàn)
import org.apache.dubbo.config.annotation.Service;
@Service
public class UserProviderImpl implements UserProvider {
@Autowired
private UserService userService;
@Override
public UserDTO checkUser(String userName, String password) {
User user = userService.checkUser(userName, password);
return UserConvertor.toDTO(user);
}
}
@Service必須是org.apache.dubbo.config.annotation.Service
4. 配置Dubbo服務(wù)相關(guān)的信息
spring:
main:
allow-bean-definition-overriding: true
dubbo:
scan:
base-packages: fun.barryhome.cloud.provider #指定 Dubbo 服務(wù)實現(xiàn)類的掃描基準(zhǔn)包
protocols:
dubbo:
name: dubbo # Dubbo 的協(xié)議名稱
port: -1 # port 為協(xié)議端口( -1 表示自增端口,從 20880 開始)
registry:
address: spring-cloud://localhost # 掛載到 Spring Cloud 注冊中心
啟動后有可能出現(xiàn)連接失敗,不影響使用
java.net.ConnectException: Connection refused (Connection refused)
at java.net.PlainSocketImpl.socketConnect(Native Method) ~[na:1.8.0_111]
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350) ~[na:1.8.0_111]
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206) ~[na:1.8.0_111]
三、服務(wù)調(diào)用方實現(xiàn)
1. 引入依賴包
<!--服務(wù)接口-->
<dependency>
<groupId>fun.barryhome</groupId>
<artifactId>cloud-provider</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-dubbo</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
2. 調(diào)用服務(wù)接口
import org.apache.dubbo.config.annotation.Reference;
public class UserController {
@Reference
private UserProvider userProvider;
@GetMapping(value = "/sessionUser")
public UserDTO sessionUser(HttpServletRequest request) {
String userName = request.getHeader("X-User-Name");
if (Strings.isEmpty(userName)) {
throw new RuntimeException("沒有找到用戶");
}
return userProvider.findByUserName(userName);
}
}
3. 配置Dubbo服務(wù)相關(guān)的信息
dubbo:
cloud:
subscribed-services: cloud-user # 服務(wù)提供方的服務(wù)名
consumer:
check: false
loadbalance: "leastactive" # 最小活躍數(shù)負(fù)載均衡
registry:
# 掛載到 Spring Cloud 注冊中心
address: spring-cloud://localhost
dubbo.consumer.check:用于啟動時是否檢查服務(wù)提供方是否運(yùn)行正常,如果不正常將不能啟動調(diào)用方
dubbo.consumer.loadbalance:負(fù)載均衡策略
- RandomLoadBalance:隨機(jī),按權(quán)重設(shè)置隨機(jī)概率
- ConsistentHashLoadBalance:一致性哈希算法
- LeastActiveLoadBalance:最小活躍數(shù)負(fù)載均衡
- RoundRobinLoadBalance:根據(jù)權(quán)重進(jìn)輪訓(xùn)
四、總結(jié)
- 服務(wù)間使用了長連接,在正常運(yùn)行時,提供方某個節(jié)點(diǎn)斷掉后會需要一段時間來切換,可使用
sentinel來控制快速切換可用節(jié)點(diǎn) - 使用dubbo進(jìn)行遠(yuǎn)程調(diào)用,內(nèi)部調(diào)用性能上有所提供,調(diào)用方式上也相對簡單
- 與
sentinel配合,合理使用負(fù)載策略,可實現(xiàn)更多功能,如灰度發(fā)布,版本控制等 - 性能的提升讓調(diào)用鏈增加成為可能性,可實現(xiàn)更小粒度的微服務(wù)拆分與組合
五、源代碼
https://gitee.com/hypier/barry-cloud