SpringCloud輕松集成Dubbo實現(xiàn)RPC調(diào)用

很久之前在做微服務(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)與注冊,同時兼容使用Feignhttp方式和使用Dubborpc方式調(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)

image
  • cloud-gateway 作為cloud集群的網(wǎng)關(guān),外部的路由轉(zhuǎn)發(fā)使用http協(xié)議,內(nèi)部的服務(wù)調(diào)用使用dubbo協(xié)議
  • cloud-usercloud-mq之間的遠(yuǎn)程調(diào)用使用dubbo協(xié)議
  • 使用Nacos作為服務(wù)注冊與發(fā)現(xiàn)配置中心的服務(wù)
  • 使用Sentinel作為服務(wù)間httpdubbo調(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é)

  1. 服務(wù)間使用了長連接,在正常運(yùn)行時,提供方某個節(jié)點(diǎn)斷掉后會需要一段時間來切換,可使用sentinel來控制快速切換可用節(jié)點(diǎn)
  2. 使用dubbo進(jìn)行遠(yuǎn)程調(diào)用,內(nèi)部調(diào)用性能上有所提供,調(diào)用方式上也相對簡單
  3. sentinel配合,合理使用負(fù)載策略,可實現(xiàn)更多功能,如灰度發(fā)布,版本控制等
  4. 性能的提升讓調(diào)用鏈增加成為可能性,可實現(xiàn)更小粒度的微服務(wù)拆分與組合

五、源代碼

https://gitee.com/hypier/barry-cloud

六、請關(guān)注我的公眾號

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容