互联网架构下的高可用与高并发设计
- 高可用设计
- 架构层面:
- 集群(负载均衡技术)
- 热备
- 多机房部署
- 应用层面的可用性
- 自我保护能力
- 监控
- 高并发
- 架构设计
- 异步化架构
- 冗余
- 代码层面
- 客户端层面的优化
- 服务负载均衡
- 分布式锁
- 服务的幂等性
高可用设计
我们高可用设计其实核心是为了解决单点故障问题而导致的服务不可用。
架构层面:
集群(负载均衡技术)
采用集群来达到服务的高可用,但是会涉及到负载均衡:
- 硬件负载 :F5、NetScalar;
1.1.F5通过心跳线来与standBy服务器建立检查机制 - 软件负载 :apache、nginx、lvs、Haproxy;
2.1.Nginx,lvs+keepalived(通过建立虚拟Ip)的方式
负载均衡算法:随机、轮训、hash、最小连接数、权重随机等。
热备
即服务是采用一台设备但是会有多设备是standBy的状态,如果master挂了那么slaver的机器会通过选举产生新的leader继续提供服务,比如:
1.**zookeeper:**采用Zab协议使用改良版的Paxos算法
2.redi-sentinel: 采用Raft
3.etcd: 采用Raft
多机房部署
分为同城灾备,异地灾备,需要进行跨机房的状态同步,其中的成本十分的高。
应用层面的可用性
采用集群部署来增加可用性,但是应用层面最重要的还是容错性
针对容错性分为:
在微服务的生态下,先在前端的一个请求可能会涉及到后台服务器在多个服务之间的调用,
1.如果其中某个服务出现故障会导致请求堆积,这样就需要我们进行failfast(快速失败)的处理,来保证后面请求的可用性。
2.甚至如果在单位时间内的某个服务失败次数超过设置的阈值,那么我们可以在一段时间内进行服务隔离,这样让服务器将堆积的请求可以处理完成。
3.代码容错处理,包括:
3.1.第三方接口的数据如果本身不是那么重要可以在报错时不用影响主流程。
3.2.再比如如果我们针对数据库进行了分库分表,如果某个时间段内的某个库出现了故障,如果查询此库中的数据不是那么重要,那么我们也可以不影响主流程继续往下进行。
自我保护能力
针对超过现在系统架构的tps,如果出现流量高峰,一般会采取一下方式处理:
1.熔断,防止服务被压蹦,我们会将服务进行一定时间的隔离。
2.限流,我们可以用限流的算法(令牌桶,漏桶,计数器-滑动窗口)来控制访问的量。
3.缓存,我们可以做热点数据的缓存,或者可以在服务启动时,做数据的预热,将一些不会变动的数据进行预先存储到缓存中。
4.主动降级,我们可以在一些活动的期间,蒋某一些无关紧要的功能进行关闭,以此来确保核心业务的流程。
监控
1.系统资源(CPU、内存、磁盘)
2.应用中通过日志系统将一些数据进行收集上传到监控平台以此来定位具体是哪个子系统出现的问题,或者通过错误码的设计,也可以很快定位到具体的子系统。
3.告警手段,通过不同的错误级别,分别对应邮件->短信->电话通知
高并发
单位时间内能够同时处理的请求数量。
设计一下的关键字解释:
RT(response time)一个请求的相应时间。
Throughput(吞吐量)
QPS(TPS)=并发数/平均响应时间
架构设计
- 微服务->服务拆分|性能瓶颈,我们可以针对核心的服务搭建更大的集群以此来提高性能的处理能力。
- 数据库层面(关系型)
。数据分片(分库分表)
。读写分离 - 服务的无状态设计,可以方便后期通过增加服务器的方式更好的水平扩容。
- 分布式缓存(热点数据)
- 容量规划
我们可以通过PV(page view)和UV(user view)来获取访问的次数,这样我们可以知道用户的访问数量、吞吐量,当我们从历史的数据分析可以估算用户数的增长以此来确定我们系统大概在什么时候需要增加设备、增加多少设备要抗住将来更大的流量。
异步化架构
我们可以增对实时性不是很高的场景或者只需要最终一致性的场景通过异步队列来实现。
冗余
通过增加副本来提升系统的可用性。比如:CDN
代码层面
- 不要在循环中调用RPC接口
- HashMap创建中如果知道数据条数,但是一开始创建的map很小,在设置数据时平凡的扩容会十分小号内存和时间
- 数据的预热
- 查询数据库的语句优化
- 异步化(线程池的使用)
- 内存的使用
客户端层面的优化
1.减少请求的数量-》合并请求
2.数据缓存-》减少请求次数
服务负载均衡
- 集群的好处
。流量的分发
。扩容和缩容
*负载均衡
。DNS轮训
。二层负载(mic地址)
。三层负载(ip)
。四层负载(IP+port)
。七层负载(请求协议中的uri地址)
分布式锁
- redis(AP)
- zookeeper(cp)
- etcd(cp)
- 数据库
服务的幂等性
服务器收到的多次请求对于数据的辩护和以此请求带来的效果是一致的。
通过手段:
- 状态机的幂等:一个数据在整个生命周期中所激励的状态
- 数据库的唯一约束
- token(可以再数据库中一次请求后生成,后续查询到有这个值则不作任何变动)
- redis来实现幂等,setNx(key,value),多个进程调用只有一个能成功