• 微服务-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" />
  • 相关阅读:
    关于Linux测试题
    Linux常用命令按功能统一总结
    关于Eclipse的Save时的自定义操作
    关于产品版本英语缩写
    关于location.href几种用法的区别
    关于Java多态的总结.
    关于JDK中正则表达式
    关于JDK中的集合总结(三)
    关于JDK中的集合总结(二)
    关于JDK中的集合总结(一)
  • 原文地址:https://www.cnblogs.com/it-worker365/p/7007629.html
Copyright © 2020-2023  润新知