zoukankan      html  css  js  c++  java
  • 微服务-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" />

    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" />
  • 相关阅读:
    chrome浏览器中安装以及使用Elasticsearch head 插件
    windows10 升级并安装配置 jmeter5.3
    linux下部署Elasticsearch6.8.1版本的集群
    【Rollo的Python之路】Python 爬虫系统学习 (八) logging模块的使用
    【Rollo的Python之路】Python 爬虫系统学习 (七) Scrapy初识
    【Rollo的Python之路】Python 爬虫系统学习 (六) Selenium 模拟登录
    【Rollo的Python之路】Python 爬虫系统学习 (五) Selenium
    【Rollo的Python之路】Python 爬虫系统学习 (四) XPath学习
    【Rollo的Python之路】Python 爬虫系统学习 (三)
    【Rollo的Python之路】Python sys argv[] 函数用法笔记
  • 原文地址:https://www.cnblogs.com/it-worker365/p/7007629.html
Copyright © 2011-2022 走看看