设计一个系统,不仅需要考虑实现业务功能,还要保证系统高并发、高可用、高可靠等,在系统容量规划(流量、容量)、SLA指定(吞吐量、响应时间、可用性、降级方案等)、压测方案(线上、线下等)、监控报警(机器负载、响应时间、可用率等)、应急预案(容灾、降级、限流、隔离、切流量、可回滚)等方面
应用无状态易于扩展.实际中应用无状态,配置文件有状态。
是否拆分取决于系统规模与可利用资源. 如果确实需要拆分,一般来说有以下几种情况:
服务注册与发现,服务分组、隔离、路由,服务治理:限流、黑白名单等.
题外话: 之前有被问到一个问题:能不能用nginx代替微幅服务API网关? 这个问题还是需要根据系统规模来看;如果说你只有两三个微服务,每个微服务的部署节点也只有两三个,那不嫌麻烦的话可以手工配置nginx;但如果你微服务数量较多、部署节点较多时,那手动配置nginx就会成为一个灾难;这个时候服务注册于发现以及统一API网关就会起到非常巨大的作用,让你不在进行繁琐的nginx路由配置,不用担心服务扩容与缩容修改路由配置.
消息队列一般用来解耦一些不需要同步调用的服务或者订阅一个自己系统关心的变化。使用消息队列可以实现服务解耦、异步处理、流量削峰/缓冲等.
针对较大流量涌入,系统需要进行一些特殊的设计平稳过度,一般来说可以系统强一致性,保证最终一致性.
使用了消息异步机制的场景下,可能会出现消息丢失,因此需要考虑进行数据校对和修正来保证数据的一致性和完整性(消息补偿)
异构的目的是实现数据的自我控制,当其他系统出问题或者自己的系统出问题不会互相影响,一般通过消息队列实现数据分发.
若订单表按照订单ID进行分库分表,那么查询用户所有订单就会导致全表扫描;异构一套用户订单表,按用户ID进行分库.
如果请求的数据来源较多,则会增加请求的响应时间和影响服务的稳定,此时可以将用到的数据进行异构存储,形成数据闭环:
缓存对于读服务可以说是一枚抗流量的银弹.
设置请求的过期时间,如针对响应头Expires
、Cache-control
进行控制,适用于对实时性不太敏感的数据;
预先下发访问素材,APP离线缓存
可以考虑将一些公共的或者不频繁改的资源推送到离用户最近的CDN节点,如公共JS、图片等
对于没有CDN缓存的应用来说,可以使用Nginx搭建一层接入层,使用如下机制:
如使用tomcat时,可采用堆内缓存和堆外缓存;堆内缓存重启时丢失,堆外缓存如local redis cache,就是使用本机redis缓存,降低网络消耗. 适用于数据量不大的结构.
数据量较大单机不能处理,可采用分布式缓存
针对一次请求多份数据,根据其先后顺序以及依存关系,进行并发处理请求,以减少耗时.
对于高可用服务,很重要的设计是降级开关,主要有以下思路:
限流的目的是防止恶意请求流量,恶意攻击,或者防止流量超出系统峰值;原则是限制流量穿透的后端薄弱的应用层. 主要有以下思路:
如果某个机架或者机房出现故障,可使用以下方式切流量:
版本化的目的是实现可审计可追溯,可回滚;如果有版本化机制,当出现故障或错误时,可进行回滚,如事务回滚
、代码库回滚
、部署版本回滚
、数据版本回滚
、静态资源版本回滚
.
如重复支付、重复扣减等
业务系统在进行消息消费时需要进行幂等处理,包括使用第三方支付异步回调时的幂等处理
不同的流程进行分离,必要时进行关联;
在后台系统的设计中,需要考虑操作结果的可预览、可反馈.
对于重要的功能,要设计审批流,比如调整价格,对操作日志记录,从而保证操作可追溯可审计
建立文档库,包括设计架构、设计思想、数据字典、业务流程、现有问题,此外业务代码特殊需求需要由注释
包括代码和人员的备份,代码入版本库; 人员的话一个系统至少两个全面了解的人(小公司压力大)
京东:《亿级流量网站架构核心技术》张开涛