中小型研发团队很多,而社区在中小型研发团队架构实践方面的探讨却很少。中小型研发团队特别是50至200人的研发团队,在早期的业务探索阶段,更多关注业务逻辑,快速迭代以验证商业模式,很少去关注技术架构。这时如果继续按照原有的架构及研发模式,会出现大量的问题,再也无法玩下去了。能不能有一套可直接落地、基于开源、成本低,可快速搭建的中间件及架构升级方案呢?我是一个有十多年经验的IT老兵,曾主导了两家公司的技术架构升级改造,现抛砖引玉,与大家一起探讨这方面的问题。整个系列有18篇文章,可分为三个部分,包括框架篇、架构篇和公共应用篇。框架篇即中间件或工具的使用,如缓存、消息队列、集中式日志、度量、微服务框架等,工欲善其事,必先利其器。架构篇主要是设计思想的提升,有企业总体架构、单个项目架构设计、统一应用分层等。公共应用篇是业务与技术的结合,有单点登录和企业支付网关,以下是具体篇章的介绍:

一、框架篇——工欲善其事,必先利其器

如果说运维是地基,那么框架就是承重墙。农村建住房是一块砖一块砖地往上垒,而城市建大House则是先打地基,再建承重墙,最后才是垒砖,所以中间件的搭建和引进是建设高可用、高性能、易扩展可伸缩的大中型系统的前提。框架篇中的每篇主要由四部分组成:它是什么、工作原理、使用场景和可直接调试的Demo。其中Demo及中间件是历经两家公司四年时间的考验,涉及几百个应用,100多个库1万多张表,日订单从几万张到十几万,年GMV从几十亿到几百亿。所有中间件及工具都是基于开源,早期我们也有部分自主研发如集中式日志和度量框架。后期在第二家公司时为了快速地搭建,降低成本,易于维护和扩展,全部改为开源。这样不仅利于个人的学习成长、知识重用和职业生涯,也利于团队的组建和人才的引进。

1、集中式缓存Redis

缓存是计算机的难题之一,分布式缓存亦是如此。Redis看起来非常简单,但它影响着系统的效率、性能、数据一致性。用好它不容易,具体包括:缓存时长(复杂多维度的计算)、缓存失效处理(主动更新)、缓存键(Hash和方便人工干预)、缓存内容及数据结构的选择、缓存雪崩的处理、缓存穿透的处理等。Redis除了缓存的功能,还有其它功能如Lua计算能力、Limit与Session时间窗口、分布式锁等。我们使用ServiceStack.Redis做客户端,使用方法详见Demo。

2、消息队列RabbitMQ

消息队列好比葛洲坝,有大量数据的堆积能力,然后再可靠地进行异步输出。它是EDA事件驱动架构的核心,也是CQRS同步数据的关键。为什么选择RabbitMQ而没有选择Kafka,因为业务系统有对消息的高可靠性要求,以及对复杂功能如消息确认Ack的要求。

3、集中式日志ELK

日志主要分为系统日志和应用日志两类。试想一下,你该如何在一个具有几百台服务器的集群中定位到问题?如何追踪每天产生的几G甚至几T的数据?集中式日志就是此类问题的解决方案。早期我们使用自主研发的Log4Net MongoDB来收集和检索日志信息,但随着数据量的增加,查询速度却变得越来越慢。后期改为开源的ELK,虽然易用性有所下降,但它支持海量数据以及与编程语言无关的特征。下图是ELK的架构图。

4、任务调度Job

任务调度Job如同数据库作业或Windows计划任务,是分布式系统中异步和批处理的关键。我们的Job分为WinJob和HttpJob:WinJob是操作系统级别的定时任务,使用开源的框架Quartz.NET实现;而HttpJob则是自主研发实现,采用URL方式可定时调用微服务。HttpJob借助集群巧妙地解决了WinJob的单点和发布问题,并集中管理所有的调度规则,调度规则有简单规则和Cron表达式。HttpJob它简单易用,但间隔时间不能低于1分钟,毕竟通过URL方式来调度并不高效。下图是HttpJob的管理后台。

5、应用监控Metrics

“没有度量就没有提升”,度量是改进优化的基础,是做好一个系统的前置条件。Zabbix一般用于系统级别的监控,Metrics则用于业务应用级别的监控。业务应用是个黑盒子,通过数据埋点来收集应用的实时状态,然后展示在大屏或看板上。它是报警系统和数字化管理的基础,还可以结合集中式日志来快速定位和查找问题。我们的业务监控系统使用Metrics.NET InfluxDB Grafana。

6、微服务框架MSA

微服务是细粒度业务行为的重用,需要与业务能力及业务阶段相匹配。微服务框架是实现微服务及分布式架构的关键组件,我们的微服务框架是基于开源ServiceStack来实现。它简单易用、性能好,文档自动生成、方便调试测试,调试工具Swagger UI、自动化接口测试工具SoapUI。微服务的接口开放采用我们自主研发的微服务网关,通过治理后台简单的配置即可。网关以NIO、IoCP的方式实现高并发,主要功能有鉴权、超时、限流、熔断、监控等,下图是Swagger UI调试工具。

7、搜索利器Solr

分库分表后的关联查询,大段文本的模糊查询,这些要如何实现呢?显然传统的数据库没有很好的解决办法,这时可以借助专业的检索工具。全文检索工具Solr不仅简单易用性能好,而且支持海量数据高并发,只需实现系统两边数据的准实时或定时同步即可。下图是Solr的工作原理。

8、更多工具分布式协调器ZooKeeper:ZK工作原理、配置中心、Master选举、Demo,一篇足以;ORM框架:Dapper.NET语法简单、运行速度快,与数据库无关,SQL自主编写可控,是一款适合于互联网系统的数据库访问工具;对象映射工具EmitMapper和AutoMapper:EmitMapper性能较高,AutoMapper易用性较好;IoC框架:控制反转IoC轻量级框架Autofac;DLL包管理:公司内部DLL包管理工具NuGet,可解决DLL集中存储、更新、引用、依赖问题;发布工具Jenkins:一键编译、发布、自动化测试、一键回滚,高效便捷故障低。二、架构篇——思想提升

会使用以上框架并不一定能成为优秀的架构师,但一位优秀架构师一定会使用框架。架构师除了会使用工具外,还需要设计思想的提升和性能调优技能。此篇以真实项目为背景,思想方法追求简单有效,主要内容包括企业总体架构、单个项目架构设计、统一应用分层、调试工具WinDbg。

1、企业总体架构

当我们有了几百个上千个应用后,不仅仅需要单个项目的架构设计,还需要企业总体架构做顶层思考和指导。大公司与小商贩的商业思维是一样的,但大公司比较难看到商业全貌和本质。而小公司又缺乏客户流量和中间件的应用场景,中型公司则兼而有之,所以企业总体架构也相对好落地。企业总体架构需要在技术、业务、管理之间游刃有余地切换,它包括业务架构、应用架构、数据架构和技术架构。附档是一份脱敏感信息后的真实案例,有参考TOGAF标准。但内容以解决公司系统的架构问题为导向、以时间为主线,包括企业商务模型、架构现状、架构规划和架构实施。

2、单个项目架构设计

单个项目的架构设计如同施工图纸,能直接指导工程代码的实施。上一环是功能需求,下一环是代码实施,这是架构设计的价值所在。从功能需求到用例,到用例活动图,到领域图、架构分层,到核心代码,它们之间环环相扣。做不好领域图可能源自没有做好用例活动图,因为用例活动图是领域图的上一环。关注职责、边界、应用关系、存储、部署是架构设计的核心,下图是具体案例参考。

3、统一应用分层

给应用分层这件事情很简单,但是让一家公司的几百个应用采用统一的分层结构,这可不是件简单的事情。它要做到可大可小、简单易用、支持多种场景,我们使用IPO方式:I表示Input、O表示Output、P表示Process,一进一出一处理。应用系统的本质就是机器,是处理设备,也是一进一出一处理,IPO方式相对于DDD而言更为简单实用。

4、调试工具WinDbg

生产环境偶尔会出现一些异常问题,而WinDbg或GDB就是解决此类问题的利器。调试工具WinDbg如同医生的听诊器,是系统生病时做问题诊断的逆向分析工具,Dump文件类似于飞机的黑匣子,记录着生产环境程序运行的状态。本文主要介绍了调试工具WinDbg和抓包工具ProcDump的使用,并分享一个真实的案例。N年前不知谁写的代码,导致每一两个月偶尔出现CPU飙高的现象。我们先使用ProcDump在生产环境中抓取异常进程的Dump文件,然后在不了解代码的情况下通过WinDbg命令进行分析,最终定位到有问题的那行代码。

三、公共应用篇——业务与技术的结合

先工具再框架,然后架构设计,最后深入公共应用。这不仅是架构升级改造的正确路径,也是微服务架构实施的正确路径。公共应用因为与业务系统结合紧密,但又具有一定的独立性,所以一般自主开发,不使用开源也不方便开源。公共应用主要包括单点登录、企业支付网关、CTI通讯网关(短信邮件微信),此次分享单点登录和企业支付网关。

1、单点登录

应用拆分后总要合在一起,拆分是应用实施层面的拆分,合成是用户层面的合成,而合成必须解决认证和导航问题。单点登录SSO即只需要登录一次,便可到处访问,它是建立在用户系统、权限系统、认证系统和企业门户的基础上。我们的凭证数据Token使用JWT标准,以解决不同语言、不同客户端、跨WebAPI的安全问题。

2、企业支付网关

企业支付网关集中和封装了公司的各大支付,例如支付宝、财付通、微信、预付款等。它统一了业务系统调用各支付接口的方式,简化了业务系统与支付系统的交互。它将各种支付接口统一为支付、代扣、分润、退款、退分润、补差、转账、冻结、解冻、预付款等,调用时只需选择支付类型即可。企业支付网关将各大支付系统进行集中的设计、研发、部署、监控、维护,提供统一的加解密、序列化、日志记录,安全隔离。

在接下来的一段时间里,我会陆续推出此系列文章。因个人原因,发布顺序会根据本人的准备情况而作调整,敬请谅解。根据我们以往的经验,分享者主讲一个小时左右,业务研发就可以快速地进入项目实战。对于后面新加入的团队成员,也可通过WIKI自主快速学习。这是我们之前对自己的要求,尽量降低工具对人员的要求,简单实用、降低成本。文章中部分Demo采用C#语言,但到了框架或架构层面,与语言本身没有太多直接的关系。如RabbitMQ、Job、Redis和集中式日志ELK,它们服务端的部署是一样的,只是客户端语言版本稍有不同。所有Demo都可直接运行,服务地址及管理后台也可直接访问。因为部署在公有云,牵涉到成本费用的问题,我计划持续到今年9月底。以上这些小小的基础工作,希望能够帮到中小型研发团队,解决他们项目中遇到的实际问题。愿与你一起成长,你的分享和点赞是我此次付出的动力,谢谢!

中小研发团队架构实践之总体架构

企业总体架构是什么,有什么用,具体怎么做呢?以我曾任职的公司为案例,一起来探讨这个问题。这家公司当时有200位研发人员和200多台服务器,我刚进这家公司时,他们的系统就已经玩不下去了,总是出现各种问题,例如日常发布系统时或访问量稍微过大时,系统就会出现很多故障,而且找不到故障发生的根本原因。我进公司后主要任务就是对这个系统进行升级改造,花了一个半月的时间写了那份企业总体架构文档,文档共有124页,直接指导了之后的技术改造,下图是那份文档的目录。

一、企业商务模型

企业商务模型的内容主要包括主营业务、商务模式、商务主体、竞品分析、组织架构、商务运作模型和业务流程等。

主营业务即公司做什么业务,商业模式即公司怎么赚钱,商务主体即哪几个人在一起做这门生意,竞品分析即了解竞争对手的情况,组织架构即公司部门是怎么划分的。组织架构图中标出人数,根据系统与业务之间对应关系,可以了解系统中哪些模块使用频率高,以及业务与其对应模块的复杂度。商务运作模型即公司是如何运作的,售前做计划,找供应商把东西买进来后,经过服务和结算,再卖给我们的经销商和采购商,使我们获得利润,售后进行大数据分析最后又指导着我们的售前,整个过程形成良性循环。可以把一家公司想象成一台机器,输进去的是钱,转一转后,又能够生出更多的钱出来。

最后是业务流程和附档资料,业务流程包括预订流程、订单处理流程、产品供应流程、财务结算流程、账户管理流程。企业商务模型的建立,指导着整个应用系统模型的建立,它是整个应用系统建设的基础和前提,毕竟应用系统是为业务服务的。

二、架构现状

架构现状的内容主要包括:功能架构、应用架构、数据设计和物理架构。

2.1、功能架构

功能架构主要包括功能、角色和权限三部分。功能是企业服务,用户使用的每一个功能,就是企业的每一个服务。角色是用户操作的归类,功能与角色的对应关系即权限。了解系统架构的现状,从功能架构开始。

2.2、应用架构

应用就是处理器,应用架构的内容包括现有架构图、Web应用现状、作业小应用(Job)现状和接口架构。其中,接口是应用层面的关键,它是一个程序与另外一个程序交互的部分。

应用架构图表列出了哪些业务逻辑没有被重用,换句话说业务逻辑被多少个应用调用,就需要被重复开发多少次,一旦改了一个地方,就要同时改多个地方,导致系统开发效率非常低下。各业务逻辑如预订逻辑,虽然被多个应用调用,但它们与应用是没有关系的,业务逻辑可以独立的存在,也可以寄宿于多个应用。业务逻辑是一个业务操作的抽象,而业务应用与业务部门共同完成了业务操作。

2.3、数据设计

100多个数据库,一万多张表,能否使用一张E-R图来表示呢?它是可以的。数据设计依赖于企业的数据,而不是数据库的设计,对企业数据适当做归类,会直接导致数据设计,最终画出E-R图,数据设计完成后,数据库设计就自然而然出来了。超越库、超越表去看这张E-R图,可以看出它包括产品、订单、结算、用户、基础设施这五类数据。低层的E-R图可以变,但是高层的E-R图一般不会变化,因为它是根据你的业务模型而定,业务模型稳定,高层E-R图也是稳定的。数据库只要早期设计得好,是可以做到易伸缩、易拆分的。下图从内往外看,一个框既可以是一个库,也可以是一个模块,还可以是一个表。在业务发展的早期它可以是一个库,里面有5个模块,中期可以分为5个库,后期以更低级别可以分为更多的库,这与业务阶段及系统复杂度相关。在数据的设计完成后,数据库的设计也就很容易规划和调整。

以上是数据库、数据表之间的静态关系,接下来我们介绍数据的流转状态即状态图。通过数据状态图去了解现有数据流转变迁,如国内订单状态变迁图,这种图的价值不仅在于数据库层,还在于服务化。图中的从等待支付到支付成功,中间有个支付行为,通过这个支付行为把数据状态变更为支付成功,否则继续等待,直到超时关闭订单。这个支付行为可以做成一个微服务,然后由不同的应用去调用。

2.4、物理架构

物理架构的内容主要包括IDC机房、机房之间访问关系、机房内服务器物理部署图、机房与业务分布、网站架构、数据库架构、集群清单和域名清单。将这些内容以列表和图形方式整理出来,就会很容易了解和发现问题,只有发现问题才能解决问题,特别是在全局体系架构方面,这也是表和图的价值所在。当时这家公司共有5个地区、8个机房,虽然只有200多台服务器,但分布很散,导致物理结构复杂,通讯也很复杂。技改前故障不断,其主要的一个原因就是物理架构不合理,运维要占60%、70%的责任,当时却把责任归咎为应用架构,这是个错误的方向。物理架构的不合理,应用架构是很难合理的,因为物理架构是我们的基础设施,位于最底层,下层为上层服务,运维要为应用服务,应用要为业务服务,业务要为客人服务。

三、领域模型

领域模型关注概念,关注职责、关注边界、关注交互,只有先确定职责和边界,交互才会很清晰。领域模型是针对现有问题域提出一个系统解决方案,然后在图表上建立完整的模型,如同用AutoCAD画的施工图纸一样。领域模型属于概要设计阶段,对于单个应用架构设计,首先需要了解业务和功能需求、用例图、用例活动图,然后才是领域模型。业务流程图是对业务操作的抽象,领域图是对业务逻辑代码的抽象。

建立领域词汇是建立领域模型的第一步,它能统一词汇明确概念,以减少一词多义、一义多词的情况。概念一旦确定,再扩展属性和行为,然后把它当作一个单元与其它事物构建在一起,就会很容易形成模型,领域模型与企业商务模型中的业务流程图有参考对应关系。领域模型在实现时可大可小,在业务的早期,在系统比较小的情况下,它有可能是一个类。当系统做大了以后,它可能是个DLL库。再做更大一点的时候,它可能是一个服务,给不同的应用去调用。每一个方法都有成为服务的潜质,特别是在系统中后期。领域模型是业务逻辑代码的施工图纸,它不仅有利于对现在系统业务逻辑的了解,同时也指导未来的架构改造。

四、架构规划

当我们了解了业务、了解了架构的现状,发现现有架构的问题,接下来就可以做中远期架构规划,以及架构的调整和具体实施。架构规划内容包括:顶层架构规划、网站功能规划、应用规划、SOA规划、分层架构规划、数据库规划和物理规划等。

4.1、顶层架构规划

上图是顶层架构的俯视图和侧视图。第一张图是俯视图,坐在飞机上看,整个顶层架构最外层的是功能,中间的是业务操作,内层的是数据。功能对应业务系统的用户界面,操作对应业务系统里的服务,数据对应业务系统的数据存储如数据库。第二张图是剖面图,切一刀来看,上层是应用,中层是服务和框架,下层是基础设施数据中心。从图中的服务层可以看出,服务的归类跟业务流程的归类有很大关系。

4.2、网站功能规划

网站功能规划就是功能的重新划分,对照着架构现状,未来的功能应该如何调整?如案例中的国内网站功能规划,分别画出了全局功能图、采购商功能图、平台商功能图和供应商功能图。其实在做网站功能规划的时候,更多需要考虑现状,而不是未来调整的部分,如果没有很大问题,则不做调整,尊重历史。因为有些东西(如名称)用户已经使用很久了,调整往往比较难,合理大于准确。

4.3、应用规划

系统是什么,系统=元素 关系。应用架构是什么?应用架构=应用 架构。应用就是系统的最小单元,应用分类和应用编号则构成了应用关系即应用的架构。如上图中的案例,应用分类新建了框架FX和公共业务系统CBS,在原有的200多个应用中并没有这两个产品线,而是分布在了不同的业务线中,从而导致重复建设。应用编号是给每个应用分配一个六位的数字ID,就如同我们的身份证一样,头两位表示产品线,中间两位表示子系统,最后两位表示应用,如100206。应用编号是应用管理、依赖和追踪的基础,集中式日志和监控框架都有使用到应用编号。

4.4、SOA规划

SOA规划就是接口规划,它的归类与商务模型中的业务流程有参考对应关系。上图案例有五个服务中心:预订服务、订单处理服务、产品供应服务、财务结算服务和公共服务。每个服务只需要实现一套自己的逻辑,我们的前台、后台、接口、作业小应用等都可以调用,服务的逻辑跟我们的业务逻辑是一致的,修改代码的时候只需要改一个地方就可以影响到所有调用到这服务的前端应用。

4.5、分层架构

分层架构看似很简单,但保证整个研发中心都使用统一的分层架构就不容易了。那么如何保证整个研发中心都使用统一的分层架构呢,以达到提高编写代码效率、保证工程统一性的目的?先简单介绍下当前两种比较流行的分层架构体系,一种是领域架构:仓储层Repository Layer、领域层Domain Layer、应用服务层Application Layer、表现层Presentation Layer和基础公共层Infrastructure Layer,请见第一张图;另一种是相对传统地分为三层:数据层Data Layer、应用逻辑层Business Layer和表现层Presentation Layer,请见第二张图。

领域架构和三层架构之间有什么区别?我们是这样认为的,在早期我们做三层架构的时候,大都以表来做驱动的,在做领域架构的时候,大都以业务逻辑来驱动的,两者的区别确实比较明显,但到了现在,如果都以业务逻辑为中心的话,实际上两者并没有本质区别。当时,我所在公司采用了第二种分层法,我们希望把分层做得极简,也就是说哪怕刚毕业进来的员工,在分层时基本上也不会乱。而相对第一种分层法,第二种分层法简单很多。每一个应用的代码量都不应该很大,一旦工程变得过大,我们就会把它适当拆分,而不是全部放在一个单块应用里。总之,我认为分层越简单,整个软件结构就越清晰,代码就越容易统一。把工程做得极简,才有利于复制,有利于业务的快速构建,有利于规模化、稳定可靠。

4.6、数据库规划

数据库是整个信息系统中生命周期最长、最难修改的部分,所以要加强规划。数据库的设计至少要提前两步,具体根据高层E-R图和数据设计来新建数据库,早建要比晚建好。数据库调整的代价大、周期长,长时间产生的问题,需要长时间来解决,先在新库里解决新表,再根据当前业务和应用的需求,逐步调整旧表。

4.7、物理规划

物理架构的规划内容包括集群规划和域名规划。首先是集群规划。20 倍规划、5 倍设计和 1.5 倍实施:规划和设计要大一些,但实施时小一些,这样不仅便于将来的扩展,也节省了当前的费用;两个逻辑网络:一个内网和一个外网,两个负载均衡,两个防火墙,安全隔离内外网;四条产品线:国际、国内、新业务以及公共业务,单点登录和企业支付网关等公共业务也属于一条产品线;六个集群:Web 集群、SOA 集群、中间件集群、数据库集群、Job 集群和 ITD 集群。以上横向集群与纵向产品线形成了一个矩阵结构,也基本确定了网络基础架构。对于域名规划。对内的域名该改的改,该停用的停用,该合并的合并。对外的域名要尽量少改,要改的话也要有历史继承性(如跳转),要尽量减小对用户的影响。

4.8、其它

除以上架构规划外,还有一些其它重要项,如源代码管理规划、文档管理规划、技术选型和团队分工。为什么还要做这些呢?因为统一了源代码怎么放、每个部门的文档怎么放、将来要用什么工具版本,才利于团队的协作,基于统一的环境才能有更高层次地提升。对于团队分工,需要逐步对齐组织架构与系统的架构规划。对于技术选型,需要注意中间件的引进,要有节奏性,力量要相对集中,要小规模试点,找非核心项目,试用成功后再进行大规模推广。

五、架构实施

做完架构规划后,就是架构实施落地了。我们的架构实施整体思路是:树目标、给地图、立榜样、抓重点、造文化、建制度、整环境、组建架构部。架构部内招几名老程序员,外招几个架构师。内部走出去,提高眼界。外部牛人请进来,落地了解历史和业务。技术建议是:SOA服务化、基础设施平台化、公共业务服务化、加强项目概要设计。当研发团队达到200多人、有了几百个应用,且在故障不断的情况下,不能与以前一样没有设计就开始编码,而是做加强项目概要设计及评审。后面的补与前面的防,两手都要抓,两手都要硬。具体计划是:Roadmap分步实施,改造一期、改造二期、改造三期,近细远粗、实事求是、逐步细化、逐步完善。不断立技术改造项目,不断将技改与业务研发项目相结合,技改即是工单、工单即是技改。避免对业务过多地影响,并不断有业务价值输出,这是架构改造得以持续实施的关键!

以上简单地介绍了总体架构的编写方法,我们的编写思路是先了解业务,建立企业商务模型,主要包括静态的商务主体、组织架构和动态的商务运作模型和业务流程。再了解架构现状,建立现有信息系统模型,主要包括功能架构、应用架构、数据设计和物理架构。一个是商务,一个是电子,两者即是整个公司的电子商务系统。然后在企业商务模型和现有系统模型之上建立领域模型,领域模型它相对稳定,直接指导着接下来的架构规划,最后一定要落地即架构实施。附档是去掉敏感信息后的真实案例,它的价值如下:

Big Picture,全局蓝图,起到方向性和指导性。将隐性知识显性化,方便传达、广而告之。对于新员工的价值,快速入门。对于老员工的价值,了解全局,过程梳理,然后专注于自己的部分。

关于企业总体架构,你可以参考标准TOGAF(开放组体系结构框架)。其实,我们是在完成那份文档后才知道TOGAF,它们之间有很多相似之处和不同之处。TOGAF的内容主要包括业务架构、应用架构、数据架构和技术架构,而我们当时只是以解决公司系统架构问题为导向、以时间为主线,内容有企业商务模型、架构现状、领域模型、架构规划和架构实施。方法论很重要,但看到事物本身的特点,深入问题以及找到解决办法更为重要。欢迎点赞和拍砖!

如果本文对你有帮助,别忘记给我个3连 ,点赞,转发,评论,

说明:本文限于篇幅,故而只展示部分内容,完整的学习文档小编已经帮你整理好了,

答案获取方式:已赞、已评、已关!

学习更多JAVA知识与技巧,关注与私信博主777