什么是微服务:

由于业务发展迅速,为了减少代码和功能重复,方便扩展,部署,维护等因素,将系统业务组件化和服务化拆分,拆分为一个个独立的服务,由服务治理系统统一管理,每个微服务为一个进程,之间的通讯方式可以通过各种消息队列,也可以通过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" />

  1. Failover:dubbo默认容错模式,调用失败自动切换,重试调用其他节点上的服务。设重试次数<dubbo:service retries="2" />
  2. Failfast:快速失败,调用只执行一次,失败则立即报错。
  3. Failsafe:调用失败, 则直接忽略失败的调用,记录下失败的调用到日志文件,以便后续审计。
  4. Failback:失败自动恢复,后台记录失败请求,定时重发。
  5. Forking:并行调用多个服务器,只要一个成功即返回。通常用于实时性要求较高的读操作,但需要浪费更多服务资源。
  6. Broadcast:广播调用所有提供者,逐个调用,任意一台报错则报错。通常用于通知所有提供者更新缓存或日志等本地资源信息。

Dubbo负载均衡:

<dubbo:service interface="..." loadbalance="roundrobin" />

<dubbo:reference interface="...">
<dubbo:method name="..." loadbalance="roundrobin"/>
</dubbo:reference>

  1. Random:随机策略,可以设置权重,有利于充分利用服务器的资源,高配的可以设置权重大一些,低配的可以稍微小一些。
  2. RoundRobin:轮询策略。
  3. LeastActive:根据请求调用的次数计数,处理请求更慢的节点会受到更少的请求。
  4. ConsistentHash:相同调用参数的请求会发送到同一个服务提供方节点上,如果某个节点发生故障无法提供服务,则会基于一致性Hash算法映射到虚拟节点上(其他服务提供方)

Dubbo线程模型配置:

<dubbo:protocol name="dubbo" dispatcher="all" threadpool="fixed" threads="100" />

快速执行并且不派生新请求的逻辑直接在IO线程上执行,减少线程池的调度,反之则需要调度线程池执行

消息包括,请求,响应,连接,断开,心跳等事件

Dispatcher派发逻辑定义

  1. all 所有消息都派发到线程池,包括请求,响应,连接事件,断开事件,心跳等。
  2. direct 所有消息都不派发到线程池,全部在IO线程上直接执行。
  3. message 只有请求响应消息派发到线程池,其它连接断开事件,心跳等消息,直接在IO线程上执行。
  4. execution 只请求消息派发到线程池,不含响应,响应和其它连接断开事件,心跳等消息,直接在IO线程上执行。
  5. connection 在IO线程上,将连接断开事件放入队列,有序逐个执行,其它消息派发到线程池。

ThreadPool

  1. fixed 固定大小线程池,启动时建立线程,不关闭,一直持有。(缺省)
  2. cached 缓存线程池,空闲一分钟自动删除,需要时重建。
  3. 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学习的更多相关文章

  1. 微服务架构学习与思考(10):微服务网关和开源 API 网关01-以 Nginx 为基础的 API 网关详细介绍

    微服务架构学习与思考(10):微服务网关和开源 API 网关01-以 Nginx 为基础的 API 网关详细介绍 一.为什么会有 API Gateway 网关 随着微服务架构的流行,很多公司把原有的单 ...

  2. kratos微服务框架学习笔记一(kratos-demo)

    目录 kratos微服务框架学习笔记一(kratos-demo) kratos本体 demo kratos微服务框架学习笔记一(kratos-demo) 今年大部分时间飘过去了,没怎么更博和githu ...

  3. .NET Core微服务架构学习与实践系列文章索引目录

    一.为啥要总结和收集这个系列? 今年从原来的Team里面被抽出来加入了新的Team,开始做Java微服务的开发工作,接触了Spring Boot, Spring Cloud等技术栈,对微服务这种架构有 ...

  4. 微服务架构学习与思考(11):开源 API 网关02-以 Java 为基础的 API 网关详细介绍

    微服务架构学习与思考(11):开源 API 网关02-以 Java 为基础的 API 网关详细介绍 上一篇关于网关的文章: 微服务架构学习与思考(10):微服务网关和开源 API 网关01-以 Ngi ...

  5. Spring Cloud 微服务架构学习笔记与示例

    本文示例基于Spring Boot 1.5.x实现,如对Spring Boot不熟悉,可以先学习我的这一篇:<Spring Boot 1.5.x 基础学习示例>.关于微服务基本概念不了解的 ...

  6. 深入理解SpringCloud与微服务构建学习总结

    说明:用时 from 2018-11-16 to 2018-11-23 七天 0 放在前面   什么是微服务?   微服务是一个分布式系统.微服务架构的风格,就是将单一程序开发成一个微服务,每个微服务 ...

  7. 基于Spring Boot和Spring Cloud实现微服务架构学习

    转载自:http://blog.csdn.net/enweitech/article/details/52582918 看了几周Spring相关框架的书籍和官方demo,是时候开始总结下这中间的学习感 ...

  8. 基于Spring Boot和Spring Cloud实现微服务架构学习--转

    原文地址:http://blog.csdn.net/enweitech/article/details/52582918 看了几周spring相关框架的书籍和官方demo,是时候开始总结下这中间的学习 ...

  9. SpringCloud微服务基础学习

    看了蚂蚁课堂的微服务学习,确实学习了不少关于微服务的知识,现在总结学习如下 : SpringCloud微服务基础单点系统架构传统项目架构传统项目分为三层架构,将业务逻辑层.数据库访问层.控制层放入在一 ...

随机推荐

  1. jQuery 事件的命名空间简单了解

    原文地址:http://www.jb51.net/article/43626.htm   用 jQuery 绑定和解绑事件监听器都是非常简单的,怎样精确地解绑其中一个监听器?我们需要了解一下事件的命名 ...

  2. centos7部署openvpn-2.4.6

    一.环境说明 返回主机的IP地址 # ip a | grep "scope global" | awk -F'[ /]+' '{print $3}' | head -1 [root ...

  3. [UE4]Child Widget中的事件调度器

    在Child Widget中新建事件调度器,就会自动在使用该Child Widget的父级界面的事件列表中自动自动出现.功能十分强大.

  4. Shiro 权限注解

      Shiro 权限注解:   Shiro 提供了相应的注解用于权限控制,如果使用这些注解就需要使用AOP 的功能来进行 判断,如Spring AOP:Shiro 提供了Spring AOP 集成用于 ...

  5. Delphi TstringList Stringlist的特殊用法

    procedure TForm1.btn1Click(Sender : TObject); var   m      : Integer;   s       : string;   strlst   ...

  6. 'ascii' codec can't decode byte 0xd6 in position 0

    使用elastalert,执行python文件时报错: 经查,python命令下输出中文字符时需要将编码指定为gb2312,一开始博主也不知道是输出在控制台的信息编码格式问题,一直以为是博主自己的ya ...

  7. 查看Selinux和关闭Selinux

    查看Selinux和关闭Selinux   注:本文非原创文章,转自以下: 链接:https://www.jianshu.com/p/a7900dbf893c 查看SELinux状态: /usr/sb ...

  8. python 搭建redis集群

    所需依赖 redis.io/download">redis-3.0.7ruby-1.8.7:sudo apt-get install rubyrubygems:sudo apt-get ...

  9. [Android]Android布局优化之 merge

    转载请标明:转载于http://www.cnblogs.com/Liuyt-61/p/6602915.html -------------------------------------------- ...

  10. py库: Selenium (自动化测试)

    http://blog.csdn.net/liujingqiu/article/details/50458553 http://www.cnblogs.com/zhaof/p/6953241.html ...