大流量和高并发应对手段总结

2024-05-25 20:18

本文主要是介绍大流量和高并发应对手段总结,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

大流量和高并发的常规应对手段

扩容、动静分离、缓存、服务降级和限流。

限流的常用算法和实践思路
  1. 目前主流的算法主要有三种:令牌桶算法、漏桶算法和计数器算法。
  2. 令牌桶算法:主要限制流量的流入速率,允许出现一定程度的突发流量。Nginx的限流模块就是使用的这种算法实现的。
    • 每秒会有r个令牌按照固定速率放入桶中。
    • 桶的容量是固定不变的,如果桶满了再放入令牌,则溢出。
    • 若桶中的可用令牌不足,则改请求会被进行限流处理(被抛弃或缓存)。
  3. 漏桶算法:主要限制流量的流出速率,并且流出速率是固定不变的
    • 可以以任意速率向桶中流入水滴。
    • 桶的容量是固定不变的,如果桶满了则溢出。
    • 按照固定的速率从桶中流出水滴。
  4. Google的Guava也实现了基于令牌桶算法那样的平均速率限流,RateLimiter抽象类。
  5. Nginx可以使用限流模块在接入层实现令桶牌算法限流,
    • limit_zone 定义每个IP的session空间大小。
    • limit_zeq_zone定义每个IP每秒允许发起的请求数。
    • limit_conn 定义每个IP能够发起的并发连接数。
    • limit_req 等待处理的请求队列数量。
  6. 生产环境中的商品抢购可以使用计数器算法,具体不同的sku限流规则配置在配置中心内,支持动态更改。可抢购次数的扣减操作,既可以用redis,也可以用JVM。如果是集群并且选择用JVM,则要根据总并发数量除以集群数量,得出单台机器的并发数。(比如总并发数5000,集群机器10台,则每台机器的并发为5000/10=500)。
抢购商品高并发读需求

对于一件抢购商品的流量来说,因为key是同一个,所以流量必然会都引入到同一个redis缓存节点中,这时就容易出现单点故障。因此有下面两种解决方式:
1. 在每个master节点都挂slave从节点,当主节点挂了可以自动顶上。
2. 多级Cache方案,多用LocalCache来过滤掉一部分流量。
- 本地缓存一般只缓存一些热点商品数据,缓存内容一般是商品详情和商品库存。
- 本地缓存跟分布式缓存的同步一般有两种方式:一种是定时主动拉取更新策略。这种会存在一定时间的不一致,要视业务情况而定,例如库存,暂时的不一致导致超卖,单到真正下单的时候还会再进行库存的判断,所以影响较小,可以接受。这种方式要注意关掉缓存的定时失效,防止当用户流量突然过大,都到分布式缓存中拉取数据;第二种方式是每次商品更新,都发布一个消息,订阅此消息的节点监听到后再更新本地缓存的内容。

实时热点自动发现方案

可以将交易系统产生的相关数据,以及在上游系统中埋点上报的相关数据异步写入日志系统中,然后通过实时热点自动发现平台对收集到的日志数据做调用次数统计和热点分析。数据符合热点条件后,就立即通知交易系统做好热点保护。

redis使用watch命令实现高并发抢购需求
  1. 一般高并发这里,不用悲观锁,会迅速增加系统资源;而使用队列,容易造成请求堆积,内存效果过快。所以一般使用乐观锁,可以用redis的watch命令实现。
  2. watch命令会监视给定的key,当exec时,如果监视的key从调用watch后发生过变化,则事务会失败。注意watch的可以是对整个连接有效的,事务也一样。如果连接断开,监视和事务都会被自动清除。当然exec,discard,unwatch命令都会清除连接中的所有监视。
缓存雪崩,缓存穿透,缓存并发,缓存预热,缓存算法
  1. 缓存雪崩:可能是因为数据未加载到缓存中,或者缓存同一时间大面积的失效,从而导致所有请求都去查数据库,导致数据库CPU和内存负载过高,甚至宕机。解决思路:
    • 加锁计数(即限制并发的数量,可以用semphore)或者起一定数量的队列来避免缓存失效时大量请求并发到数据库。但这种方式会降低吞吐量。
    • 分析用户行为,然后失效时间均匀分布。或者在失效时间的基础上再加1~5分钟的随机数。
    • 如果是某台缓存服务器宕机,则考虑做主备。
  2. 缓存穿透:指用户查询数据,在数据库没有,自然在缓存中也不会有。这样就导致用户查询的时候,在缓存中找不到,每次都要去数据库中查询。解决思路:
    • 如果查询数据库也为空,直接设置一个默认值存放到缓存,这样第二次到缓冲中获取就有值了,而不会继续访问数据库。设置一个过期时间或者当有值的时候将缓存中的值替换掉即可。
    • 可以给key设置一些格式规则,然后查询之前先过滤掉不符合规则的Key。
  3. 缓存并发:如果网站并发访问高,一个缓存如果失效,可能出现多个进程同时查询DB,同时设置缓存的情况,如果并发确实很大,这也可能造成DB压力过大,还有缓存频繁更新的问题。解决思路:
    • 对缓存查询加锁,如果KEY不存在,就加锁,然后查DB入缓存,然后解锁;其他进程如果发现有锁就等待,然后等解锁后返回数据或者进入DB查询。
  4. 缓存预热:目的就是在系统上线前,将数据加载到缓存中。解决思路:
    • 数据量不大的话,在系统启动的时候直接加载。
    • 自己写个简单的缓存预热程序。
  5. 缓存算法:
    • FIFO算法:First in First out,先进先出。原则:一个数据最先进入缓存中,则应该最早淘汰掉。也就是说,当缓存满的时候,应当把最先进入缓存的数据给淘汰掉。
    • LFU算法:Least Frequently Used,最不经常使用算法。
    • LRU算法:Least Recently Used,近期最少使用算法。
    • LRU和LFU的区别。LFU算法是根据在一段时间里数据项被使用的次数选择出最少使用的数据项,即根据使用次数的差异来决定。而LRU是根据使用时间的差异来决定的。
协程(纤程)Fiber
  1. 协程概念:一种用户态的轻量级线程,其实就是单线程,指定执行整个函数中到一部分然后就先出去执行别的,等条件满足时,协程下次更新帧到了再继续往下执行。优点是无需线程上下文切换的开销,充分开发了单CPU的能力,资源占用低,适合高并发I/O。缺点也很明显,就是没办法利用多CPU的优势。
  2. 框架:Quasar,调度器使用ForkJoinPool来调度这些fiber。Fiber调度器FiberScheduler是一个高效的、work-stealing、多线程的调度器。
  3. 场景:服务A平时需要调用其他服务,但其他服务在并发高的时候延迟很严重。
    • 一开始可以用httpClient连接池+线程池来处理,但如果调用服务的时候延迟太高或者超时,则会导致服务A的吞吐量会特别差。原因主要是一般一个链接由一个线程来处理,是阻塞的,所以在线程池数有限的情况下,吞吐量肯定上不去。并且当所有线程都I/O阻塞的时候,会很浪费CPU资源,并且CPU会一直做无用的上下文切换。
    • 这时候可以考虑协程来替换。
  4. 参考文章:http://blog.csdn.net/qq910894904/article/details/41699541,
    http://blog.csdn.net/hj7jay/article/details/51980038,
    http://blog.csdn.net/zdy0_2004/article/details/51323583
ForkJoinPool线程池
  1. Fork/Join框架是Java7提供了的一个用于并行执行任务的框架,是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架。
  2. 工作窃取(work-stealing)算法是Fork/Join框架最重要的特性。一般一个线程会对应一个任务队列,当处理较快的线程处理完自己的任务之后,就会窃取另外一个处理比较慢的线程对应的任务,这时候会存在两个线程同时处理一个队列的情况,所以任务队列一般使用双端队列,被窃取任务线程永远从双端队列的头部拿任务执行,而窃取任务的线程永远从双端队列的尾部拿任务执行。优点是充分利用线程进行并行计算,并减少了线程间的竞争。

这篇关于大流量和高并发应对手段总结的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1002516

相关文章

SQL中JOIN操作的条件使用总结与实践

《SQL中JOIN操作的条件使用总结与实践》在SQL查询中,JOIN操作是多表关联的核心工具,本文将从原理,场景和最佳实践三个方面总结JOIN条件的使用规则,希望可以帮助开发者精准控制查询逻辑... 目录一、ON与WHERE的本质区别二、场景化条件使用规则三、最佳实践建议1.优先使用ON条件2.WHERE用

Nginx Location映射规则总结归纳与最佳实践

《NginxLocation映射规则总结归纳与最佳实践》Nginx的location指令是配置请求路由的核心机制,其匹配规则直接影响请求的处理流程,下面给大家介绍NginxLocation映射规则... 目录一、Location匹配规则与优先级1. 匹配模式2. 优先级顺序3. 匹配示例二、Proxy_pa

Android学习总结之Java和kotlin区别超详细分析

《Android学习总结之Java和kotlin区别超详细分析》Java和Kotlin都是用于Android开发的编程语言,它们各自具有独特的特点和优势,:本文主要介绍Android学习总结之Ja... 目录一、空安全机制真题 1:Kotlin 如何解决 Java 的 NullPointerExceptio

python多线程并发测试过程

《python多线程并发测试过程》:本文主要介绍python多线程并发测试过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、并发与并行?二、同步与异步的概念?三、线程与进程的区别?需求1:多线程执行不同任务需求2:多线程执行相同任务总结一、并发与并行?1、

MySQL基本查询示例总结

《MySQL基本查询示例总结》:本文主要介绍MySQL基本查询示例总结,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录Create插入替换Retrieve(读取)select(确定列)where条件(确定行)null查询order by语句li

Linux高并发场景下的网络参数调优实战指南

《Linux高并发场景下的网络参数调优实战指南》在高并发网络服务场景中,Linux内核的默认网络参数往往无法满足需求,导致性能瓶颈、连接超时甚至服务崩溃,本文基于真实案例分析,从参数解读、问题诊断到优... 目录一、问题背景:当并发连接遇上性能瓶颈1.1 案例环境1.2 初始参数分析二、深度诊断:连接状态与

Linux区分SSD和机械硬盘的方法总结

《Linux区分SSD和机械硬盘的方法总结》在Linux系统管理中,了解存储设备的类型和特性是至关重要的,不同的存储介质(如固态硬盘SSD和机械硬盘HDD)在性能、可靠性和适用场景上有着显著差异,本文... 目录一、lsblk 命令简介基本用法二、识别磁盘类型的关键参数:ROTA查询 ROTA 参数ROTA

Java并发编程之如何优雅关闭钩子Shutdown Hook

《Java并发编程之如何优雅关闭钩子ShutdownHook》这篇文章主要为大家详细介绍了Java如何实现优雅关闭钩子ShutdownHook,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起... 目录关闭钩子简介关闭钩子应用场景数据库连接实战演示使用关闭钩子的注意事项开源框架中的关闭钩子机制1.

Qt实现网络数据解析的方法总结

《Qt实现网络数据解析的方法总结》在Qt中解析网络数据通常涉及接收原始字节流,并将其转换为有意义的应用层数据,这篇文章为大家介绍了详细步骤和示例,感兴趣的小伙伴可以了解下... 目录1. 网络数据接收2. 缓冲区管理(处理粘包/拆包)3. 常见数据格式解析3.1 jsON解析3.2 XML解析3.3 自定义

Python实现图片分割的多种方法总结

《Python实现图片分割的多种方法总结》图片分割是图像处理中的一个重要任务,它的目标是将图像划分为多个区域或者对象,本文为大家整理了一些常用的分割方法,大家可以根据需求自行选择... 目录1. 基于传统图像处理的分割方法(1) 使用固定阈值分割图片(2) 自适应阈值分割(3) 使用图像边缘检测分割(4)