写在前面
时节如流,转瞬间2018已经过去,之前太忙于奔跑,一直说的读书笔记整理,也搁置了4个多月。回顾这一年给我惊喜很多的书有很多,后面会专门整理下。计划从这两本架构相关的书开始,惊喜的其实并不是书中有什么高深的套路,而是一种思维的冲击,用DD大神的话总结就是
《架构即未来》&《架构真经》 其实就是道与术的较量,道看似浅显却很高深,术看似实用却受限于道。
架构之道
架构之道在于人
可扩展性的关键是人
- 人增加越多,每个成员的单位沟通和协调成本就越大。尤其个性解放的年代,每个小伙伴的性情各异,成长背景,工作经历都不尽相同,所以导致成员间的性格差别,做事风格迥异,要大家统一遵守一个规则,显得相对困难,所以耗费在沟通和协调的成本不断变大。
- 合适的人,在合适的时间,做合适的事,都是一种美好的设想。所以招人时候,偏向于招味道相近的人。这样的话期盼沟通成本,理解成本和默契程度更高,所以才会有些通用的评价人标准,聪明要性皮实等。
组织的重要性
人是系统扩展中最重要的因素,那么如何把人组织起来完成工作也就同样重要。
- 团队规模 ,过大过小都会出问题。
- 团队过小 成员会过度劳累,陷入加班循环 (比如少于6人)
- 团队过大 沟通不畅,上产效率低下,士气低落(比如多于15人)
规模过大团队生产率低下的原因:两个极端,因为高级工程师没有足够精力指导导致新人上手慢,反过来如果高级工程师花费大量时间指导新人,那么会导致老人效率低下。
- 团队分工,警惕情感型冲突
分工代表责任划分,一旦职责划分不清,就会出现情感型冲突,比如这个需求该谁做,这块问题该谁负责。而不是认知型冲突,比如这个问题该怎么做。
可扩展性和可用性失败的共同原因是责任不清。
- 团队结构
- 职能型组织:按照主要目的或职能设置部门
- 优势:职责划分清楚,容易分工,便于专注
- 缺点:跨部门沟通 出奇难
- 矩阵型组织:引入多种职能角色在团队中
- 优势:专人解决沟通问题,分而治之
- 缺点:个人精力分散,汇报多人,成员压力大
- 敏捷型组织:自我管制,自我组织。
- 优势:提升团队的创造力
- 缺点:闭环的成本高
- 职能型组织:按照主要目的或职能设置部门
最好的架构、需求和设计源于自组织的团队
- 团队管理
- 团队管理者 应该以人为本
- 以己为本 把员工当成向上爬的梯子,踩着他们往上走
- 以人为本 为所有一流员工建立好向上爬的梯子
- 团队建设
- 建设团队 (类比球队) 不断寻找负担的起的最好的人才
- 优化团队 (类比花园)
- 播种 增加新的,更好的人才
- 施肥 培养和发展要保留的人才
- 除草 尽早淘汰表现差的人,就能越快找到合适的替代者,让团队向前发展
- 团队管理者 应该以人为本
架构之术
大道至简
避免过度设计
- 如何界定过度:设计是否浅显易懂,是否让其他同学可以快速理解
- 表现为把一件事做的过于复杂和以复杂的方式去完成一个任务
在设计中要警惕复杂的解决方案
在这一块儿的感触还是比较深的,订单导出的早期跑的比较快,没有清楚自己的定位复用底层详情能力,而开始疯狂造轮子,为了获取一个字段而专门设计了一个client,然后再设计一个组件来专门做这两个数据聚合,由于都是并发取,发现新增的一个字段会导致老的导出出问题,用这种非常复杂的设计去获取一个字段。而换个角度,详情把字段能力补齐,而导出复用能力,会来的更加方便,维护起来架构也异常简单,过度设计的成本很高。
方案中带有扩展DID
设计方案时候,要想的远些,比如应对是现有流量的10倍流量时候,这套设计是否会出现重大问题,而真正部署的时候如果是无状态的可以动态扩展的最好,比如核心应用最少要预留五倍容量。
- Design 设计应对20-无限容量的挑战
- Implement 实施3-20倍容量
- Deploy 部署1.5-3倍容量
三次简化方案
- 简化方案范围 比如砍掉些不必要的功能,释放更多资源投入到更有价值的事情上
- 简化方案设计 易于理解、低成本、高效益和可扩展的方式来完成工作
- 简化方案实施 最简单的实施是可扩展的衡量标准
帕累托原则: 收益的80%来自于20%的工作
分而治之
AKF扩展立方体
这里重点介绍下AKF扩展立方体,受益匪浅。之前组内分享了下订单搜索冷热数据分离的分片维度及依据,这个订单搜索的AKF架构演进之路,后面会专门整理出来。
-
X轴: 关注水平的数据和服务克隆,比如主备集群,数据完全一样复制。克隆多个系统(加机器)负载均衡分配请求
- 优点:成本最低,实施简单
- 缺点:当个产品过大时,服务响应变慢
- 场景:发展初期,业务复杂度低,需要增加系统容量
-
Y轴: 关注应用中职责的划分,比如数据业务维度拆分。比如交易库,商品库,会员库拆分。
- 优点:故障隔离,提高响应时间,更聚焦
- 缺点:成本相对较高
- 场景:业务复杂,数据量大,代码耦合度高,团队规模大
-
Z轴: 关注服务和数据的优先级划分,数据用户维度拆分。比如上面按用户维度买卖家切分 数据分片
- 优点:降低故障风险,影响范围可控,可以带来更大的扩展性
- 缺点:成本最高
- 场景:用户指数级快速增长
水平扩展
- 向上扩展 购买更大的软件而实现的扩展
- 向外扩展 通过复制或拆分服务或数据库而分散事务负载
- 异地多活 灾备
配置 | 网络 | 服务器 | 数据库 | 存储 | 节点互连 | 总成本 |
---|---|---|---|---|---|---|
单数据中心 | 100% | 100% | 100% | 100% | 0 | 100% |
冷热双数据中心 | 200% | 200% | 200% | 200% | 1 | 200% |
双活双数据中心 | 200% | 200% | 200% | 200% | 1 | 200% |
三活三数据中心 | 150% | 150% | 150% | 200% | 3 | ~166% |
先利其器
适当使用数据库
- 关系型数据库
- 适用 当需要ACID属性来保证数据之间的关系和一致性时
- 优势 提供了高度的事务完整性,支持sql,可用于发杂查询
- 缺点 难以扩展 成本高 海量数据效率低
- 非关系型数据库
- 适用 不需要关联其他数据,也不需要事务完整性
- 优势 无需sql层解析,读写性能快,存储格式多样
- 缺点 无事务处理
马斯诺锤子:当你只有一个锤子时,任何东西看起来都像个钉子
前车之鉴
失败乃成功之母
抓住每个机会,尤其是失败的机会,学习经验并吸取教训,不断的从错误和成功中学习。
最好的经验来自于失败的错误,而不是成功。
之前订单搜索和订单详情都有两个经典设计失败案例,一直说要整理下,还没有整理出来,看到这段话时候很触动。两次设计失败都是为了追求通用性,复用性,所以将不同功能集于一身,成为一个万能接口,导致功能支持起来后期比较吃力。举个例子订单搜索支持通用搜索(非订单搜索),而早期入参是按订单搜索维度设计,所以导致通用个搜索入参特别不友好。早期订单详情支持实时+非实时一起,而发现实时的可返回字段远远少于非实时字段,实时非实时对应支持的扩展组件也不尽相同,不得不重构抽离。
有备无患
用“泳道”隔离故障
- 隔离的好处 不赘述
- 隔离的原则
- 泳道不共享
- 泳道之间不进行同步调用
- 异步调用设置超时和开关控制
- 限制泳道间异步调用
避免系统串联
这个比较常见的雪崩源头都是系统串联,其中一环发生问题,不断导致上游出问题,而上游显得很被动,串联组件受多重失败乘法效应的影响。减少以串联形式连接的组件数量。
启用和禁用功能
限流降级的重要性,最大程度的保证应用不被其他应用拖垮。核心依赖的跑不了。
超然物外
力求无状态
有状态会限制可扩展性,降低可用性并增加成本
异步通信
尽可能异步通信
尽可能优先考虑异步通信而不是同步通信,异步通信可以削峰解耦,极大程度的避免耦合。同时同步调用使得整个程序停下来等待响应,它捆绑的所有服务和层,进而导致连锁性延迟或故障。
思考数据价值
海量订单下的数据价值显得格外重要,一些无用的垃圾信息或者不重要信息占据昂贵的存储资源上,同时需要提供这种久远历史的查询,对整个系统的意义显得格外低下,之前超过6个月的物流详细信息进行了删除并引导到对应物流公司网址查,后来据说要保留下来以提供查询。还有就是6年前订单也要跟现有订单一起查,体会不到这个看似无比强大的能力背后带来的价值和整个系统架构为了实现该功能所付出的代价,也许站的角度不同,不被感知。
画蛇添足
避免写入后立即验证刚写入的数据
比较典型的场景是消息推送后反查,系统发送消息比如通知该订单已经支付,然后马上过来再查下确认下是否真的变成已支付。这种对实时性要求很高,只能引导去查实时数据库,造成很大浪费,理论上消息体中的信息就可以直接拿到,所见即所信,当然有的说消息推送的只是部分信息,需要来查全信息,那这种更倾向于推送的时候把信息退全,避免被动即时拉取。
意犹未尽
梯级存储策略
将存储成本与数据价值匹配,包括删除价值低于存储成本的数据,并非所有的数据对业务都有相似的价值,事实上,随着时间的推移,数据的价值经常下降。因此不应该用单一的存储解决方案以同样的成本存储所有的数据。
RFM价值 Recency 指问题中数据多久前被访问过 Frequency 数据多久被访问一次 Monetization 数据的业务价值
分类处理不同负载
通过分区和故障隔离,处理独特的工作负载,以最大限度的提高整体可用性、可扩展性和成本收益
完善监控
把必须监控应用作为一条架构原则,看看整体监控策略确保可以回答
- 有问题吗?
- 问题在哪里?
- 什么问题?
附上完整思维导图