Dubbo框架学习

Dubbo框架

Apache Dubbo dubbo文档

一、为什么要使用dubbo ?

​ 随着Internet的快速发展,Web应用程序的规模不断扩大,最后我们发现传统的垂直体系结构(单片式)已无法解决。分布式服务体系结构和流计算体系结构势在必行,迫切需要一个治理系统来确保体系结构的有序发展。

Dubbo框架学习

1.整体架构

​ 当流量非常低时,只有一个应用程序,所有功能都部署在一起以减少部署节点和成本。在这一点上,数据访问框架(ORM)是简化CRUD工作量的关键。

2.垂直架构

​ 当流量增加时,添加单片应用程序实例不能很好地加速访问,提高效率的一种方法是将单片应用程序拆分为离散的应用程序。此时,用于加速前端页面开发的Web框架(MVC)是关键。

3.分布式服务架构

​ 当垂直应用程序越来越多时,应用程序之间的交互是不可避免的,一些核心业务被提取出来并作为独立的服务来服务,从而逐渐形成一个稳定的服务中心,这样前端应用程序就可以更好地响应不断变化的市场需求。很快。此时,用于业务重用和集成的分布式服务框架(RPC)是关键。

4.流计算架构

​ 当服务越来越多时,容量评估变得困难,而且小规模的服务也经常造成资源浪费。为解决这些问题,应添加调度中心,以根据流量管理集群容量并提高集群利用率。目前,用于提高机器利用率的资源调度和治理中心(SOA)是关键。

二、使用dubbo的要求

服务治理:

Dubbo框架学习

​ 在大规模服务出现之前,应用程序可能只是通过使用RMI或Hessian公开或引用远程服务,调用是通过配置服务URL完成的,负载平衡是通过硬件(如F5)完成的。

当服务越来越多时,配置服务URL变得非常困难,F5硬件负载平衡器的单点压力也在增加。此时,需要一个服务注册表来动态注册和发现服务,以使服务的位置透明通过获取用户方的服务提供商地址列表,可以实现软负载平衡和故障转移,从而减少了对F5硬件负载平衡器的依赖性以及某些成本。

当事情进一步发展时,服务依赖关系变得如此复杂,以至于甚至连架构师也无法完全描述应用程序架构之间的关系。

这时,需要自动绘制应用程序的依赖关系图,以帮助架构师清除关系。

​ **然后,流量变得更大,服务的容量问题暴露出来,需要多少台机器来支持该服务?何时应添加机器?**为解决这些问题,首先,应将日常服务电话和响应时间视为容量规划的参考。其次,动态调整权重,增加在线计算机的权重,并记录响应时间的变化,直到达到阈值为止,记录此时的访问次数,然后将此访问次数乘以计算机总数,以计算容量依次。

三、dubbo框架的构造

Dubbo框架学习

节点角色规范

节点 角色规格
Provider 提供者公开远程服务
Consumer 消费者致电远程服务
Registry 注册表负责服务发现和配置
Monitor 监视器计算服务调用的次数和耗时
Container 容器管理服务的生命周期

服务关系

  1. Container负责启动,加载和运行服务Provider
  2. Provider``Register在启动时向其注册服务。
  3. ConsumerRegister启动时开始订阅所需的服务。
  4. RegisterProviders列表返回Consumer,更改时,RegisterConsumer通过长连接将更改后的数据推送到。
  5. Consumer``Provider根据软负载平衡算法选择s之一并执行调用,如果失败,它将选择另一个Provider
  6. 两者ConsumerProvider都会计算内存中调用服务的次数和耗时,并将统计信息发送到Monitor每一分钟。

Dubbo功能:

连接性
  • Register负责注册和搜索服务地址(例如目录服务),Provider并且Consumer仅在启动期间与注册表交互,并且注册表不转发请求,因此压力较小
  • “监视器”负责计算服务调用的数量和耗时,统计信息将首先在ProviderConsumer的内存中汇总,然后发送到Monitor
  • “提供商”将服务注册为“注册”,并将耗时的统计信息(不包括网络开销)报告给“监控器”
  • “消费者”从中获取服务提供商地址列表,Registry根据LB算法直接呼叫提供商,向上报耗时的统计信息Monitor,其中包括网络开销
  • 之间的连接RegisterProvider并且Consumer是长连接,Moniter是一个例外
  • Register``Provider通过长连接意识到存在,当断开连接时ProviderRegister会将事件推送到Consumer
  • 它不影响已经运行的实例ProviderConsumer甚至所有RegisterMonitor趴下,因为Consumer得到的缓存Provider上榜
  • Register并且Monitor是可选的,Consumer可以Provider直接连接
坚固性
  • Monitor的停机时间不会影响使用情况,只会丢失一些采样数据
  • 当数据库服务器关闭时,Register可以通过检查其缓存将服务Provider列表返回到Consumer,但是新服务器Provider无法注册任何服务
  • Register 是一个对等集群,当任何实例出现故障时,它将自动切换到另一个集群
  • 即使所有Register实例都发生故障,Provider并且Consumer仍然可以通过检查其本地缓存来进行通信
  • 服务Provider是无状态的,一个实例的停机时间不会影响使用
  • Provider一项服务的所有服务关闭后,Consumer将无法使用该服务,并无限地重新连接以等待服务Provider恢复
可伸缩性、可扩展性
  • Register 是一个可以动态增加其实例的对等群集,所有客户端将自动发现新实例。
  • Provider是无状态的,它可以动态地增加部署实例,并且注册表会将新的服务提供者信息推送到Consumer
可升级性

​ 当服务集群进一步扩展并且IT治理结构进一步升级时,需要动态部署,并且当前的分布式服务体系结构不会带来阻力。这是未来可能的架构

Dubbo框架学习

节点角色规范

节点 角色规格
Deployer 用于自动服务部署的本地代理
Repository 该存储库用于存储应用程序包
Scheduler 调度程序会根据访问压力自动增加或减少服务提供商
Admin 统一管理控制台
Registry 注册表负责服务发现和配置
Monitor 监控器计算服务呼叫时间和时间

四、dubbo用法

1.在spring框架运行

在dubbo-demo目录下创建3个子目录:

  • dubbo-demo-api:通用服务api
  • dubbo-demo-provider:提供者代码
  • dubbo-demo-consumer:消费者代码
添加依赖
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>4.3.9.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/dubbo -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>dubbo</artifactId>
    <version>2.5.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.javassist/javassist -->
<dependency>
    <groupId>org.javassist</groupId>
    <artifactId>javassist</artifactId>
    <version>3.21.0-GA</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.netty/netty -->
<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty</artifactId>
    <version>3.10.5.Final</version>
</dependency>
​服务提供者

DemoService.java:

package org.apache.dubbo.demo;
public interface DemoService {
    String sayHello(String name);
}

项目结构应如下所示:

.
├── dubbo-demo-api
│   ├── pom.xml
│   └── src
│       └── main
│           └── java
│               └── org
│                   └── apache
│                       └── dubbo
│                           └── demo
│                               └── DemoService.java
在服务提供商中实现接口

DemoServicelmpl.java

package org.apache.dubbo.demo.provider;
import org.apache.dubbo.demo.DemoService;
public class DemoServiceImpl implements DemoService {
    public String sayHello(String name) {
        return "Hello " + name;
    }
}
使用Spring配置公开服务

provider.xml

<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

    <!-- 提供者 -->
    <dubbo:application name="demo-provider"/>
    <!-- 注册地址 -->
    <dubbo:registry address="multicast://224.5.6.7:1234"/>
    <!-- dubbo暴露端口 -->
    <dubbo:protocol name="dubbo" port="20880"/>
    <!-- 实现类接口 -->
    <bean id="demoService" class="org.apache.dubbo.demo.provider.DemoServiceImpl"/>
    <!--服务提供者-->
    <dubbo:service interface="org.apache.dubbo.demo.DemoService" ref="demoService"/>
</beans>
配置日志纪录系统

​ 默认情况下,Dubbo使用log4j作为日志记录系统,它还支持slf4j,Apache Commons Logging和JUL日志记录。

log4j.properties

###set log levels###
log4j.rootLogger=info, stdout
###output to the console###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[%d{dd/MM/yy hh:mm:ss:sss z}] %t %5p %c{2}: %m%n
引导服务提供商

provider.java

package org.apache.dubbo.demo.provider;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Provider {
    public static void main(String[] args) throws Exception {
        System.setProperty("java.net.preferIPv4Stack", "true");
        //spring环境上下文
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"META-INF/spring/dubbo-demo-provider.xml"});
        context.start();
        System.out.println("Provider started.");
        System.in.read(); // press any key to exit
    }
}

最后,项目结构应如下所示:

├── dubbo-demo-provider
│   ├── pom.xml
│   └── src
│       └── main
│           ├── java
│           │   └── org
│           │       └── apache
│           │           └── dubbo
│           │               └── demo
│           │                   └── provider
│           │                       ├── DemoServiceImpl.java
│           │                       └── Provider.java
│           └── resources
│               ├── META-INF
│               │   └── spring
│               │       └── dubbo-demo-provider.xml
│               └── log4j.properties
服务消费者–使用spring配置引用远程服务

Consumer.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
       xmlns="http://www.springframework.org/schema/beans"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
       http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

    <!-- 消费者 -->
    <dubbo:application name="demo-consumer"/>
    <!-- 注册地址 -->
    <dubbo:registry address="multicast://224.5.6.7:1234"/>
    <!-- 服务提供者 -->
    <dubbo:reference id="demoService" check="false" interface="org.apache.dubbo.demo.DemoService"/>
</beans>
引导消费者
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.apache.dubbo.demo.DemoService;
 
public class Consumer {
    public static void main(String[] args) throws Exception {
        //spring上下文环境
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"META-INF/spring/dubbo-demo-consumer.xml"});
        context.start();
        // 得到提供者
        DemoService demoService = (DemoService)context.getBean("demoService");
        // 打印
        String hello = demoService.sayHello("world");
        // 结果
        System.out.println(hello);
    }
}

最后,项目结构应如下所示:

├── dubbo-demo-consumer
│   ├── pom.xml
│   └── src
│       └── main
│           ├── java
│           │   └── org
│           │       └── apache
│           │           └── dubbo
│           │               └── demo
│           │                   └── consumer
│           │                       └── Consumer.java
│           └── resources
│               ├── META-INF
│               │   └── spring
│               │       └── dubbo-demo-consumer.xml
│               └── log4j.properties

运行结果:

Hello world

2.在springBoot框架运行

添加依赖
<!--web组件--> 
<dependency> 
   <groupId>org.springframework.boot</groupId> 
    <artifactId>spring-boot-starter-web</artifactId> 
</dependency> 
<!--dubbo依赖--> 
<dependency> 
    <groupId>com.alibaba.spring.boot</groupId>      
    <artifactId>dubbo-spring-boot-starter</artifactId> 
</dependency> 
<!--zkClient依赖--> 
<dependency> 
    <groupId>com.101tec</groupId> 		                     
    <artifactId>zkclient</artifactId>
</dependency>
定义服务接口
public interface UserService { 
	User selectUserById(Integer id); 
}

实体类User.java

public class User implements Serializable 
{
	private Integer id; 
	private String name;
    public Integer getId()
    	{ return id; }
    public void setId(Integer id) 
    	{ this.id = id; }
	public String getName()
		{ return name; }
	public void setName(String name)
		{ this.name = name; }
}
在provider模块中实现服务接口
/*** 用户接口实现类 */
@Service(interfaceClass=UserService.class)
@Component 
public class UserServiceImpl implements UserService 
{ 
	@Override 
	public User selectUserById(Integer id) 
	{ 
		User user=new User();
		user.setId(id);
        user.setName("jj"); 
        System.out.println("提供服务"); 
        return user;
     } 
}
application.yml
server: 
# 端口 
	port: 8003 
spring: 
 	application: 
		name: dubbo 
 	dubbo: 
		#开启dubbo 
		server: true 
		#应用信息 
		application: 
			name: provider 
		# 注册中心地址 
		registry: 
			address: multicast://224.5.6.7:1234 
		protocol: 
			#协议名 
			name: dubbo 
			#协议端口 
			port: 20880 
		#扫描包的位置 
		scan: com.xxx.dubbodemoprovider.service
启动测试提供者
@SpringBootApplication 
//开启dubbo 
@EnableDubboConfiguration 
public class DubbodemoProviderApplication { 	
	public static void main(String[] args) { 			
        SpringApplication.run(DubbodemoProviderApplication.class, args); 
	} 
}
在consumer模块中实现服务接口
@SpringBootApplication 
//开启dubbo 
@EnableDubboConfiguration 
public class DubbodemoConsumerApplication { 

	public static void main(String[] args) { 

	SpringApplication.run(DubbodemoConsumerApplication.class, args); 
	} 
}
application.yml配置
server: 
# 端口 
	port: 8002
spring: 
 	application: 
		name: dubbo 
 	dubbo: 
		#开启dubbo 
		server: true 
		#应用信息 
		application: 
			name: consumer 
		# 注册中心地址 
		registry: 
			address: multicast://224.5.6.7:1234 
		protocol: 
			#协议名 
			name: dubbo 
			#协议端口 
			port: 20880 
		#扫描包的位置 
		scan: com.xxx.dubbodemoconsumer.service
/**用户消费类 */ 
@Component 
public class UserInit implements CommandLineRunner { 
    
	@Reference(interfaceClass= UserService.class) 
	private UserService userService; 
	@Override 
	public void run(String... args) throws Exception { 
		User user=userService.selectUserById(1); 
		System.out.println("消费服务"); 
		System.out.println(user); 
	} 
}

五、dubbo中的负载均衡

1.LoadBalance策略

随机负载平衡
  • Ramdom重量设定随机概率。
  • 某一部分发生冲突的可能性很高,但是呼叫次数越大,分布越均匀。并且当基于概率使用权重时,分布证明是均匀的,这也有助于动态调整提供者权重。
RoundRobin权重负载平衡
  • RoundRobin,使用权重的公共顾问确定轮循比率。
  • 流向速度较慢的提供程序的流量可能会导致请求堆积,例如,如果某个提供程序以非常慢的速度处理请求,但该请求仍处于活动状态,这意味着它可以正常接收请求。根据RoundRobin政策,消费者将以预定的速度连续向该提供程序发送请求,而不会意识到提供程序的不良状态。最终,我们将收到许多关于此不健康提供商的请求。
最小活动负载平衡
  • LeastActive是一种基于活动变量的随机机制,actives表示消费者已发送但尚未返回的请求数量。
  • 较慢的提供者将收到较少的请求,因为较慢的提供者将收到较高的请求actives
一致的哈希负载平衡
  • ConsistentHash,始终将请求的相同参数发送到相同的提供程序。
  • 当提供程序失败时,基于虚拟节点算法的对提供程序的原始请求将平均到其他提供程序,不会引起急剧的变化。
  • 算法参考:http://zh.wikipedia.org/wiki/Consistent_hashing
  • 默认情况下只有第一个参数哈希,如果要修改,请配置 <dubbo:parameter key="hash.arguments" value="0,1" />
  • 默认情况下160个虚拟节点,如果要修改,请配置 <dubbo:parameter key="hash.nodes" value="320" />

2.组态

服务器服务级别
<dubbo:service interface="..." loadbalance="roundrobin" />
客户服务水平
<dubbo:reference interface="..." loadbalance="roundrobin" />
服务器方法级别
<dubbo:service interface="...">
    <dubbo:method name="..." loadbalance="roundrobin"/>
</dubbo:service>
客户方法级别
<dubbo:reference interface="...">
    <dubbo:method name="..." loadbalance="roundrobin"/>
</dubbo:reference>
上一篇:Spring Cloud 七:Feign介绍与使用


下一篇:Architecture(Dubbo)