软件开发通常会提到一个词“三高”,即高并发、高性能、高可用。具体指标定义,如:高并发要求QPS大于10万;高性能要求请求延迟小于100毫秒;高可用性要求高于99.99%。接下来,我们将重点关注这三个高并发。我们用QPS(QueriesPerSecond,每秒查询率)来衡量系统的承载能力。架构策略是什么?1、负载均衡就是所谓的两拳四手。高并发支持场景的首选方案是集群部署。一台服务器承载的QPS是有限的,多台服务器叠加出来的效果会不一样。服务器集群如何转发流量需要负载均衡,比如LVS、Nginx。常用的负载算法有轮询法、随机法、源地址散列法、加权轮询法、加权随机法、最小连接数法等。业务实践:千万级流量的秒杀业务,一个LVS无法搞定流量高峰通常需要10台左右,在上面使用DDNS(动态DNS)进行域名解析负载均衡。配合高性能网卡,单个LVS可以提供??百万以上的并发能力。注意LVS负责网络四层协议转发,不能根据HTTP协议中的请求路径进行负载均衡。所以需要Nginx2和池化技术来复用单个连接,不能承载高并发。如果每次请求都创建一个新的连接并关闭连接,考虑到TCP的三次握手和四次握手,存在时间开销的浪费。池化技术的核心是资源的“预分配”和“循环利用”。常用的池化技术包括线程池、进程池、对象池、内存池、连接池和协程池。连接池的几个重要参数:最小连接数、空闲连接数、最大连接数。在Linux内核中,资源是以进程为单位进行调度的,线程也是轻量级的进程。因此,进程和线程是由内核创建和调度的。协程是由应用程序创建的任务执行单元,例如Go语言中的协程“goroutine”。协程本身运行在线程上,由应用程序自己调度。它是比线程更轻的执行单元。在Go语言中,协程的初始内存空间为2KB(Linux下默认的线程栈大小为8MB),远小于线程和进程。协程的创建和销毁完全在用户态进行,不涉及用户态和内核态的切换。另外,协程完全由用户态的应用程序调用,不涉及内核态的上下文切换。由于在协程之间切换时不需要处理线程状态,所以需要保存的上下文很少,速度非常快。Go语言中协程池的实现方式有两种:抢占式和调度式。抢占式协程池,所有任务都存储在一个共享通道中,多个协程同时消费通道中的任务,存在锁竞争。调度协程池,每个协程都有自己的通道,每个协程只消费自己的通道。在交付任务时,负载均衡算法用于选择合适的协程来执行任务。例如,选择队列中任务最少的协程,或者简单的轮询。3、上面说的流量漏斗,是对系统QPS的一种积极的提升。我们也可以逆向思维,做减法,拦截非法请求,把核心能力留给正常业务!高并发的互联网流量并不都是纯粹的,也有很多恶意流量(如黑客攻击、恶意爬虫、黄牛、秒杀等),我们需要设计流量拦截器来阻断那些非法的、不合格的、低端的priority过滤掉流量,降低系统的并发压力。拦截器分层:网关和WAF(WebApplicationFirewall,Web应用防火墙)采用拦截攻击者源IP、拒绝非法参数请求、源IP限流、用户ID限流等方式。风险控制分析。利用大数据能力,对订单等历史业务数据进行分析,有效识别同IP多个账号下单、下单后支付过快等行为,标记账号供业务团队使用。每个下游tomcat实例应用本地内存缓存,并在本地存储一些库存以供预验证。当然,为了尽可能保持数据的一致性,还有定时任务会定时从Redis中拉取最新的库存数据,更新到本地内存缓存中。高性能直接影响用户的感官体验。在访问一个系统时,如果超过5秒没有反应,大部分用户会选择离开。那么哪些因素会影响系统的性能呢?用户网络环境请求/响应数据包大小业务系统CPU、内存、磁盘等性能业务链路长度下游系统的性能算法实现是否高效当然,随着并发数的增加,系统的压力也会增加,并且平均请求延迟也会随着增加而增加。1、高性能缓存每次都会从DB中读取一些热点数据,会给DB带来很大的压力,导致性能急剧下降。因此,我们需要使用缓存来提高热点数据的访问性能,比如在浏览器的缓存中保存一段时间的活动信息数据。Cache按照性能从高到低分为:寄存器、L1缓存、L2缓存、L3缓存、本地内存、分布式缓存的上位寄存器、L1缓存、L2缓存是位于CPU核心的缓存,访问延迟通常为10亚纳秒。L3缓存是位于CPU核心之外但位于芯片内部的共享缓存,访问延迟通常在10纳秒左右。缓存具有成本高、容量小的特点,容量最大的三级缓存通常只有几十MB。本地内存是计算机中的主内存。与CPU芯片内部缓存相比,内存的成本要低很多。容量通常在GB级别,访问延迟通常在几十到几百纳秒。当断电时,存储器和高速缓冲存储器都是易失性存储器。如果机器断电,这种内存中的数据就会丢失。特别注意:使用缓存时要注意缓存穿透、缓存雪崩、缓存热点、缓存数据一致性。当然,为了提高整体性能,通常会采用多级缓存组合方案(浏览器缓存+服务器端本地内存缓存+服务器端网络内存缓存)。2、日志优化避免IO瓶颈当系统处理大量磁盘IO操作时,由于CPU和内存的速度远高于磁盘,可能会导致CPU花费太多时间等待磁盘返回处理结果。对于CPU对IO的这部分开销,我们称之为“iowait”。在IO中断过程中,如果此时有其他任务线程可以调度,系统会直接调度其他线程,这样CPU就会相应显示为Usr或Sys;但如果此时系统比较空闲,没有其他任务可以调度,CPU就会显示为Usr或Sys。显示为iowait(其实和idle没有本质区别)。磁盘有一个性能指标:IOPS,即每秒读写次数。性能较好的固态硬盘,IOPS在3万左右。对于秒杀系统,如果单节点QPS为10万,每次请求产生3条日志,那么日志写入QPS为30W/s,磁盘根本无法承受。Linux有一个特殊的文件系统:tmpfs(临时文件系统),它是一种由操作系统管理的基于内存的文件系统。当我们写入磁盘时,实际上是写入了内存。当日志文件达到我们设定的阈值时,操作系统会将日志写入磁盘,并删除tmpfs中的日志文件。这种批量和顺序写入大大提高了磁盘的吞吐性能!HighAvailability高可用性指标用来衡量一个系统的可用性有多高。MTBF(MeanTimeBetweenFailure),系统可用性MTTR(MeanTimeToRepair),发生故障后系统恢复正常所需的时间SLA(Service-LevelAgreement),服务级别协议,用于评估服务可用性等级。计算公式为MTBF/(MTBF+MTTR)一般我们说可用性高于99.99%,意味着SLA高于99.99%。技术架构,高可用有哪些策略?多云架构,异地多活,异地备份主备切换,如redis缓存,mysql数据库,主备节点实时同步备份数据。如果主节点不可用,会自动切换到备节点微服务,无状态架构,业务集群部署,心跳检测,可以在最短的时间内检测到不可用的服务。通过熔断和限流,解决流量过载问题,提供过载保护,关注web安全,解决攻击和XSS问题1.主备切换,减少故障时间当系统出现故障时,首要任务不是立即查找原因,考虑到故障的复杂性,这样定位排查需要一定的时间,当问题修复后,SLA会下降好几倍。有没有更快的方法来解决这个问题?那就是故障转移。当发现故障节点时,不会尝试修复它,而是立即将其隔离,同时将流量转移到健康节点。这样,故障转移不仅降低了MTTR,提高了SLA,而且为修复故障节点争取了足够的时间。主备倒换大致分为三个步骤:第一步是自动故障检测(Auto-detect),通过健康检查、心跳等技术手段自动检测故障节点;第二步是自动转移(FailOver),当检测到节点出现故障后,采用移除流量、离开集群等方式隔离故障节点,将流量转移到正常节点;第三步是自动恢复(FailBack)。当故障节点恢复正常后,会自动加入集群,保证集群资源与故障前一致。2、熔断器,提供过载保护所谓过载保护是指当负载超过系统的承载能力时,系统会自动采取保护措施,确保不被压坏。熔断是在系统濒临崩溃时立即中断服务,保证系统的稳定性,避免崩溃。它类似于电器中的“保险丝”。当电流过大时,“保险丝”会先被烧毁,电流就会断开,以免电路过热烧坏电器,引起火灾。例:断路器的触发条件往往与系统节点的承载能力和服务质量有关。例如CPU使用率超过90%,请求错误率超过5%,请求延迟超过500ms。其中任意一个满足条件,熔断发生。3、限流,提供过载保护限流的原理有点类似于熔断,通过判断某种条件来决定是否执行某种策略。但是有区别的,熔断器触发过载保护,节点会暂停服务直到恢复。限流就是只处理自己能力范围内的请求,过多的请求会被限制。限流算法主要有:计数器限流、滑动窗口限流、令牌桶限流、漏桶限流。网上的资料很多,这里就不赘述了。4.降级例如电商业务大促,业务高峰期,系统无法承受所有流量时,系统负载和CPU使用率超过警戒线,部分非-可以对核心功能进行降级,减轻系统压力,比如暂时关闭商品评价、交易记录等功能。弃车保帅,保障订单创建、支付等核心功能的正常使用。当然,不同的业务,不同的公司,处理方式是不一样的。需要结合实际场景与业务方协商,最终达成统一认可的降级方案。总结一下:降级就是通过暂时关闭一些非核心服务或组件来保护核心系统的可用性。
