前言
程序开发毕竟还不是搬砖这种无脑体力劳动,需要事先有标准,有架构,有设计,绝对不是新公司今天创立,明天就可以开始编码的。其实很多公司在起步的时候没有财力和资源建设独立的基础架构或平台架构部门,甚至运维团队都没有,但是这不妨碍我们心中有一个蓝图知道努力的方向,本文我们就简单聊聊平台架构相关的工作内容(或者说作为一个技术管理,应该去梳理、统一、明确的部分)的蓝图。由于本文覆盖的内容比较多,只能抛砖引玉大概提一些,无法一一展开太详细的东西。图中的数字是我认为的优先级,仅供参考。
规范
规范它虽然不是一个实际的代码或组件,只是一个文档,但是我觉得非常重要。没有规范,那么员工加下去任何一行新代码可能都是错的,整个研发流程也可能会因为没有规范导致很多不必要的事故产生。
- 代码提交&分支管理规范,我们可以在gitflow基础上根据实际情况(结合运维流程,项目复杂度,团队人数,发布周期)进行细化,涉及到:
- 有哪几个常驻分支,哪几个临时分支?
- 分支命名规范?
- 提交代码描述规范?
- 分支迁出和合并的时机?
- 哪些分支普通开发没有权限直接提交?
- 测试用什么分支,上线又用什么分支?
- 多版本并行开发如何提测?
- Hotfix如何处理分支?
- 编码规范,比如Java代码可以以阿里Java开发手册为基础,大家一起过一遍,针对项目的实际情况(时间要求,对性能要求),选择其中的一些坚决执行,然后补充一些其它的。我们也可以让大家的IDE使用(导入)统一的Code Style Template来要求一致的编码格式。因为Code Style的不一致导致提交的时候大范围的代码新增删除完全会污染提交,让大家很难看出提交的代码到底改了什么。
- 数据库设计规范。阿里Java开发手册里包含了一小部分数据库设计规范,术业有专攻,这个还是应该请资深DBA来给出一定的规范,包括但不限于:
- 命名(表和字段前缀后缀命名,外键字段命名、通用字段命名统一)规范
- 字段设计类型规范
- 字段冗余规范
- 通用字段规范
- 索引使用规范
- ……。可以参考《朱晔的互联网架构实践心得S2E1:业务代码究竟难不难写?》中提到的一些内容
- 项目结构规范,对于Java Maven项目来说基本目录结构比较统一,对于其它语言的项目(比如Python),目录结构没有一定标准的话,项目源码结构会千奇百怪,最好还是对于项目结构有一个规范,包括:
- 三层结构目录划分
- 多环境(Profile)配置文件
- 服务接口、服务实现、Web、Job模块命名
- 最后是项目管理流程,有一些公司会有专门的PMO,有一些初创公司研发Leader也会充当PMO的角色,虽然这个活一般和平台架构没啥关系,不管怎么样,既然是项目肯定少不了项目管理,作为技术管理角色需要关注的一个点,项目管理流程也是比较重要的:
- 迭代周期,迭代周期中的大环节大概发生的时间点
- 开哪些会,开会时间点是?(日站会、周例会、启动会、回顾会、复盘会、排期会、PRD预评审会、PRD评审会、测试用例评审会、上线方案讨论会)
- 项目生命周期中每一个角色产出哪些文档?
- 任务在哪里管理,每一个角色怎么去维护任务状态的流转?不可能任务的每一个状态的流转都由PMO来做
基础框架
使用一些基础框架来做应用开发是必须的,对于Java技术栈,大家所熟悉的框架有Spring Cloud全家桶、Spring Boot套件(封装的各种starters)、Mybatis等,直接使用这些框架进行开发是可以的,但是更建议的是由基础架构团队封装自己的框架,自己做一层封装,我们可以以类似Spring Boot Starter的模式,为所有的组件封装自己的Starter模块,好处是:
- 方便进行统一的外部依赖类库 & 库版本管理和约定
- 方便针对公司内部情况做更合适的自动配置(甚至实现0配置)
- 如果内部技术栈是异构的话,使用统一的框架有助于技术栈后端基础设施的打通
- 为所有的模块打通监控,自动配置AOP做相应的拦截统一抓取获取监控数据
- 模块之间可以相互整合和配合,实现1+1>2的效果
- 还有很重要的一点是,我们可以提供相应的管控后台来配合框架使用,把框架的配置、管理和审计暴露在控制台上
其实说白了,就是使用自己封装的类库占坑,哪怕只是一层浅浅的封装,也是很有好处的,不仅仅是做了各种统一(使用框架的统一,框架版本号的统一),更多的是因为占了坑(当然,要扩展做Java agent动态字节码注入的方式也是可行的,这种方式的缺点是没有办法提供API给业务使用),以后直接可以通过升级框架通过IOC组件替换+AOP直接做各种扩展(不需要再麻烦业务团队了)。
我们来看看这里脑图上大概列出的一些业务开发需要用到的常见模块(可以看一下我们公司开源的框架SummerFramework(github.com/ke-finance/… ) ,当然开源出来的模块比较少,实际公司内部封装了这里提到的所有模块:
- Web MVC:可以基于Spring MVC进行封装,增加一些模板引擎的支持等
- 数据访问:可以基于MyBatis或Mybatis Plus+Druid数据源进行封装,做一些额外的功能,比如敏感数据加密保存
- RPC服务调用或微服务:可以基于Dubbo或Spring Cloud(Feign+Eureka)进行封装,在客户端方面扩展一些更智能的LB算法,以及路由策略(比如灰度)等功能
- Web API:可以在Spring MVC+Swagger UI基础上实现功能,提供统一的RESTful服务端API的标准,比如规范化API版本、响应结构体自动包装(自适应)、错误包装、HATEOAS超媒体资源导航整合、数据加解密实现、Collection资源的规范化、自动的mock接口的实现等
- 配置:可以基于携程Apollo(github.com/ctripcorp/a… )客户端进行封装,做自动配置
- 消息:可以封装RabbitMQ、RocketMQ的客户端实现统一的消息API,然后扩展事务消息(收发消息和业务逻辑本地事务在一个事务中处理)等功能
- 缓存:可以基于CacheCloud(github.com/sohutv/cach… )提供Redis缓存服务
- 调度:可以封装XXLJob(github.com/xuxueli/xxl… )或ElasticJob(elasticjob.io)提供调度服务
- 日志监控:可以基于Micrometer实现应用打点,找一个APM(Skywalking github.com/apache/skyw… 或Pinpoint github.com/naver/pinpo… )整合trace功能,扩展logback做日志脱敏,扩展Spring Boot Actuator Endpoint等功能
- 锁:可以基于Redisson封装分布式锁,使用统一的API来提供内存锁和分布式锁
- 分布式事务:主要是两块,同步2PC分布式事务处理(比如我们开源的https://github.com/ke-finance/dts ),异步的saga思想的实现,参考https://github.com/eventuate-tram/eventuate-tram-sagas 。
- 弹性:流控+隔离+熔断,考虑基于https://github.com/alibaba/Sentinel 来实现,可以是独立的模块提供服务,也可以整合到Web API或RPC模块中去
- 安全:可以基于Spring Security进行扩展,加入符合业务需求的风控策略进去
基础平台
基础平台(管理平台)需要和基础框架打配合,框架是开发的时候使用的,平台更多的是开发或运维人员做技术运营时使用的。很多开源框架都已经提供了管理后台,我们需要做的可能只是一些小修改,比如包括:
- 打通公司内部自己的账号登录体系和权限体系
- 根据不同的环境(开发、测试、灰度、生产)部署多份管理控制台
- 根据需要看是否需要做多租户的改造,实现业务隔离
有些平台是重流程的,这些可能需要自主开发,大概介绍一下脑图上提到的这些:
- 配置平台:如果使用了携程Apollo,自然就是使用Apollo的管理后台
- 微服务管理平台:这里我列出了两个方面的工作,一个是服务中心,更多的是服务维护、管理、监控方面的功能,可以基于Spring Cloud Admin进行改造;一个是服务集市,更多的是服务标准化方面的管理,比如服务上线需要的文档,接入的监控系统,以及上线后统一的文档中心,服务集市类似于App Store的概念
- 缓存平台,如果使用了CacheCloud,可以使用CacheCloud的管理后台
- 日志平台,分为两块,一块是日志收集展示基本ELK已经是标准;还有一块是日志异常报警,可以自己来开发,基于Kafka消费日志异步做日志筛选+聚合结合自己公司的IM和邮件体系做报警
- 数据库管理平台:
- DDL/DML工作流:开发提交申请,主管审批,自动执行,外加自动的风险检测,优化建议等
- DDL/DML变更通知:方便大数据以及运营团队针对感兴趣的数据库和表进行订阅,在DDL应用到各个环境(测试、生产)的时候能够第一时间得到通知可以进行人工、自动处理(类似before,after Filter的概念)
- 数据库知识库:有一个统一的地方查看数据库的结构说明、字典枚举的定义
- 当然数据库管理平台还可以进一步做数据库监控、慢SQL优化原因分析等功能
- 全链路追踪平台:比如如果使用Skywalking的话可以实现它提供的管理台,主要功能无非是依赖拓扑分析、Trace查看、服务性能分析等
- 指标查看平台:分为两块,Dashboard一般可以考虑直接使用Grafana,报警的话虽然Grafana也有Alert但是还是建议在更底层(数据源头)去做,可以基于流处理去做或基于定时拉的方式去实现
基础中间件
中间件是指独立部署的不具有业务逻辑耦合 的通用服务,存储服务在广义上归到中间件也不是不可以,这里大概列了几个典型:
- MQ代理(Broker,不是Proxy),比如RabbitMQ、RocketMQ、Kafka
- API网关,有很多开源的网关实现,比如Kong(github.com/Kong/kong )、Spring Cloud Gateway,我们也实现了一套https://github.com/ke-finance/tesla ,一般网关的主要功能是调用路由、协议转换、调用编排,然后也会以插件和过滤器形式提供很多安全、弹性方面的扩展功能
- DB代理,比如类似https://github.com/flike/kingshard 和https://github.com/Qihoo360/Atlas 的MySQL Proxy,实现数据库的读写分离、分表分库、故障转移、弹性处理、监控、SQL优化等功能
- ES集群,也可以理解为中间件,毕竟ES其实做的就是基于Lucene的分布式集群管理工作
这些中间件虽然很多时候做的是Proxy背后的其它服务,但是节点本身很可能是有状态的,也需要考虑中间件本身的高可用性问题。
基础服务
一般而言如果公司具有多个项目的话,项目之间肯定会用到一些通用的内部和外部能力,这些能力和业务逻辑没有太多关系,可以考虑把这些能力进行统一的封装独立部署以微服务形式提供出来,这样所有项目都可以快速对接。
在这里把基础服务分为了两类,一类是没有业务逻辑的纯基础服务,往往是对接封装一个或多个外部服务通道,另外一类是包含一些业务的业务基础服务。对于第一类基础服务你可能会想,既然是对接外部服务通道直接使用他们的SDK或服务是不是直接在业务系统使用那些三方SDK就好了,基础服务是需要做什么呢?我觉得基础服务应该这么封装:
- 封装外部服务的SDK,一般而言比如短信也好、推送也好、存储也好,都会使用多家提供的服务做备份、降级,通过我们的SDK提供统一的对内API,屏蔽不同SDK的API差异
- 提供一个服务端,在服务端做数据落地,落地的目的有几个:
- 方便和外部进行服务消费对账
- 方便出错的时候查找原因
- 方便和外部服务同步调用状态(比如短信到达)
- 方便进行服务余额预警
- 服务端除了做数据落地,由统一的服务端做出口的好处是:
- 做权限控制,一般而言即使是公司内部的项目进行基础服务的调用应该也是需要先申请再使用的,甚至需要做服务调用量的控制(类似在内部再实现一层SaaS)
- 收敛调用源IP
- 集中管理调用外部SaaS服务的密钥
- 外部服务的降级和切换策略更换比较方便
- 给接入方做报警
- 做一个管理后台,虽然外部服务提供方作为SaaS产品一般都会有不错的控制台(其实更多的时候,不可能把外部服务的控制台的权限放给所有人看,内部业务方看自己的基础服务控制台即可),但是我们内部做一个管理后台意义还是很大的,主要的功能一般是:
- 统一登录
- 账号(包括Secret)申请和分配,以及配额、限流等配置(管理员权限)
- 调用记录(请求、结果)查看
- 调用模板的配置(考虑一下是不是放开服务的使用,比如短信、邮件、推送一般是基于模板的,模板需要内部外部审核后才能使用)
如果每一个服务都有控制台的话,可以大大方便业务方的自主接入和问题排查,这是基础服务封装非常有价值的一个点,对于大点的公司内部项目众多就更需要把基础服务在内部进行SaaS化了,而且最好对于不同的基础服务打通接入方(统一的地方来申请所有需要的基础服务)。
这里脑图上大概列了一些常见的基础服务和业务服务,每一个公司根据自己的业务一般都会不尽相同,基础服务包括:
- 短信:接入多个短信渠道,根据政策、费率、到达率等情况路由
- 文件存储:接入多个小文件存储服务(比如七牛、腾讯云),根据存储服务提供的功能,文件大小、费率等情况路由
- 邮件:接入内部和外部(比如SendCloud)的邮件服务,根据使用场景进行路由
- 推送:接入多个推送渠道(比如极光、个推),并且做用户、设备的关系维护
- 唯一ID:全局唯一ID的生成
- 图形、滑动、点击、智能验证码:提供统一的验证码服务,可以根据场景自动选择验证码类型
- 电子签章:接入多个电子签章服务,根据费率等因素路由
- 地图服务:接入多个外部地图服务,根据功能以及接入方使用的地图进行服务选择
业务服务包括:
- RBAC权限控制:统一的RBAC配置后台,以及方便的SDK
- 通用表单服务:根据后台配置的表单自动生成界面,以及表单信息的收集
- 状态机:可以借鉴https://github.com/hekailiang/squirrel ,基于状态(State)、行为(Action)、转移(Transition)、条件(Condition)等概念,构建基于数据库的状态机平台
- 统一支付:聚合支付,业务方可以快速接入多种支付渠道,并且统一支付可以提供统一的SDK和H5来实现统一的支付收银台
- 工作流、爬虫、SSO……不详细说明了
工程效率
接下去也简单提一下工程效率和运维范畴的事情,虽然这和平台架构没啥太大关系,但是这两块是很重要的技术基建工作:
- 源代码仓库:比如可以选择Gitlab或atlassian三件套的Bitbucket
- 内部类库仓库:比如Java的Maven仓库,可以自己搭建Nexus仓库
- 项目管理平台:可以选择SaaS产品(比如Tower、Teambition),比较有名的是atlassian三件套的Jira
- 知识管理平台:可以选择SaaS或开源Wiki产品,比较有名的是atlassian三件套的Confluence
- Bug管理平台:比如可以选择禅道或直接复用Jira
- 代码质量分析:比如可以搭建SonarQube平台
运维
这里提到的一些运维系统相关工作有的公司是架构团队来建设的,列一个大概:
- CI/CD平台:一般而言需要自己结合公司的工作流程做一套CI/CD平台(底层可以基于Jenkins(或直接SSH+脚本)封装),这个平台需要结合公司的工作流程去做,比如谁可以发起流程,每一个发布环节需要谁来审批,发布时间窗口等等
- DNS平台:一般会直接使用域名管理商的平台或类似DNSPod这种平台
- CMDB:一般都会根据自己的情况自建平台,进行运维各个层次相关资源的元数据以及配置管理
- 监控:一般会基于Prometheus+Grafana+Zabbix等开源项目来打造运维的基础监控
- CDN平台:一般是用云的,比如七牛、又拍或三大云服务的CDN都可以
- 集群配置管理:这个不是指CMDB,是指批量进行集群配置应用操作,管理操作的平台,比如Chef、Puppet、Ansible、Fabric,一般也是基于开源改造封装或直接用开源的
- 容器编排:比如K8S平台,一般可能会基于k8s的API做一套自己的k8s管控平台或选用类似Rancher这种更好用更高层的服务,完全基于命令行的k8s运维不是很高效易用
- 容器镜像仓库:比如Docker私有仓库Harbor
总结
好吧,的确一些中大型互联网公司是有超过100个内部系统是和研发相关的,甚至需要有专门的导航网站来管理工程效率、运维、基础框架、基础服务、基础中间件、基础平台的这些网站,这些系统本身的维护工作量也是不小的,一整理就会发现原来除了业务程序还有这么多周边的东西是为研发服务的,欢迎大家针对本文的内容进行补充。