什么是微服务:

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

    >>> x=1.235 >>> int(x) 1 >>> str="fsgavfdbafdbntsbgbt" >> ...

  2. Tom与Jerry谁先死?

    有如下问题:Tom的攻击力为113,血量为688,Jerry的攻击力为112,血量为691.每一个回合他们各攻击对方一次,请问谁先死? 这是一个简单的“人狗大战问题”,我们只要利用类的继承,在原有的基 ...

  3. google最新的书签导入导出

    1.google浏览器地址栏最右边,自定义及控制--->书签----->书签管理器 2. 右上角,有整理图标, 3.点击按钮即可导入导出书签

  4. [UE4]位与字节

    位 1.bit,比特 2.一个位可以表示两个值,0或者1(一个位只能表示0或者1,并不是能同时表示0和1). 3.一个位为什么只能是2个值,而不能是3个值呢?这是由于技术因素造成的,在硬件中,如果用一 ...

  5. mysql 8.0 错误The server requested authentication method unknown to the client

    mysql 安装了最新版本8.0.11后创建用户并授权后,授权的用户连接数据库提示 The server requested authentication method unknown to the ...

  6. Oracle 在SQL语句中如何获取系统当前时间并进行操作

    select sysdate from dual;select to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') from dual; select to_char(s ...

  7. Xmanager远程连接CentOS7

    上周例会,又被说了一通,Xmanager远程连接的文档没写?服务没搭建?心想这都有VNC了,为毛一定要弄这个啊?!!但是,我还是在今天给弄了,╮(╯▽╰)╭没人权.搭建完尝试用了下,感觉吧,也不咋地啊 ...

  8. IIS 反向代理设置

    http://blog.csdn.net/yuanguozhengjust/article/details/23576033

  9. Go语言 数据类型,流程控制

    Go语言 数据类型,流程控制 人生苦短,Let's Go ! package main // 必须要有一个main包 import "fmt" func main() { fmt. ...

  10. Ext.NET Ext.JS 常用代码片段摘录

    引言 最近写代码突然有"一把梭"的感觉, 不管三七二十一先弄上再说. 换别人的说法, 这应该是属于"做项目"风格法吧. 至于知识体系, 可以参考官方或者更权威的 ...