zoukankan      html  css  js  c++  java
  • dapeng-soa服务生命周期

    一个服务的前世今生-dapeng-soa服务生命周期详述

     
     
    dapeng-soa architechure

    1. 概述

    随着搭载于dapeng框架之上的业务系统一个个上线并趋于稳定,不少开发同事们在抓虫子之余,也萌生了一些“不满”:用了dapeng好久了,但是它就像一个黑盒子,我们知之甚少,能否系统的介绍一下啊。
    确实,dapeng框架提供了丰富的脚手架以及详尽的开发指南(详见dapeng官网), 极易上手。但了解一下dapeng的内部机制,有利于开阔眼界,并在开发中充分利用各个特性,对于提高服务的质量也很有好处。

    本文着眼于分析一个服务从启动到结束的整个过程。

    后续会分专题陆续介绍dapeng框架的各个特性,敬请留意。

    2. dapeng 容器目录结构

    dapeng-container
    ├── apps                           # 1. business services
    │   ├── order_service
    │   └── stock_service
    ├── bin
    │   ├── dapeng-bootstrap.jar                      # 2. dapeng bootstrap module
    │   ├── lib                                       # 3. dapeng container jars(including dependency)
    │   ├── shutdown.sh                               # 4. startup/shutdown shell
    │   └── startup.sh
    ├── conf                                          # 5. configuration files for container
    │   └── logback.xml
    ├── lib                                           # 6. core lib
    │   ├── dapeng-core-2.1.1.jar
    │   └── logback-*.jar
    ├── logs                                          # 7. directory where log files located
    └── plugin                                        # 8. plugin directory
    
    1. 业务服务,该目录由dapeng的ApplicationClassLoader加载, 可在一个dapeng容器中放多个服务,但是建议一个容器一个服务
    2. dapeng bootstrap模块,容器的启动入口,负责生成其它的定制classLoader并启动容器。
    3. dapeng container jar目录,容器的实现类及其三方依赖,通过ContainerClassLoader加载
    4. 启动以及停止脚本
    5. 容器的配置文件
    6. 核心接口库以及日志,由CoreClassLoader负责加载,可用于服务端以及客户端
    7. 日志目录
    8. 插件目录,由PluginClassLoader加载

    注意, 不同的目录由不同的classLoader加载。常见的错误是:apps路径下的服务有个对象(通过ApplicationClassLoader加载),假设叫a,其类型为A,它是单例对象(通过A.getInstance()获得)。但是在bin路径下(也就是通过ContainerClassLoader加载), 通过A.getInstance()得到的a', 就跟a是完全不同的对象了。

    3. zk节点结构

    /soa/
    ├── runtime/service/                                   # 1. runtime info
    │   ├── com.today.soa.idgen.service.IDService/
    │   │   ├── 192.168.10.130:9081:1.0.0:0000000181        # 2. node info
    │   │   ├── 192.168.20.101:9081:1.0.0:0000000179        # 3. master node
    │   │   └── 192.168.10.138:9081:1.0.0:0000000183
    │   ├── com.today.api.order.service.OrderService2/ 
    │   │   ├── 192.168.10.133:9099:1.0.0:0000000368        
    │   │   ├── 192.168.10.126:9099:1.0.0:0000000372       
    │   │   ├── 192.168.20.102:9099:1.0.0:0000000367      
    │   │   └── 192.168.10.131:9099:1.0.0:0000000366        # master node
    │   └── ...                                             # 4. other services
    └── config/
        ├── services/                                       # 5. config info
        │   ├── com.today.soa.idgen.service.IDService
        │   └── com.today.api.order.service.OrderService2
        ├── freq/                                           # 6. rate limit rules
        ├── routes/                                         # 7. router rules
        └── cookies/                                        # 8. cookie rules
    

    3.1 服务运行时信息 /soa/runtime/service/

    服务运行时信息由服务在启动的时候注册到zk的/soa/runtime/service/${serviceName}路径上,其表现形式为挂靠在该路径下的临时节点,格式为:ip:port:version:seq, seq由zookeeper自动生成,且能保证在同目录下唯一并单调递增。
    其中,dapeng容器根据本容器中服务运行时信息的seq,判断是否为master主节点(seq最低者为master)

    一个服务对应一个临时节点。 我们可通过该路径得知目前服务集群中该服务的节点数量

    3.2 服务配置信息 /soa/config/

    服务配置信息存放了dapeng-soa所需要的一些配置项,可通过命令行工具或者配置中心进行管理。

    服务的配置信息当前有四种,分布在/soa/config/不同的子目录下。它们的结构都类似,都是把服务名字作为节点挂在配置子目录下,然后配置信息作为节点的内容。

    3.2.1 普通配置信息 /soa/config/services/

    包括负载均衡策略、服务超时等信息。
    包含两个层次:

    • 全局性配置: 直接写进/soa/config/services/节点
    timeout/100ms;loadbalance/LeastActive;
    
    • 服务私有配置: 写到具体的服务节点上, 例如/soa/config/services/com.today.api.order.service.OrderService2
    timeout/100ms,createOrder:500ms,createOrderPayment:60000ms;loadbalance/LeastActive,createOrder:Random,createOrderPayment:RoundRobin;
    

    3.2.2 限流配置信息 /soa/config/freq/

    dapeng 的流控做在服务端,所以该节点只对服务端有效。
    限流信息直接写在具体的服务节点上,例如如下订单的限流配置写在/soa/config/freq/com.today.api.order.service.OrderService2

    [rule1]
    match_app = listOrder # 针对具体方法限流
    rule_type = callerIp # 对每个请求端IP
    min_interval = 60,5  # 每分钟请求数不超过5次
    mid_interval = 3600,100 # 每小时请求数不超过100次
    max_interval = 86400,200 # 每天请求数不超过200次
    
    [rule2]
    match_app = * # 针对订单服务限流
    rule_type = callerIp # 对每个请求端IP
    min_interval = 60,600  # 每分钟请求数不超过600
    mid_interval = 3600,10000 # 每小时请求数不超过1万
    max_interval = 86400,80000 # 每天请求数不超过8万
    

    详见dapeng-soa限流文档

    3.2.3 路由配置信息 /soa/config/routes/

    服务路由信息也是直接写在具体的服务节点上,例如下面订单的路由配置写在/soa/config/routes/com.today.api.order.service.OrderService2

    method match r"create.*" => ip"192.168.10.0/24"
    cookie_storeId match %"10n+1..6" => ip"192.168.20.128"
    

    详见dapeng-soa路由文档

    3.2.3 cookie 规则信息 /soa/config/cookies/

    cookie规则信息也是直接写在具体的服务节点上,例如针对来自dapengCli的手工对订单接口的调用,我们为这些调用打开TRACE功能,那么我们把规则配置到/soa/config/cookies/com.today.api.order.service.OrderService2:

    callerIp match ip"192.168.20.200" => c"thread-log-level#TRACE"
    

    3. 容器的生命周期

    容器提供了一个LifeCycleAware接口以及若干事件,在事件发生的时候会触发相应的业务逻辑。
    业务可通过实现该接口, 做一些初始化以及清理的动作。

    例如某服务的业务,只在主节点启动一个工作线程。那么它就可以监听MASTER_CHANGE事件。当主节点发生变更的时候,就启动或者停止工作线程。

        public enum LifeCycleEventEnum {
            /**
             * dapeng 容器启动
             */
            START,
            PAUSE,
            MASTER_CHANGE,
            CONFIG_CHANGE,
            STOP
        }
    
    /**
     * 提供给业务的lifecycle接口,四种状态
     *
     * @author hui
     * @date 2018/7/26 11:21
     */
    public interface LifeCycleAware {
    
        /**
         * 容器启动时回调方法
         */
        void onStart(LifeCycleEvent event);
    
        /**
         * 容器暂停时回调方法
         */
        default void onPause(LifeCycleEvent event) {
        }
    
        /**
         * 容器内某服务master状态改变时回调方法
         * 业务实现方可自行判断具体的服务是否是master, 从而执行相应的逻辑
         */
        default void onMasterChange(LifeCycleEvent event) {
        }
    
        /**
         * 容器关闭
         */
        void onStop(LifeCycleEvent event);
    
        /**
         * 配置变化
         */
        default void onConfigChange(LifeCycleEvent event) {
        }
    }
    

    4. 容器的启动过程

    容器启动需要协调各个插件的顺序,避免在服务还没准备好的情况下,客户端请求就涌进来。
    通过脚本startup.sh启动容器: java -server $JAVA_OPTS -cp ./dapeng-bootstrap.jar com.github.dapeng.bootstrap.Bootstrap

     
    dapeng-soa bootstrap
    1. Bootstrap创建三个classLoader, 分别是CoreClassLoader(负责加载lib目录的类)、ContainerClassLoader(负责加载bin/lib目录的类)以及ApplicationClassLoader(负责加载apps目录下的类)。

    2. Bootstrap通过ContainerClassLoader加载ContainerFactory并调用其getContainer方法, 获得DapengContainer实例。

    3. DapengContainer创建五个Plugin,并依次调用其start方法:
      3.1 启动NettyPlugin, 打开服务监听端口(例如9090)
      3.2 启动ZkPlugin, 跟注册中心zookeeper建立连接。
      3.3 启动SpringPlugin
      3.3.1 通过ApplicationClassLoader加载服务(一个服务表现为一个Application对象)
      3.3.2 对每个服务(假设为OrderService),通过ZkPlugin把服务信息注册到/soa/runtime/service/com.today.api.order.service.OrderService2目录里,并启动一个对该路径的zk watcher(主要用于跟踪服务集群中master节点的变化, 当发生master变换时,需触发MASTER_CHANGE事件。

      一旦服务完成注册,嗷嗷待哺的客户端就会如潮水般涌进该服务节点。

      3.4 启动SchedulePlugin, 定时任务就绪
      3.5 启动JmxPluginJmx 端口就绪
      3.6 如果是开发模式(默认), 那么启动ApiDocPlugin, 内置的文档站点可访问。该插件在生产环境下不会启动

    4. 触发容器START事件

    5. 加载服务端Filter(详情下回分解)。

    6. 最后,注册Jvm进程的ShutdownHook

    至此,容器启动完毕, 服务生命周期开始。

    5. 容器的优雅关闭过程

    容器的关闭过程,同样需要协调插件的关闭顺序,确保进来的请求尽量处理完毕后再关闭容器,避免对业务产生影响。为此, dapeng 容器会维护一个请求计数器requestCounter,计数值是当前容器内尚未处理完的请求数目。

    1. 启动脚本startup.sh会监听kill信号。收到kill信号后,脚本转发该信号到容器Jvm进程。
    2. 容器的ShutdownHook给触发,依次执行:
      2.1 ZkPlugin.stop方法,断开跟zookeeper的连接,从而把本节点服务信息从/soa/runtime/services/${serviceName}上摘除,进而新的请求就不会再路由到本节点。
      2.2 休眠若干次,直到requestCounter数目为0或者超时。
      2.3 关闭其它插件( Netty有自己的优雅关闭机制,能确保outbound队列的消息能全部发送出去)

    至此,容器关闭,服务结束了其使命。

     
  • 相关阅读:
    JavaWeb--HttpSession案例
    codeforces B. Balls Game 解题报告
    hdu 1711 Number Sequence 解题报告
    codeforces B. Online Meeting 解题报告
    ZOJ 3706 Break Standard Weight 解题报告
    codeforces C. Magic Formulas 解题报告
    codeforces B. Sereja and Mirroring 解题报告
    zoj 1109 Language of FatMouse 解题报告
    hdu 1361.Parencodings 解题报告
    hdu 1004 Let the Balloon Rise 解题报告
  • 原文地址:https://www.cnblogs.com/sea520/p/12165737.html
Copyright © 2011-2022 走看看