当前位置: 首页>编程语言>正文

springboot单体服务划分模块 springboot double服务框架

Dubbo 是一个开源分布式服务框架,致力于提供高性能和透明化的 RPC 远程服务调用方案以及 SOA 服务治理方案。Dubbo 采用全 Spring 配置方式,透明化接入应用,对应用没有任何 API 侵入,只需用 Spring 加载 Dubbo 的配置即可,Dubbo 基于 Spring 的 Schema 扩展进行加载。Dubbo 推荐的注册中心是 ZooKeeper。

springboot单体服务划分模块 springboot double服务框架,springboot单体服务划分模块 springboot double服务框架_rpc,第1张

调用关系说明:

  1. 服务容器负责启动、加载、运行服务提供者,服务提供者在启动时向注册中心注册自己提供的服务;
  2. 服务消费者在启动时,向注册中心订阅自己所需的服务;
  3. 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长链接推送变更数据给消费者;
  4. 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用;
  5. 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。

Dubbo 架构具有以下几个特点:

Dubbo特点

说明

连通性

1)注册中心负责服务地址的注册与查找,相当于目录服务,服务提供者和消费者只在启动时与注册中心交互,注册中心不转发请求,压力较小;

2)监控中心负责统计各服务调用次数,调用时间等,统计先在内存汇总后每分钟一次发送到监控中心服务器,并以报表展示;

3)服务提供者向注册中心注册其提供的服务,并汇报调用时间到监控中心,此时间不包含网络开销;

4)服务消费者向注册中心获取服务提供者地址列表,并根据负载算法直接调用提供者,同时汇报调用时间到监控中心,此时间包含网络开销;

5)注册中心,服务提供者,服务消费者三者之间均为长连接,监控中心除外;

6)注册中心通过长连接感知服务提供者的存在,服务提供者宕机,注册中心将立即推送事件通知消费者;

7)注册中心和监控中心全部宕机,不影响已运行的提供者和消费者,消费者在本地缓存了提供者列表;

8)注册中心和监控中心都是可选的,服务消费者可以直连服务提供者。

健状性

1)监控中心宕掉不影响使用,只是丢失部分采样数据;

2)数据库宕掉后,注册中心仍能通过缓存提供服务列表查询,但不能注册新服务;

3)注册中心对等集群,任意一台宕掉后,将自动切换到另一台;

4)注册中心全部宕掉后,服务提供者和服务消费者仍能通过本地缓存通讯;

5)服务提供者无状态,任意一台宕掉后,不影响使用;

6)服务提供者全部宕掉后,服务消费者应用将无法使用,并无限次重连等待服务提供者恢复。

伸缩性

1)注册中心为对等集群,可动态增加机器部署实例,所有客户端将自动发现新的注册中心;

2)服务提供者无状态,可动态增加机器部署实例,注册中心将推送新的服务提供者信息给消费者。

升级性

当服务集群规模进一步扩大,带动IT治理结构进一步升级,需要实现动态部署,进行流动计算,现有分布式服务架构不会带来阻力。下图是未来可能的一种架构:

节点角色说明:

Deployer:自动部署服务的本地代理

Repository:仓库用于存储服务应用发布包

Scheduler:调度中心基于访问压力自动增减服务提供者

Admin:统一管理控制台

Registry:服务注册与发现的注册中心

Monitor:统计服务的调用次数和调用时间的监控中心

springboot单体服务划分模块 springboot double服务框架,springboot单体服务划分模块 springboot double服务框架_spring boot_02,第2张

Dubbo 核心如下:

Dubbo核心

说明

远程通讯

提供对多种基于长连接的NIO框架抽象封装,包括多种线程模型,序列化,以及“请求-响应”模式的信息交换方式

集群容错

提供基于接口方法的透明远程过程调用,包括多协议支持,以及软负载均衡,失败容错,地址路由,动态配置等集群支持

自动发现

基于注册中心目录服务,使服务消费方能动态的查找服务提供方,使地址透明,使服务提供方可以平滑增加或减少机器

Dubbo 通讯协议推荐使用 Dubbo 协议(dubbo://)。Dubbo 协议采用单一长连接和 NIO 异步通讯,使用基于 mina 1.1.7 和 hessian 3.2.1 的 tbremoting 交互。适合于小数据量大并发的服务调用,以及服务消费者机器数远大于服务提供者机器数的情况。反之,Dubbo 协议不适合传送大数据量的服务,比如传文件,传视频等,除非请求量很低。

springboot单体服务划分模块 springboot double服务框架,springboot单体服务划分模块 springboot double服务框架_dubbo_03,第3张

dubbo://

说明

连接个数

单连接

连接方式

长连接

传输协议

TCP

传输方式

NIO 异步传输

序列化

Hessian 二进制序列化

适用范围

传入传出参数数据包较小(建议小于100K),消费者比提供者个数多,单一消费者无法压满提供者,尽量不要用 dubbo 协议传输大文件或超大字符串。

适用场景

常规远程服务方法调用

关于 Dubbo 管理控制台的安装(Dubbo管理控制台的主要作用是服务治理,包含服务注册、服务降级、路由规则、访问控制、动态配置、权重调节、负载均衡、服务负责人、等管理功能。)请参考 dubbo-admin。

使用 Dubbo 服务提供者 (provider) 和消费者 (consumer) 需要添加 Maven 依赖:

<!-- dubbo -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>dubbo</artifactId>
    <version>2.6.2</version>
    <exclusions>
        <exclusion>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-framework</artifactId>
    <version>2.12.0</version>
    <exclusions>
        <exclusion>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
        </exclusion>
    </exclusions>
</dependency>

1.Dubbo的使用

1.服务接口(API)

api(服务接口,服务模型,服务异常)需单独打包,服务提供方和消费方依赖于 api。api 对服务消费方隐藏实现。下来定义统一服务接口 (如果返回的是 pojo,pojo 必须实现 Serializable 接口):

public interface DemoService {
    String sayHello(String name);
}

2.服务提供者(Provider)

在服务提供方实现接口:

import org.springframework.stereotype.Service;
@Service
public class DemoServiceImpl implements DemoService {
    @Override
    public String sayHello(String name) {
        return "Hello, " + name;
    }
}

在 Provider 上尽量多配置 Consumer 端属性,在 Provider 配置后,Consumer 不配置则会使用 Provider 的配置值,即 Provider 配置可以作为 Consumer 的缺省值。否则,Consumer 会使用 Consumer 端的全局设置,这对于 Provider 不可控的,并且往往是不合理的。在 Provider 上可以配置的 Consumer 端属性有:

属性

说明

timeout

方法调用超时。

retries

失败重试次数,缺省是 2。

loadbalance

负载均衡算法,缺省是随机 random,还可以有轮询 roundrobin、最不活跃优先 leastactive。

actives

消费者端最大并发调用限制,缺省是 0,不限制。即当 Consumer 对一个服务的并发调用到上限后,新调用会等待,直到超时。

配置声明暴露服务 resources/spring-config-dubbo.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://code.alibabatech.com/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

    <!-- 提供方应用信息,用于计算依赖关系 -->
    <dubbo:application name="dubbo-demo-provider"/>
    <!-- 使用zookeeper注册中心暴露服务地址,多个地址逗号隔开 -->
    <dubbo:registry client="curator" protocol="zookeeper" address="127.0.0.1:2181"/>
    <!-- 用dubbo协议在20880端口暴露服务 -->
    <dubbo:protocol name="dubbo" port="20880"/>

    <import resource="spring-config-dubbo-provider.xml"/>
</beans>

resources/spring-config-dubbo-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://code.alibabatech.com/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

    <!-- 声明需要暴露的服务接口 -->
    <dubbo:service interface="com.example.server.soa.service.DemoService" group ="bj" version="1.0.0" ref="demoServiceImpl"
                   timeout="200" retries="2" loadbalance="random" actives="0"/>
</beans>

然后在项目启动类中导入配置即可:

@SpringBootApplication
@ImportResource(
        "classpath:spring-config-dubbo.xml"
)

3.服务消费者(Consumer)

配置引用远程服务 resources/spring-config-rpc-dubbo.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://code.alibabatech.com/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

    <!-- 消费方应用名,用于计算依赖关系,不是匹配条件,不要与提供方一样 -->
    <dubbo:application name="dubbo-demo-consumer"/>
    <!-- 使用zookeeper注册中心暴露发现服务地址,多个地址逗号隔开 -->
    <dubbo:registry client="curator" protocol="zookeeper" address="127.0.0.1:2181"/>

    <import resource="spring-config-rpc-dubbo-consumer.xml"/>
</beans>

resources/spring-config-rpc-dubbo-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://code.alibabatech.com/schema/dubbo"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">

    <!-- 生成远程服务代理,可以和本地bean一样使用demoService -->
    <dubbo:reference id="demoService" interface="com.example.server.soa.service.DemoService" group ="bj" version="1.0.0"/>
</beans>

然后在项目启动类中导入配置即可:

@SpringBootApplication
@ImportResource(
        "classpath:spring-config-rpc-dubbo.xml"
)

接下来开始调用远程服务:

@RestController
public class DemoController {
    @Resource
    private DemoService demoService;

    @RequestMapping("/sayHello")
    public String sayHello(@RequestParam String name) {
        return demoService.sayHello(name);
    }
}

分别运行 Provider 和 Consumer 工程,浏览器访问 Consumer 对外提供的 RESTful API,即可成功调用远程服务。这里我们也可以看出,Dubbo 对应用没有任何 API 侵入。官方 schema 配置参考手册。

2.服务化最佳实践

-

说明

粒度

1)服务接口尽可能大粒度,每个服务方法应代表一个功能,而不是某功能的一个步骤,否则将面临分布式事务问题,Dubbo 暂未提供分布式事务支持;

2)服务接口建议以业务场景为单位划分,并对相近业务做抽象,防止接口数量爆炸。

版本

1)每个接口都应定义版本号,为后续不兼容升级提供可能;

2)建议使用两位版本号,因为第三位版本号通常表示兼容升级,只有不兼容时才需要变更服务版本;

3)当不兼容时,先升级一半提供者为新版本,再将消费者全部升为新版本,然后将剩下的一半提供者升为新版本。

异常

1)建议使用异常汇报错误,而不是返回错误码,异常信息能携带更多信息,以及语义更友好。

2)如果担心性能问题,在必要时,可以通过 override 掉异常类的 fillInStackTrace() 方法为空方法,使其不拷贝栈信息。

3)查询方法不建议抛出 checked 异常,否则调用方在查询时将过多的 try…catch,并且不能进行有效处理。

4)服务提供方不应将 DAO 或 SQL 等异常抛给消费方,应在服务实现中对消费方不关心的异常进行包装,否则可能出现消费方无法反序列化相应异常。

3.在Linux上部署Dubbo服务

部署目录规范(要避免应用迁移时的路径冲突):

/home/wwwroot/example/
		        |- /app             //部署app
		             |- /app1
		             |- /app2
			    |- /service         //部署分布式服务
			         |- /order      //订单服务
			         |- /queue      //消息队列服务
			         |- /user       //用户服务
			    |- /timer           //部署定时任务
			         |- /report     //报表
			    |- /web             //部署web工程
			         |- /gateway
			         |- /operation
			         |- /portal

手工维护 Dubbo 服务(有时会报映射错误,主机名ip映射可通过 vim /etc/hosts 配置):

# java -jar xxx.jar &                       //启动服务

# nohup java -jar xxx.jar &                 //加日志启动
# tail -f nohup.out                         //查看启动日志

# ps -ef | grep java                        //第一个数字就是PID
# kill PID                                  //杀死服务
# kill -9 PID

自定义 Dubbo 服务维护的 Shell 脚本(命名规范:/home/wwwroot/example/xxx/service-xxx.sh):

#!/bin/sh

## java env
export JAVA_HOME=/usr/local/jdk
export JRE_HOME=$JAVA_HOME/jre

## service name
APP_NAME=user

SERVICE_DIR=/home/wwwroot/example/service/$APP_NAME
SERVICE_NAME=dubbo-service-$APP_NAME
JAR_NAME=$SERVICE_NAME\.jar
PID=$SERVICE_NAME\.pid

cd $SERVICE_DIR

case "" in

    start)
        ## debug:-Xms256m-Xmx512m,formal:-Xms512m-Xmx2048m
        nohup $JRE_HOME/bin/java -Xms256m -Xmx512m -jar $JAR_NAME >/dev/null 2>&1 &
        echo $! > $SERVICE_DIR/$PID
        echo "=== start $SERVICE_NAME"
        ;;

    stop)
        kill `cat $SERVICE_DIR/$PID`
        rm -rf $SERVICE_DIR/$PID
        echo "=== stop $SERVICE_NAME"

        sleep 5
        ##
        ## dubbo-service-aa.jar
        ## dubbo-service-aa-bb.jar
        P_ID=`ps -ef | grep -w "$SERVICE_NAME" | grep -v "grep" | awk '{print }'`
        if [ "$P_ID" == "" ]; then  
            echo "=== $SERVICE_NAME process not exists or stop success"
        else
            echo "=== $SERVICE_NAME process pid is:$P_ID"
            echo "=== begin kill $SERVICE_NAME process, pid is:$P_ID"
            kill -9 $P_ID
        fi
        ;;

    restart)
        # cd /home/wwwroot/example/service/user
# chmod 777 *.sh                             //切换到root用户,对*.sh赋可执行的权限

# ./service-user.sh start
# ./service-user.sh stop
# ./service-user.sh restart

# ps -ef | grep java                        //查看运行状态 stop
        sleep 2
         start
        echo "=== restart $SERVICE_NAME"
        ;;

    *)
        ## restart
         stop
        sleep 2
         start
        ;;

esac
exit 0


https://www.xamrdz.com/lan/5wr1959775.html

相关文章: