微服务-dubbo学习
什么是微服务:
由于业务发展迅速,为了减少代码和功能重复,方便扩展,部署,维护等因素,将系统业务组件化和服务化拆分,拆分为一个个独立的服务,由服务治理系统统一管理,每个微服务为一个进程,之间的通讯方式可以通过各种消息队列,也可以通过rest/rpc。
微服务治理框架需要实现那些功能:
以Dubbo为切入点,内容九成来在自官网http://dubbo.io/User+Guide-zh.htm
在大规模服务化之前,应用可能只是通过RMI或Hessian等工具,简单的暴露和引用远程服务,通过配置服务的URL地址进行调用,通过F5等硬件进行负载均衡。
但随着规模越来越大,URL不易管理,F5节点压力过高,所以需要引入服务的注册和发现功能,即服务提供方将服务发布到注册中心,而服务消费方可以通过注册中心订阅服务,接收服务提供方服务变更通知,这种方式可以隐藏服务提供方的细节,包括服务器地址等敏感信息,而服务消费方只能通过注册中心来获取到已注册的提供方服务,而不能直接跨过注册中心与服务提供方直接连接。
并通过在消费方获取服务提供方地址列表,实现软负载均衡和Failover,降低对F5硬件负载均衡器的依赖,也能减少部分成本。
服务管理和容错:服务越来越多,需要理清服务之间的调用关系,以及每次调用链路的详细信息为决策和维护做出支持,整条调用链上有某个服务出现问题,可能卡死整个调用,所以可以采取的措施有:重试机制/限流/熔断/负载均衡/降级/本地缓存等
服务监控:服务调用追踪,升降级,授权
Dubbo的基本角色和关系:
Container容器启动服务提供者,Provider想注册中心注册自己,Consumer想注册中心注册自己需要的服务,Registry将提供者列表返回给消费者,如果变更,注册中心基于长连接推送,消费者得到提供者信息,根据负载均衡算法,选择其中一台调用,调用失败再还另一台,消费者和提供者在内存中累计调用次数和调用事件,定时每分钟发送一次到监控中心。
写一个服务,跟之前一样,一个接口一个实现
package com.alibaba.dubbo.demo; public interface DemoService {
String sayHello(String name);
}
package com.alibaba.dubbo.demo.provider; import com.alibaba.dubbo.demo.DemoService; public class DemoServiceImpl implements DemoService {
public String sayHello(String name) {
return "Hello " + name;
}
}
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:application name="hello-world-app" /> <!-- 使用multicast广播注册中心暴露服务地址 -->
<dubbo:registry address="multicast://224.5.6.7:1234" /> <!-- 用dubbo协议在20880端口暴露服务 -->
<dubbo:protocol name="dubbo" port="20880" /> <!-- 声明需要暴露的服务接口 -->
<dubbo:service interface="com.alibaba.dubbo.demo.DemoService" ref="demoService"check
=
"false"
/> <!-- 和本地bean一样实现服务 -->
<bean id="demoService" class="com.alibaba.dubbo.demo.provider.DemoServiceImpl" /> </beans>
加载配置并启动
import org.springframework.context.support.ClassPathXmlApplicationContext; public class Provider {
public static void main(String[] args) throws Exception {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"http://10.20.160.198/wiki/display/dubbo/provider.xml"});
context.start();
System.in.read(); // 按任意键退出
}
}
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"> <!-- 消费方应用名,用于计算依赖关系,不是匹配条件,不要与提供方一样 -->
<dubbo:application name="consumer-of-helloworld-app" /> <!-- 使用multicast广播注册中心暴露发现服务地址 -->
<dubbo:registry address="multicast://224.5.6.7:1234" /> <!-- 生成远程服务代理,可以和本地bean一样使用demoService -->
<dubbo:reference id="demoService" interface="com.alibaba.dubbo.demo.DemoService" /> </beans>
加载配置,调用远程服务
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.alibaba.dubbo.demo.DemoService; public class Consumer {
public static void main(String[] args) throws Exception {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"http://10.20.160.198/wiki/display/dubbo/consumer.xml"});
context.start();
DemoService demoService = (DemoService)context.getBean("demoService"); // 获取远程服务代理
String hello = demoService.sayHello("world"); // 执行远程方法
System.out.println( hello ); // 显示调用结果
}
}
公共信息可以用xml方式,也可以用属性文件方式,也可以用注解方式,还可以命令-D方式,还有代码方式
<dubbo:application name="consumer-of-helloworld-app" />
dubbo.application.name=consumer-of-helloworld-app @Service(version="1.0.0") 服务实现类加标记,后面属性文件中指定扫描注解
<dubbo:annotation package="com.foo.bar.service" /> -Ddubbo.application.name=consumer-of-helloworld-app
还可以在测试时用代码方式
Dubbo容错模型:
<dubbo:service cluster="failsafe" />
- Failover:dubbo默认容错模式,调用失败自动切换,重试调用其他节点上的服务。设重试次数<dubbo:service retries="2" />
- Failfast:快速失败,调用只执行一次,失败则立即报错。
- Failsafe:调用失败, 则直接忽略失败的调用,记录下失败的调用到日志文件,以便后续审计。
- Failback:失败自动恢复,后台记录失败请求,定时重发。
- Forking:并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。
- Broadcast:广播调用所有提供者,逐个调用,任意一台报错则报错。通常用于通知所有提供者更新缓存或日志等本地资源信息。
Dubbo负载均衡:
<dubbo:service interface="..." loadbalance="roundrobin" />
<dubbo:reference interface="...">
<dubbo:method name="..." loadbalance="roundrobin"/>
</dubbo:reference>
- Random:随机策略,可以设置权重,有利于充分利用服务器的资源,高配的可以设置权重大一些,低配的可以稍微小一些。
- RoundRobin:轮询策略。
- LeastActive:根据请求调用的次数计数,处理请求更慢的节点会受到更少的请求。
- ConsistentHash:相同调用参数的请求会发送到同一个服务提供方节点上,如果某个节点发生故障无法提供服务,则会基于一致性Hash算法映射到虚拟节点上(其他服务提供方)
Dubbo线程模型配置:
<dubbo:protocol name="dubbo" dispatcher="all" threadpool="fixed" threads="100" />
快速执行并且不派生新请求的逻辑直接在IO线程上执行,减少线程池的调度,反之则需要调度线程池执行
消息包括,请求,响应,连接,断开,心跳等事件
Dispatcher派发逻辑定义
- all 所有消息都派发到线程池,包括请求,响应,连接事件,断开事件,心跳等。
- direct 所有消息都不派发到线程池,全部在IO线程上直接执行。
- message 只有请求响应消息派发到线程池,其它连接断开事件,心跳等消息,直接在IO线程上执行。
- execution 只请求消息派发到线程池,不含响应,响应和其它连接断开事件,心跳等消息,直接在IO线程上执行。
- connection 在IO线程上,将连接断开事件放入队列,有序逐个执行,其它消息派发到线程池。
ThreadPool
- fixed 固定大小线程池,启动时建立线程,不关闭,一直持有。(缺省)
- cached 缓存线程池,空闲一分钟自动删除,需要时重建。
- limited 可伸缩线程池,但池中的线程数只会增长不会收缩。(为避免收缩时突然来了大流量引起的性能问题)。
禁用注册配置,两种设置方式,一种属性,一种URL
<
dubbo:registry
address
=
"10.20.153.10:9090"
register
=
"false"
/>
<dubbo:registry address="10.20.153.10:9090?register=false" />
可以让服务提供者方,只注册服务到另一注册中心,而不从另一注册中心订阅服务。
<
dubbo:registry
id
=
"qdRegistry"
address
=
"10.20.141.150:9090?subscribe=false"
/>
静态注册,人工干预
<dubbo:registry address="10.20.141.150:9090?dynamic=false" />
不同服务在性能上适用不同协议进行传输,比如大数据用短连接协议,小数据大并发用长连接协议。所以需要为服务配置不同的协议
<dubbo:application name="world" />
<dubbo:registry id="registry" address="10.20.141.150:9090" username="admin" password="hello1234" /> <!-- 多协议配置 -->
<dubbo:protocol name="dubbo" port="20880" />
<dubbo:protocol name="rmi" port="1099" /> <!-- 使用dubbo协议暴露服务 -->
<dubbo:service interface="com.alibaba.hello.api.HelloService" version="1.0.0" ref="helloService" protocol="dubbo" />
<!-- 使用rmi协议暴露服务 -->
<dubbo:service interface="com.alibaba.hello.api.DemoService" version="1.0.0" ref="demoService" protocol="rmi" />
<dubbo:service id="helloService" interface="com.alibaba.hello.api.HelloService" version="1.0.0" protocol="dubbo,hessian" />
多注册中心
<dubbo:application name="world" /> <!-- 多注册中心配置 -->
<dubbo:registry id="hangzhouRegistry" address="10.20.141.150:9090" />
<dubbo:registry id="qingdaoRegistry" address="10.20.141.151:9010" default="false" /> <!-- 向多个注册中心注册 -->
<dubbo:service interface="com.alibaba.hello.api.HelloService" version="1.0.0" ref="helloService" registry="hangzhouRegistry,qingdaoRegistry" />
不同服务使用不同注册中心
<!-- 向中文站注册中心注册 -->
<dubbo:service interface="com.alibaba.hello.api.HelloService" version="1.0.0" ref="helloService" registry="chinaRegistry" /> <!-- 向国际站注册中心注册 -->
<dubbo:service interface="com.alibaba.hello.api.DemoService" version="1.0.0" ref="demoService" registry="intlRegistry" />
多注册中心引用
<!-- 引用中文站服务 -->
<dubbo:reference id="chinaHelloService" interface="com.alibaba.hello.api.HelloService" version="1.0.0" registry="chinaRegistry" />
服务分组
<dubbo:reference id="feedbackIndexService" group="feedback" interface="com.xxx.IndexService" />
<dubbo:reference id="memberIndexService" group="member" interface="com.xxx.IndexService" />
多版本
<dubbo:service interface="com.foo.BarService" version="1.0.0" />
合并分组
<dubbo:reference interface="com.xxx.MenuService" group="aaa,bbb" merger="true" />
参数验证
public class ValidationParameter implements Serializable { private static final long serialVersionUID = 7158911668568000392L; @NotNull // 不允许为空
@Size(min = 1, max = 20) // 长度或大小范围
private String name; @NotNull(groups = ValidationService.Save.class) // 保存时不允许为空,更新时允许为空 ,表示不更新该字段
@Pattern(regexp = "^\\s*\\w+(?:\\.{0,1}[\\w-]+)*@[a-zA-Z0-9]+(?:[-.][a-zA-Z0-9]+)*\\.[a-zA-Z]+\\s*$")
private String email; @Min(18) // 最小值
@Max(100) // 最大值
private int age; @Past // 必须为一个过去的时间
private Date loginDate; @Future // 必须为一个未来的时间
private Date expiryDate;
<dubbo:reference id="validationService" interface="com.alibaba.dubbo.examples.validation.api.ValidationService" validation="true" />
热门结果缓存
<dubbo:reference interface="com.foo.BarService">
<dubbo:method name="findBar" cache="lru" />
</dubbo:reference>
泛化引用-参数及返回值中的所有POJO均用Map表示
<dubbo:reference id="barService" interface="com.foo.BarService" generic="true" />
GenericService barService = (GenericService) applicationContext.getBean("barService");
Object result = barService.$invoke("sayHello", new String[] { "java.lang.String" }, new Object[] { "World" });
隐式参数传递
RpcContext.getContext().setAttachment("index", "1"); // 隐式传参,后面的远程调用都会隐式将这些参数发送到服务器端,类似cookie,用于框架集成,不建议常规业务使用
xxxService.xxx(); // 远程调用
异步调用
<dubbo:reference id="fooService" interface="com.alibaba.foo.FooService">
<dubbo:method name="findFoo" async="true" />
</dubbo:reference>
fooService.findFoo(fooId); // 此调用会立即返回null
Future<Foo> fooFuture = RpcContext.getContext().getFuture(); // 拿到调用的Future引用,当结果返回后,会被通知和设置到此Future。
// 此时findFoo和findBar的请求同时在执行,客户端不需要启动多线程来支持并行,而是借助NIO的非阻塞完成。
Foo foo = fooFuture.get(); // 如果foo已返回,直接拿到返回值,否则线程wait住,等待foo返回后,线程会被notify唤醒。
延迟暴露
<dubbo:service delay="5000" />
并发控制
<dubbo:service interface="com.foo.BarService">
<dubbo:method name="sayHello" executes="10" />
</dubbo:service>
<dubbo:reference interface="com.foo.BarService" actives="10" />
连接数控制
<dubbo:provider protocol="dubbo" accepts="10" />
<dubbo:service interface="com.foo.BarService" connections="10" />
延迟连接,连接粘滞
<dubbo:protocol name="dubbo" lazy="true" /> <dubbo:protocol name="dubbo" sticky="true" />
黑白名单路由规则
host = 10.20.153.10 => host = 10.20.153.11
脚本路由
RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension();
Registry registry = registryFactory.getRegistry(URL.valueOf("zookeeper://10.20.153.10:2181"));
registry.register(URL.valueOf("override://0.0.0.0/com.foo.BarService?category=configurators&dynamic=false&application=foo&timeout=1000"));
服务降级
registry.register(URL.valueOf("override://0.0.0.0/com.foo.BarService?category=configurators&dynamic=false&application=foo&mock=force:return+null"));
ReferenceConfig cache...
协议
<dubbo:protocol name="dubbo" port="20880" /> <dubbo:protocol name="rmi" port="1099" /> <dubbo:protocol name="hessian" port="8080" server="jetty" /> <dubbo:protocol name="http" port="8080" />
。。。。
注册中心
<dubbo:registry ... client="zkclient" />
<dubbo:registry address="redis://10.20.153.10:6379" />
微服务-dubbo学习的更多相关文章
- 微服务架构学习与思考(10):微服务网关和开源 API 网关01-以 Nginx 为基础的 API 网关详细介绍
微服务架构学习与思考(10):微服务网关和开源 API 网关01-以 Nginx 为基础的 API 网关详细介绍 一.为什么会有 API Gateway 网关 随着微服务架构的流行,很多公司把原有的单 ...
- kratos微服务框架学习笔记一(kratos-demo)
目录 kratos微服务框架学习笔记一(kratos-demo) kratos本体 demo kratos微服务框架学习笔记一(kratos-demo) 今年大部分时间飘过去了,没怎么更博和githu ...
- .NET Core微服务架构学习与实践系列文章索引目录
一.为啥要总结和收集这个系列? 今年从原来的Team里面被抽出来加入了新的Team,开始做Java微服务的开发工作,接触了Spring Boot, Spring Cloud等技术栈,对微服务这种架构有 ...
- 微服务架构学习与思考(11):开源 API 网关02-以 Java 为基础的 API 网关详细介绍
微服务架构学习与思考(11):开源 API 网关02-以 Java 为基础的 API 网关详细介绍 上一篇关于网关的文章: 微服务架构学习与思考(10):微服务网关和开源 API 网关01-以 Ngi ...
- Spring Cloud 微服务架构学习笔记与示例
本文示例基于Spring Boot 1.5.x实现,如对Spring Boot不熟悉,可以先学习我的这一篇:<Spring Boot 1.5.x 基础学习示例>.关于微服务基本概念不了解的 ...
- 深入理解SpringCloud与微服务构建学习总结
说明:用时 from 2018-11-16 to 2018-11-23 七天 0 放在前面 什么是微服务? 微服务是一个分布式系统.微服务架构的风格,就是将单一程序开发成一个微服务,每个微服务 ...
- 基于Spring Boot和Spring Cloud实现微服务架构学习
转载自:http://blog.csdn.net/enweitech/article/details/52582918 看了几周Spring相关框架的书籍和官方demo,是时候开始总结下这中间的学习感 ...
- 基于Spring Boot和Spring Cloud实现微服务架构学习--转
原文地址:http://blog.csdn.net/enweitech/article/details/52582918 看了几周spring相关框架的书籍和官方demo,是时候开始总结下这中间的学习 ...
- SpringCloud微服务基础学习
看了蚂蚁课堂的微服务学习,确实学习了不少关于微服务的知识,现在总结学习如下 : SpringCloud微服务基础单点系统架构传统项目架构传统项目分为三层架构,将业务逻辑层.数据库访问层.控制层放入在一 ...
随机推荐
- BOF、EOF 属性
BOF.EOF 属性 BOF 指示当前记录位置位于 Recordset 对象的第一个记录之前. EOF 指示当前记录位置位于 Recordset 对象的最后一个记录之后. 返回值 BOF 和 EOF ...
- MATLAB在三维坐标中显示图片 并 使得图片部分透明
要画一个光路图,本来可以用proe,但是鼠标不好用,有些操作也忘了,用MATLAB画了个.下面是用到的图片. 但是三维坐标中显示彩色图片的目标没有搞定,做了个灰度图,然后用仿射程序将彩色图片贴到了二维 ...
- 廖雪峰Java-3流程控制-7for循环
for循环 for循环使用计数器实现循环 for循环条件需要设置:计数器初始值:循环前检测条件:每次循环后如何更新计数器 计数器变量通常命名为i int[] ns = {1,4,9,16,25}; f ...
- es6 class函数的用法,及兼容程度
//es6中 class的新特性:面向对象的方式 class name{ fram(){ var div=document.getElementById("div"); div.s ...
- sas share 备忘录
options comamid=tcp;libname payable 'E:\shouen';proc server authenticate=optional id=share1 msgnumbe ...
- Spring MVC 处理列表和数组数据
SpringMVC处理列表和数组类型: 当form提交多个参数时,可以使用@RequestParam(value="")注解将其注入到列表或数组中,否则参数无法传值 1 contr ...
- saliency map [转]
基于Keras实现的代码文档 (图+说明) "Deep Inside Convolutional Networks: Visualising Image Classification Mod ...
- Socket网络编程(winform)
[服务器] using System; using System.Collections.Generic; using System.ComponentModel; using System.Data ...
- Synchronized常用用法
我们都知道 Synchronized 是线程安全同步用的,大部分程序可能只会用到同步方法上面.其实 Synchronized 可以用到更多的场合,栈长列举了以下几个用法. 1.同步普通方法 这个也是我 ...
- 如何使用IntelliJ集成nodejs进行接口测试<response demo>
1.相关的配置及安装,在如下地址进行参考,这位大师写得也挺好(mac和windows都可以下载) https://www.jianshu.com/p/dd2d2d0ff133 2.在集成nodejs的 ...