更好的阅读体验 \large{\color{red}{更好的阅读体验}} 更好的阅读体验
前言
可以将某个项目或产品的架构体系按照如下方式分层:
- 业务层面:项目业务体系
- 技术层面:
- 数据架构:数据持久层策略
- 应用架构:应用层的实现方式
- 部署架构:部署方式,自动化持续集成等策略
针对每一层也随着时间的变化而变化。
业务架构
单体模式
早期的互联网产品多为单体系统,特点是以业务为导向,往往形成业务团队各自为战,在新业务线出现时需求大量增长。
这里补充部分业务模式的概念:
- B2B:企业与企业之间的供销模式
- B2C:企业面向消费者的交易模式
- C2C:消费者与消费者之间的交易模式
- O2O:线上与线下业务混合模式
随着公司的业务发展,业务层面会不断向 B2B、B2C 等扩张。
这就引出了单体架构的局限性:
- 功能冗余:B2B、B2C 会有相同的业务重叠,导致多个单体系统功能近似或冗余
- 数据不互通:多个跨域业务下,对于同一用户群体的数据不能互相沟通
功能冗余会带来成本的浪费(开发运维成本),数据的不互通带来业务壁垒,跨域业务间数据难以打通。
中台战略
为了解决单体架构带来的问题,阿里在 2015 年提出了中台战略,这是一种企业架构,而不是单纯的技术层面。
这里再细化一下单体系统相较中台战略的局限性:
- 技术和业务架构上:
- 单体系统功能重复,而抽调出中台可以大幅减少冗余代码的开发
- 业务集成度高,开发和运维成本高,而中台模式下,基础业务也下沉到技术部门,甚至通过技术反推业务发展
- 对于多变的需求,中台战略可以将业务细化分层,上层业务针对产品快速迭代,下层业务持续沉淀,为上层业务封装底层接口
- 组织架构上:
- 单体架构下,往往是每个项目就是一个团队,团队随项目扩张不断增大或重组复用,利用率低
- 中台模式下,可以将上层业务和下层业务的团队分离,并将各个中台单独立项,提高利用率
除此之外,中台战略在业务扩展方面具备先天性优势:
去中台化
虽然中台战略看起来已经足够优秀,但目前又呈现出了去中台化的趋势。
在大市场不断跟风的情况下,中台战略暴露出来的问题也越来越多:
- 中台战略需要过硬的技术支撑,大部分的公司没有完善的中台构建方案
- 公司业务差距太大,中台复用度不高,中台带来的生产价值远远小于中台的开发和运维成本
- 高度依赖中台的业务体系之间,耦合度严重提高
甚至中台战略的鼻祖——阿里的中台战略发展也没有达到预期,在反垄断的大背景下,减少大而集中的部门,拆分不同业务线独立发展,降低耦合。
数据架构
单体模式
早期的单体项目业务简单,一般只需要单体数据库(多为 MySQL),但随着业务体量不断增大,这一时期往往引发追逐商业大型数据库(Oracle)。
单体数据库架构多见于早期的 JavaWeb 和 SSH 项目:
- 通过 JDBC 直连,简单直接
- 数据库用 MySQL,或大型商业 DB
- 单库上的机器 IO 及 cpu 性能很快达到上限
主从读写
淘宝以前就是 MySQL,后来更换为了 Oracle,直到 2007 年又从 Oracle 回迁为了 MySQL,这个历程中实现了主从库的部署与读写分离。
这一架构的特点如下:
- 应用层连接多个数据库,数据库之间形成主从关系,主库为写,从库上读,分离读写压力
- 数据库集群策略,一主多从或双主单写,提升数据层的容灾和高可用能力
但是这一架构也避免不了带来新的问题:
- 数据不一致:主库到从库之间数据要进行同步,不同的数据同步策略会产生对应的问题
- 单库瓶颈:业务越来越多,表数量越来越多,甚至可能会出现单个库几百张表的现象
- 数据局限:依然无法解决单表大数据的问题
分库分表
为了解决单库的数据局限性问题,又引入了分库分表的解决方案:
- 水平分库:将一个库的数据拆分到多个库中
- 水平分表:将一张表的数据拆分到多个表中
- 垂直分表:将一张表的多个字段拆分到多个表中、
对于垂直分库,一般是分布式架构下,按照业务将数据库进行拆分,保存不同的表和数据。
对于分库分表也会不可避免地带来新的问题:
- 分库:不同的数据库,所以无法使用数据库事务,而分布式事务的效果并不理想,多采用幂等和最终一致性方案
- 分表:拆了再聚合是一对矛盾,例如按下单时间维度的分表,需要按用户排序统计变得异常困难
高速缓存
数据库往往是系统的瓶颈,即便通过垂直分表可以将冷热数据进行分离,但从本质上仍然无法提升 IO 瓶颈。
因此,又提出根据数据的冷热划分,热点数据如类目、商品基础信息放在告诉缓存中,再其他数据延迟加载方案:
- redis:性能可靠,纯内存,自带分片,集群,哨兵,支持持久化,几乎成为当前的标准方案
- memcache:性能可靠,纯内存,客户端需要自己实现,无持久化
- ehcache:非分布式,简单,易维护,可用性一般
引入缓存,在实际生产中也会遇到问题:
- 缓存击穿:单一 Key 失效,遇到大量请求压垮数据库
- 缓存雪崩:大量 Key 失效,遇到大量请求压垮数据库
- 缓存穿透:不存在的 Key,遇到大量请求压垮数据库
- 数据不一致问题:数据库更新,缓存也要更新保持一致性
数据多样化
数据库和缓存只是一种基本的存储手段,除了这些,其他各种形式的存储结构和存储需求也相继涌现:
- NoSQL:非关系型数据库,如:Redis,MongoDB,Neo4j
- 分布式文件存储:存储不同文件,如:Hdfs,Fastdfs,CephFs,MinIO
- 搜索引擎:解决海量数据搜索问题,如:Lucene,Elasticsearch
针对这些需求,带来的架构层面的挑战也是巨大的:
- 数据可靠:面对高并发等场景,要保证数据服务的高可用
- 数据运维:多数据服务下,对应系统的容灾措施也相应复杂,维护成本水涨船高
- 数据安全:要求能够针对不同数据的访问权限进行隔离
应用架构
单机调优
互联网早期项目模式多为 MVC 模式:
- Model: 模型代表一个存取数据的对象或 JAVA POJO。它也可以带有逻辑,在数据变化时更新控制器。
- View: 视图代表模型包含的数据的可视化。
- Controller:控制器作用于模型和视图上。它控制数据流向模型对象,并在数据变化时更新视图。它使视图与模型分离开。
这一时期的项目单机特点是:
- 每个项目独立为一个 MVC 结构,部署在应用服务器上(tomcat、jboss、websphere,weblogic)
- 需求迭代快,项目体量越来越大,一个 war 包动辄几百兆
- 技术方案不成熟,有大量历史问题遗留(屎山)
由于各种各样的单机性能瓶颈问题,这一时期的项目往往都推崇 JVM 单节点调优。
动静分离
为了解决单机瓶颈,又提出应用服务集群的动静分离的方案:
- 静态响应:tomcat 对静态文件响应一般,提取静态文件,直接由nginx响应
- 动态代理:后端 api 通过代理转发给 tomcat 应用机器(集群)
在这一时期的项目特点是:
- 项目结构大幅调整,由原来的一体化 MVC 转换为后端api + 前端形式
- 前后端的分工变得更明确,互相并行开发,独立部署
这一时期大量的 Apache + tomcat 已初具前后端分离架构的雏形,直到后来被 nginx 几乎一统江山
SOA
单纯的动静分离只解决了自己服务的项目结构,跨项目接口调用时,必须经过 rest 请求,不利于服务之间的交互。
因此又提出了面向服务的架构——SOA:
- SOA 是一种建设企业T生态系统的架构指导思想,SOA的关注点是服务
- 服务是最基本的业务功能单元,通过将业务系统服务化,可以将不同模块解耦
- 各种异构系统间可以轻松实现服务调用、消息交换和资源共享
对于 SOA 的落地目前有两种主要表现形式:
- 分布式服务化:采用 SOA 去中心化的落地方式,典型的落地的技术栈:Dubbo + Zookeeper,服务之间依靠 RPC 框架互相调用
- 集中式管理:偏重于以 ESB 作为基础支撑技术,以整合集成为核心,将各个新旧系统的业务能力逐渐在 ESB 容器上聚合集成
这一阶段的项目特点鲜明,技术难度大:
- 界限把控:服务的粒度、拆分和公共服务提炼需要架构师的全局把控,设计不好容易引发混乱
- 部署升级:服务数量增多,人工部署变的不现实,必须借助自动化运维
- 服务可用性:抽调的微服务因需要被多个上层业务共享,对系统整体的容灾能力要求提高
- 熔断和限流:做好服务熔断和限流,提防服务单点瓶颈造成整个系统瘫痪
微服务
当分布式架构成为时代主流后,一种基于 SOA 的升级版——微服务架构也横空出世,它和分布式架构的主要区别如下:
- 微服务架的拆分颗粒度更细、更小,中台化得以实现
- 服务的治理强,容易构建成熟的容灾和高可用集群体系
- 微服务的技术栈更全、更成体系,技术栈钱内部的技术组件也是基于微服务的思想来做的
同时,这种架构也有需要平衡的地方:
- 服务拆分:拆分粒度并非越小越好,太小会带来部署维护等一系列成本的上升
- 接口约束:系统增多,各个服务接口的规范化日益重要,要求有统一的服务接口规范,推动企业消息总线的建设
- 权限管理:服务之间的接口要做好鉴权,借助 oauth2 等手段,实现服务之间的权限认证
部署架构
单机部署
最早的单机项目部署方案大多为:
- 采用 web 包部署与发布,db 等资源同台机器连接,例如早期采用 tomcat + war 的形式,后来则是 java -Jar,
- 单机性能达到瓶颈后,只能通过提升机器配置的方式来提升性能,成本较高
这种单机部署架构在业务发展的初始阶段尚可支撑,但随着访问量的上升,这种部署架构无法达到业务的性能要求。
角色划分
如果项目再大一些,可以把数据库、缓存、消息等中间件剥离出去,单独机器来部署:
- 多台机器:tomcat 与 mysql 各自独占机器资源
- 针对性扩容:tomcat 应用机更注重 cpu 的运算和内存,mysql 更注重 IO 与磁盘性能,针对各自情况扩容
在这种方案下,可以将 dba 分离出来单独维护数据库服务器,但同时也带来了数据安全方面的问题。
应用集群
应用集群部署带来的最大优势就是——负载均衡,此时期常见技术栈为:
- apache:早期负载均衡方案,性能一般
- nginx:七层代理,性能强悍,配置简洁
- haproxy:性能同样可靠,可做7层或4层代理。
- lvs:四层代理,性能最强,linux 集成,但配置麻烦
- f5:四层代理,硬件负载
这一方案的特点是:
- session 会话:集群环境下,用户登陆需要分布式 session 做支撑
- 分布式协同:分布式环境下对资源的加锁要超出线程锁的范畴,上升为分布式锁
- 调度问题:调度程序不能多台部署,容易跑重复,除非使用分布式调度,如 elastic-job
- 机器状态管理:多台应用机的状态检测与替换需要做到及时性,一般 niginx 层做故障转移
- 服务升级:滚动升级成为可能,灰度发布
对于更大的部署,往往采用多层代理:
- 动静态均有多个 nginx 负载,入口统一交给 lvs 负载
- 但是 lvs 依然是单一节点,即使 keepalived 做到高可用,流量仍然需要在唯一入口进入
异地访问
为了提升系统的物理容灾能力,解决机器部署的扩容问题,又产生了多机房部署策略:
- 将相同的系统部署多份,分散到异地多个机房,或者电信、移动等多个网络中
- 不同地点,不同网络接入的用户,有了不同的访问入口和选择
此时,对于异地访问也有对应的访问策略:
- DNS 轮询:通过 DNS 的策略轮询调用,可以实现机房层面的扩容
- CDN:就近原则,使用户获得就近的机房访问相关资源
多机房部署成本较高,一般只有规模较大,具有强硬的市场支撑的公司才会使用,同等条件下远不如上云来的实惠
云平台
近年来,针对中台化的建设及微服务数量的飙升,在快速部署和资源弹性伸缩的需求下,容器化与云平台开始大火。
云平台部署下,常见的技术方案为:
- 虚拟化:vm 方案,Openstack,Vmware,VirtualBox
- 容器化:docker
- 持续集成:Jenkins,CI/CD
- 编排:swarm,k8s,k3s
- 云化:私有云到企业云
云平台部署与传统部署方式最大的优势在于资源的灵活扩容和回收,针对活动期间弹性扩容,非活动期间回收闲置资源。
但同时云平台部署需要运维层面的高度支撑,门槛较高,其次,对应风险上,云瘫痪也会造成不可计量的损失,要对系统风险进行合理预估
总结
纵观今年互联网架构的演变,不难看出没有任何体系是一成不变的,架构体系往往随着业务需求不管革新。
因此,架构要服务于业务,而不能脱离业务存在,任何架构的设计都要贴合实际的业务场景。
在技术上不断收敛,因为引入新技术必然会带来新问题,尽量追求原生,降低项目的开发和维护成本。
对于架构的扩展性要适度取舍,要考虑到互联网产品的周期,不能过分保留。