架构设计三大定律
墨菲定律
任何事没有表面看起来那么简单所有的事都会比预计的时间长 - 可能出错的事情总会出错 - 担心某种事情发生,那么它就更有可能发生
康威定律
系统架构师公司组织架构的反映
按照业务闭环进行系统拆分/组织架构划分,实现闭环、高内聚、低耦合,减少沟通成本如果沟通出现问题,应该考虑进行系统和组织架构的调整 适合时机进行系统拆分。不要一开始就吧系统、服务拆分拆的非常细,虽然闭环,但是每个人维护的系统多,维护成本高 - 微服务架构的理论基础 - 康威定律
二八定律
80%的结果取决于20%的原因
高可用
所谓高可用,即要保证系统在几乎任何时候都能正常运行,功能正常,保证系统不出问题,“永不宕机”。
1.单机系统下的可用性问题,从Nginx->Tomcat->db/soa来看,单点问题会影响系统的高可用。比如要是这个链路上其中一个单点挂了,整个系统就不可以用了。(Nginx负载均衡等,Tomcat提供服务,db存储数据)。所以引申出来主备/集群模式,防止单点问题。
2.高并发场景下,请求过多也会因为后端瓶颈点引起整个系统down掉,如周杰伦演唱会抢票,高铁抢票,所以一般情况下对并发场景我们会限流,采用mq等消息队列形式削峰,保证后端系统不会down掉。
设计建议
1.减少单点
去去单点首先要识别出整个系统所有主链路的单点,如机房(同城异地双机房)、应用服务器、DNS服务器、SFTP服务器、LBS(基于位置服务)
缓存服务器、数据库、消息服务器、代理服务器和专线等。
如系统通过专线调用对方服务,需要考虑同时拉联通和电信的专线,联通或电信的专线还是有一定效率出现问题但是同时出现问题的概率就会小很多。优先使用软负载(负载软件如Nginx),使用硬负载(外部网络和服务器间的硬件设备如F5)兜底。
2.减少依赖
减少DNS依赖,减少远程服务依赖。DNS依赖可以尝试设置本地host,用工具给所有服务器推送最新的域名映射关系,通过本地缓存或者近端服务减少RPC(远程过程调用)调用。
3.限制循环
避免无限死循环,导致CPU利用率百分百,可以设置for循环的最大循环次数,如最大1000次
4.增加限流
对外服务增加限流,注意限流的值最好是压测过的,如果没有压测过,只能设置成平时的峰值流量,否则可能增加一点流量就不能提供服务了。
5.控制流量
避免异常流量对应用服务器产生影响,可以对指定指定服务设置流量限制,如QPS(每秒查询率),TPS(每秒处理事务数),QPH(每小时总请求量),QPD(每天总请求量)
6.精准监控
对CPU利用率,load,内存,带框,系统调用量,应用错误量,PV(页面浏览量),UV(独立访客量,以cookie为主)和业务进行监控,避免内存泄露和异常代码对系统产生影响,配置一定要精准,如平时设置内存利用率是50%,监控可以配置成60%进行报警,这样可以提前感知内存泄露问题,避免应用无响应。
7.无状态
服务器不能保存用户状态数据,如在集群下不能用static保存用户数据,不能长时间把用户文件存放在服务器本地。服务器有状态会难以扩容,出现单点问题。
8.容量规划
定期对容量进行评估,如大促前进行压测和容量预估,根据需要进行扩容。如双11进行扩容。
9.功能开关
打开和关闭某些功能,如消息量过大,系统处理不了,把开关打开后直接丢弃信息不处理。上线新功能增加开关,如果出现问题就关闭新功能。
10.设置超时
设置连接超时和读超时设置,不应该太大,如果是内部调用连接超时可以设置成1秒,读超时3秒,外部系统调用连接超时可以设置成3秒,读超时设置20秒。
11.重试策略
当调用外部服务异常时可以设置重试策略,每次重试时间递增,但需要设置最大重试次数和重试开关,避免对下游系统产生影响。
12.隔离
应用隔离,模块隔离,机房隔离,线程池隔离。按照优先级,不变和变几个维度来隔离应用和模块,如抽象和不变的代码放在一个模块,这个模块的代码几乎不会修改,可用性高,经常变的业务逻辑放在一个模块里,这样就算出现问题,也只影响某一业务。不同业务使用不同的线程池,避免低先级任务阻塞高优先级,或者高优先级任务过多影响低优先级任务永不执行。
13.异步调用
同步调用变成异步调用,解决远程调用障碍或者调用超时对系统的影响。
14.热点缓存
对热点数据进行缓存,降低RPC调用。如B系统提供名单服务,B系统可以提供一个client SDK提供近端缓存服务,定期去服务器读取数据,减少RPC调用。
15.缓存容灾
当数据库不可用时可以使用缓存的数据。并设置分级缓存,如优先读取本地缓存,其次分布式缓存。
16.分级缓存
优先读取本地缓存,其次读取分布式缓存。通过推模式更新本地缓存。
17.系统分级
对系统进行分级,如ABC三个等级,高级别系统不依赖与低级别系统,并且高级别系统比低级别系统高可用虑高
18.服务降级
如果系统出现响应缓慢等状况,可以关闭部分功能,从而释放系统资源,保证核心服务的正常运行。需要识别哪些服务可以降级,比如突然有大量消息流入,导致服务不可用,我们会直接把消息丢掉。或者设置流控,拒绝为低级别系统提供服务。
19.流量蓄洪
当流量陡增时,可以将请求进行蓄洪,如把请求保存在数据库中,再按照指定的QPS进行泄洪,有效保护下游系统,也保证了服务的可用性。调用对方系统,对方系统缓慢或者无响应时,可采取自动蓄洪。
20.服务权重
在集群环境中,可自动识别高性能服务,拒绝调用性能低的服务,如在集群环境中,对调用超时的服务器进行权重降低,优先调用权重高的服务器。
21.依赖简化
减少系统间的依赖,如使用消息驱动。A和B系统通过消息服务器传递数据,A和B系统使用数据库进行读写分离,A系统负责往数据库写数据,B系统负责读数据,因为数据存放在数据库中,当A不可用时,短时间不影响B系统提供服务。
22.弹性扩容
根据资源的使用率自动或者手动进行扩容。如带宽不够用,快速增加带宽。
23.灰度和回滚
发布新功能只让部分服务器生效,且观察几天逐渐切流,如果出现问题只影响部分客户。出现问题快速回滚,或者直接下线灰度的机器。
24.减少远程调用
优先调用本地JVM内服务,其次是同机房服务,然后是同城服务,最后是跨城服务。如A调用B,B调用互联网C的系统获取数据,B系统可以把数据缓存起来,并设置数据的保鲜度,减少B对C的依赖。配置中心把注册服务的地址推送到调用服务的系统本地。参数中心把参数配置信息推送到系统的本地内存,而不是让系统去远程服务器获取参数信息。
25.熔断机制
增加熔断机制,当监控出现数据大幅涨跌时,及时中断,避免对业务产生更大影响。如我们做指标计算时,指标可以计算慢,但不能算错,如果发现某个用户的指标环比或同比增长一倍或跌零,会考虑保存所有信息,并终止该用户的指标计算。
26.运行时加载模块
我们会把经常变的业务代码变成一个个业务模块,使用JAVA的ClassLoader在运行时动态加载和卸载模块,当模块有问题时,可以快速修复。
27.代码扫描#
使用IDEA代码分析等工具进行代码扫描,识别出程序中的BUG,如空指针异常,循环依赖。
28.自动备份
程序,系统配置和数据定期进行备份。可以使用Linux命令和shell脚本定时执行备份策略,自动进行本地或者异地备份。出现问题时能快速重新部署。
29.线上测压
系统的对外服务需要进行压测,知道该服务承受的QPS和TPS,从而做出相对精准的限流。
高并发
所谓高并发,即能够同时接受处理千万级乃至亿万级的并发访问。
高并发又分为cpu密集型和io密集型。前者要求网站的计算能力要高,后者要求网站的吞吐能力要高。
高并发设计有几个原则如下:
1.无状态
无状态应用,便于水平扩展
有状态配置可通过配置中心实现无状态
实践: Disconf、Yaconf、Zookpeer、Consul、Confd、Diamond、Xdiamond等
2.拆分
系统维度:按照系统功能、业务拆分,如购物车,结算,订单等
功能维度:对系统功能在做细粒度拆分
读写维度:根据读写比例特征拆分;读多,可考虑多级缓存;写多,可考虑分库分表
AOP维度: 根据访问特征,按照AOP进行拆分,比如商品详情页可分为CDN、页面渲染系统,CDN就是一个AOP系统
模块维度:对整体代码结构划分Web、Service、DAO
3.服务化
服务化演进: 进程内服务-单机远程服务-集群手动注册服务-自动注册和发现服务-服务的分组、隔离、路由-服务治理
考虑服务分组、隔离、限流、黑白名单、超时、重试机制、路由、故障补偿等
实践:利用Nginx、HaProxy、LVS等实现负载均衡,ZooKeeper、Consul等实现自动注册和发现服
4.消息队列
目的: 服务解耦(一对多消费)、异步处理、流量削峰缓冲等
大流量缓冲: 牺牲强一致性,保证最终一致性
(案例:库存扣减,现在Redis中做扣减,记录扣减日志,通过后台进程将扣减日志应用到DB)
数据校对: 解决异步消息机制下消息丢失问题
5.数据异构
数据异构: 通过消息队列机制接收数据变更,原子化存储
数据闭环: 屏蔽多从数据来源,将数据异构存储,形成闭环
6.缓存
用户层:
DNS缓存
浏览器DNS缓存
操作系统DNS缓存
本地DNS服务商缓存
DNS服务器缓存
客户端缓存
浏览器缓存(Expires、Cache-Control、Last-Modified、Etag)
App客户缓存(js/css/image...)
代理层:
CDN缓存(一般基于ATS、Varnish、Nginx、Squid等构建,边缘节点-二级节点-中心节点-源站)
接入层:
Opcache: 缓存PHP的Opcodes
Proxy_cache: 代理缓存,可以存储到/dev/shm或者SSD
FastCGI Cache
Nginx+Lua+Redis: 业务数据缓存
应用层:
页面静态化
业务数据缓存(Redis/Memcached/本地文件等)
消息队列
数据层:
NoSQL: Redis、Memcache、SSDB等
MySQL: Innodb/MyISAM等Query Cache、Key Cache、Innodb Buffer Size等
系统层:
CPU : L1/L2/L3 Cache/NUMA
内存
磁盘:磁盘本身缓存、dirtyratio/dirtybackground_ratio、阵列卡本身缓存