zoukankan      html  css  js  c++  java
  • 给公司部门设计的SOA架构(转)

    新来老大年前开会说:各位同学,公司业务越来越重,未来几年要成倍增长......,我们要梳理出一套新架构,才能更好的支持N万用户.....,以后升职加薪当上....打败..... 
    想想还有点小激动呢,于是过年时楼主趁等待相亲妹纸无聊的时候,反思了目前系统现状,构思设计新架构如下。

    阅读目录:

    1. 现有系统
    2. 新架构    
      2.1 逻辑架构图 
      2.2 解释说明
    3. 系统实施
      3.1 SOA管理中心
      3.2 发布服务
      3.3 订阅服务
      3.4 采蘑菇示例
    4. 设计目标
      4.1 尽可能少的侵入
      4.2 服务自治&&水平扩展
      4.3 系统升级降级
    5. 常见问题
      5.1 ClientApi VS ServiceApi
      5.2 聚合服务
      5.3 服务分级
    6. 总结心得

    现有系统

    鄙司业务比较重,系统也有些年头,各研发团队、系统都比较稳定了。所以不差也不太好,总之也能满足现有需求。但近2年O2O,移动互联网等大行其道,老大们也都心动了,开始磨刀霍霍了。而现有系统应对复杂的变化,在一些地方颇显不足:

    • 接口没有统一管理
    • 很多组件无法复用/重复造轮子
    • 模块间职责不清,耦合过深
    • 联调排查问题比较慢
    • 开发前规划不足,形成堆积
    • 缺乏API规范/文档较少

    新架构

    逻辑架构图:

    查看大图

    解释说明:

    • A开头:是系统级别,可以独立部署。即可寄宿在IIS/WindowsService等上面。
    • B开头:是模块级别,不可独立部署。相对独立的功能模块,而又不大,所以依附其他系统或者和多个模块组成一个子系统。模块级别在项目中可以分多层,可根据分数升级成子系统(见系统升级降级)。
    • C开头:是组件级别,不可独立部署。大多数是公共性组件,一般是单独类库存在,以DLL提供使用。一些开源组件也归到这里,例:Autofac,FluentData。 需要自搭Nuget服务器,进行统一版本管理。
    • 字母后面的数字:是代表服务的级别,见服务分级。
    • 系统通信: 各系统之间尽量走内网Wcf/Tcp,对外合作单位及各移动端走WebApi/Http。
    • 传输格式: Protobuffer、Json。
    • 数据交换: 优先通过数据服务接口,其次SSIS、Job。
    • 基础平台: 缓存Redis,队列RabbitMq等。依赖抽象,框架可替换。
    • DB 层: 每个子系统拥有自己的子DB,原则上不能跨库读其他的。
    • 高可用 : 子系统自行做负载,服务变更通知使用zookeeper。
    • 单向2级:只能订阅服务,不能发布服务,2级只能订阅2级服务。
    • 定点:某个客户端只能订阅某个服务端提供的服务。

    系统实施

    SOA管理中心

    这是新架构的核心部分,主要功能如下:

    • 提供发布/订阅/ServiceAdapter组件
    • 提供Web管理界面
    • 对服务访问的各种配置
    • 在高峰期对服务限流/报警
    • 服务访问授权、描述

    发布服务

    各系统通过Web管理页面进行服务配置发布。
    也可以通过管理中心提供的组件,进行配置发布:

    复制代码
        protected void Application_Start()
        {
            ServicePublisher.Pushlish(new ServiceConfig()
            {
                ServiceName = "获取预订单详情",
                Qps = 1000,
                Level = 1,
                Key = "xxxx-yyyy",
                Source = SubscribeSource.All,
                ServiceAddress = "/Order/GetDetail",
                //其他
            });
        }
        [ServiceFilter]
        void GetDetail()
        {
        }
    复制代码

    订阅访问服务

    各系统通过管理中心提供的组件,去获取订阅的服务,然后通过适配器去访问接口,服务变更在心跳里面做:

    复制代码
        protected void Application_Start()
        {
            //获取服务列表
            var serviceList = ServiceManager.GetServiceList();
            GlobalService.ServiceList=serviceList;
        }
        void Heartbeat()
        {
            var serviceList = ServiceManager.GetServiceList();
            GlobalService.ServiceList=serviceList;
        }
        ServiceAdapter.Access(GlobalService.ServiceList[0]);
    复制代码

    采蘑菇示例

    设计目标

    尽可能少的侵入

    这点是非常重要的,如果不能很好的重用已有的系统或侵入性太强,势必会导致:

    • 新架构周期过长,长期维护二套结构。这种情况下,成本太高,不好推行下去或者还未推行就被砍了。
    • 开发人员的抵抗,每个猿类内心都有桀骜的脾气、造轮子的天赋、重组世界的梦想...。如果太复杂、约束太强,天知道你们这群猿类会干出什么事情!

    基于这种考虑,才采用服务分布式而不是服务集中式。

    • 每个系统在需要时,去订阅服务,然后拉取服务地址/MyNeedServcie.list。
    • 然后通过ServiceAdapter访问服务,ServiceAdapter中会做权限等一些校验。
    • 在服务上增加ServiceFilter,Fileter会做权限校验及服务被调用的信息采集。
    • 然后在管理中心添加服务,文档描述。

    好处是:A系统与B系统是直接交互的,服务调用不走中转路由,性能也好。而组件的作用仅是辅助性的约束。

    服务自治&&水平扩展

    由于侵入性较小,所以各个系统之间的服务变更,维护完全由各自研发团队维护。
    本系统之间通讯不走服务,直接内部调用。调用通过ServiceAdapter组件访问,ServiceAdapter包含对进程内、WCF、WebApi等访问的封装,这样便于以后替换成其他服务。 各服务在扩展上不受管理中心节制,自行做负载、增加服务器即可。

    系统升级降级

    当有个新需要过来时,会根据产品是否需要独立部署,和现有系统耦合性等因素,来评估是模块级还是系统级。
    对于旧模块,根据重要程度、访问量等评估出分数。达标的由模块抽离出子系统,单独管理。
    同样对于旧系统,不达标的进行降级处理,缩小成模块整合到其他系统里面。

    这块其实很重要,如果不对项目做好评估的话,往往会导致一个系统越来越沉重。最后的结果就是维护越来越麻烦,经常出问题。最后逼不得已就推到重来,这个成本就较大些,当然成本的事情老大会考虑更多些。处于这种情况下猿类们会一边吐槽着之前的同类渣渣,一边跃跃欲试准备大展身手,让你们瞧瞧什么叫DDD、TDD、设计模式......。

    前提是在需求开发时,按模块进行分小层而不是整个大层,这样方便协作开发和抽取成子系统。

    常见问题

    ClientApi VS ServiceApi

    ClientApi这个在前期用的比较多的办法。优点很明显:简单快捷,从Nuget上安装引用即可。这样后期会问题越来越多。
    就拿缓存Redis来说,多个系统都使用客户端直接访问Redis服务器。如果有个系统连接数忘记关闭,就会影响整个大系统,原因就是Client权限过大,客户端是可以对redis服务器直接进行操控。这种情况下redis服务器本身是暴露在外的,哪怕客户端封装的再好也不行,只要研究下通信协议规范,就可以自己写个客户端连(参见:c#实现redis客户端(一))。 这个通信期间无法管控,无法做拦截,同样队列等其他也是同样情况。

    ServiceApi:

    我们在中间加了一层,在缓存系统里面做管控,同样依赖抽象,Redis可替换。缓存系统以服务的形式发布给其他系统使用。 避免不了的就是性能有损耗,当然这个损耗可以通过一些手段减小。

    聚合服务

    服务的颗粒度一直是SOA设计的头疼事情。太粗了就很难复用,太细了需要多次往返交互,其性能、事务处理都是个问题。 比如下订单服务,这个过程中包含创建用户资料,生成预订单、支付订单,更新账务关系,更新库存等一系列的操作。这是个粗粒度服务,里面包含若干子系统的提供的细粒度服务。 粗粒度服务下,多个子系统避免不了互相交互,长久下去会让系统过于沉重,变得职责混乱。
    服务设计准则就是让服务高内聚,服务之间松耦合、边界清晰。所以我们抽离一个聚合服务系统,它专门负责把各系统提供的细粒度服务进行整合,提供给前端使用。而其他各个系统只做自己职责之内的事情。 在聚合服务系统中,方便我们更合理的把控服务的颗粒度,提高服务复用。

    服务分级

    多个研发团队协作时,很难每个人都对全部业务熟悉。所以为了避免服务调用混乱,甚至循环依赖调用,增加了对服务的分级。
    按图中所示,1级服务不能调2级服务,即低级不能调高级,高级可调低级,同级互相可调。
    这个级别针对单个服务而分的。比如有个更新库存服务,它没有外部依赖的服务,只是更新自己的DB,这样我们就可以把它划分为1级服务。 而我们的聚合服务系统中有个下订单粗粒度服务,它内部调用更新库存服务,那么它就是2级服务。很明显这里的1级不应该调用2级,对服务分级也是这个目的。

    总结心得

      • 好架构是不断进化来的
      • 尽可能考虑到每个细节
      • 注重整体平衡性,而非局部最优
      • 依赖抽象,而不是具体哪个框架技术
      • 先考虑人、资源,在考虑用哪个技术
      • 跟妹纸相处时不要想程序那点事

    http://www.cnblogs.com/mushroom/p/4298461.html

  • 相关阅读:
    PythonのTkinter基本原理
    使用 Word (VBA) 分割长图到多页
    如何使用 Shebang Line (Python 虚拟环境)
    将常用的 VBScript 脚本放到任务栏 (Pin VBScript to Taskbar)
    关于 VBScript 中的 CreateObject
    Windows Scripting Host (WSH) 是什么?
    Component Object Model (COM) 是什么?
    IOS 打开中文 html 文件,显示乱码的问题
    科技发展时间线(Technology Timeline)
    列置换密码
  • 原文地址:https://www.cnblogs.com/softidea/p/4310687.html
Copyright © 2011-2022 走看看