这些并发编程技术你都知道吗?

与其碌碌无为,不如兴风作浪。


虽然不是所有的系统都需要很多的并发编程技术,但是掌握常见的高并发秘籍,便能让我们的系统快起来,面对访问量的剧增从容应对。
接下来,为我们一起来看看常见的高并发技术有哪些。总结起来,主要包括缓存、限流、熔断降级、异步、池化、代码优化、JVM调优、预热、等。

缓存

主要包括本地缓存和分布式缓存。可以使用Redis和Caffeine等方式缓存数据,一般情况下分布式系统使用分布式缓存就可以了。对于高并发的系统,可以考虑多级缓存,但是要考虑内存以及数据一致性问题。
本地缓存:解决redis的热key问题和提升性能;
分布式缓存:解决缓存容量和提升性能。

本地缓存

虽然redis号称单节点能抗住10Wqps,但是开发过程中为了保险,会降低预期。那么如何发现这些热点key呢?可以在开发的时候凭业务经验估计,比如秒杀的商品信息。上线后,也可以随时在客户端进行收集。
Caffeine是基于java8实现的新一代缓存工具,缓存性能接近理论最优。可以看作是Guava Cache的增强版,功能上两者类似,不同的是Caffeine采用了一种结合LRU、LFU优点的算法:W-TinyLFU,在性能上有明显的优越性。

使用方式如下:

public class CaffeineCacheTest {public static void main(String[] args) throws Exception {//创建guava cacheCache<String, String> loadingCache = Caffeine.newBuilder()//cache的初始容量.initialCapacity(5)//cache最大缓存数.maximumSize(10)//设置写缓存后n秒钟过期.expireAfterWrite(17, TimeUnit.SECONDS)//设置读写缓存后n秒钟过期,实际很少用到,类似于expireAfterWrite//.expireAfterAccess(17, TimeUnit.SECONDS).build();String key = "key";// 往缓存写数据loadingCache.put(key, "value");// 获取value的值,如果key不存在,获取value后再返回String value = loadingCache.get(key, CaffeineCacheTest::getValueFromDB);// 删除keyloadingCache.invalidate(key);}private static String getValueFromDB(String key) {return "value";}
}

分布式缓存

也就是引入redis中间件进行数据缓存。
image.png

使用Spring Cache进行商品类目数据缓存:

/*** 商品类目*/
@DubboService
@CacheConfig(cacheNames = CACHE_NAME_CATEGORY)
@Slf4j
public class CategoryFacadeServiceImpl implements ICategoryFacadeService {// 使用@Cacheable注解,它会将方法返回结果存储在注解指定的缓存中@Override@Cacheablepublic List<CategoryResp> listAllCategory() throws ServiceException {log.info("查询所有类目开始");return allCategory;}// @CacheEvict 注解来表示删除一个、多个或所有的值,以刷新缓存@Override@Transactional(rollbackFor = Exception.class)@CacheEvict(cacheNames = CACHE_NAME_CATEGORY, allEntries = true)public Long saveAndUpdate(@NotNull CategoryReq req) throws ServiceException {log.info("新增或修改类目开始CategoryReq{}", req);return result;}@Override@Transactional(rollbackFor = Exception.class)@CacheEvict(cacheNames = CACHE_NAME_CATEGORY, allEntries = true)public boolean deleteCategory(@NotNull Long id) throws ServiceException {log.info("开始删除类目");return flag&&mappingFlag;}
}

多级缓存

通过新增本地缓存,可用使得流量在应用层直接返回,避免进一步访问Redis。大大提高数据读取的效率,但是成本也是很高的。

  • 内存要求:需要在应用服务器同于数据,需要提高应用服务器的内存;
  • 数据一致性:需要保证多级缓存之间,各个本地缓存之间数据的一致性。

需要重具体的业务场景触发,兼顾以下三个方面考虑是否需要本地缓存:

  • 并发量
  • 内存情况
  • 变更是否频繁

image.png

限流

限流是为了保护系统的可用性而做出的一种妥协,通过减低请求成功的数量,保证重要功能的可用。需要通过压测预估系统可承载的并发量。在系统资源紧张的情况下,保证系统的可用性。
可通过sentinel实现限流,经典算法包括令牌桶,漏桶,滑动时间窗口等。

熔断降级

熔断降级是分布式系统中常用的两种保护机制,旨在提高系统的稳定性和可用性。以下是关于熔断降级的详细解释:

熔断

定义:熔断类似于电路中的保险丝,当某个异常条件被触发时,直接熔断整个服务,防止系统因某个服务的故障而导致整体服务失败。
触发条件:熔断的触发条件通常与服务调用的失败率、请求超时等有关。例如,在Spring Cloud的Hystrix组件中,如果检测到10秒内请求的失败率超过50%,则触发熔断机制。
作用:熔断机制通过快速失败和快速恢复,防止在复杂分布式系统中出现级联故障,从而提高系统的整体弹性。

降级

定义:降级是指在系统压力剧增或出现故障时,根据当前业务情况及流量,对一些服务和页面进行有策略的降级,以此缓解服务器资源的压力,保证核心业务的正常运行。
触发条件:降级的触发条件通常包括服务超时、失败次数、故障、限流等。在Hystrix中,降级可以在方法抛出异常、方法调用超时、熔断器开启拦截调用、线程池或队列或信号量已满等情况下触发。
目的:降级的目的是在系统出现问题时,仍能保证有限功能可用,提供一种退而求其次的解决方案。例如,在电商交易系统中,当系统负载过高时,可以开启降级功能,优先保证支付功能可用,而其他非核心功能如评论、物流、商品介绍等可以暂时关闭。

熔断与降级的区别

概念不同:熔断是当服务出现故障时,直接熔断整个服务,防止系统因某个服务的故障而导致整体服务失败;而降级是在系统压力剧增或出现故障时,通过关闭部分非核心功能来保证核心业务的正常运行。
触发条件不同:熔断的触发条件通常与服务调用的失败率、请求超时等有关;而降级的触发条件则包括服务超时、失败次数、故障、限流等。
归属关系不同:熔断时可能会调用降级机制,因为熔断是从全局出发,为了保证系统稳定性而停用服务;而降级是退而求其次,提供一种保底的解决方案。
常见的降级类型包括:大促非核心的接口降级;日志降级等。

异步

主要涉及到如何让程序在执行某些可能耗时的操作时,不会阻塞主线程,从而提高程序的响应性和性能。主要策略包括多线程和消息队列等。
系统解耦:对于不需要客户感知结果的部分,可通过消息的方式完成后续处理,完成后通知客户结果。不需要阻塞客户一直等待。
提升性能:对于一些查询操作,可能设置多个独立的数据内容,这种情况可以使用CompletableFuture进行一步任务编排,提升查询效率。
下面是通过任务编排实现商品属性查询的案例:

CompletableFuture<String> futureImg = CompletableFuture.supplyAsync(() -> {System.out.println("查询商品的图片信息");return "hello.jpg";
});CompletableFuture<String> futureAttr = CompletableFuture.supplyAsync(() -> {System.out.println("查询商品的属性");return "黑色";
});CompletableFuture<String> futureDesc = CompletableFuture.supplyAsync(() -> {try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }System.out.println("查询商品介绍");return "华为";
});// 等待全部执行完
//        CompletableFuture<Void> allOf = CompletableFuture.allOf(futureImg, futureAttr, futureDesc);
//        allOf.get();// 只需要有一个执行完
CompletableFuture<Object> anyOf = CompletableFuture.anyOf(futureImg, futureAttr, futureDesc);
anyOf.get();
System.out.println("main....end....." + anyOf.get());

池化技术

池化技术主要用于避免频繁创建和销毁昂贵资源(如数据库连接、线程、大对象等)所带来的性能开销。通过预先创建一定数量的资源并维护在一个池中,当需要时从池中获取资源使用,使用完毕后归还到池中而不是直接销毁,可以显著提高应用程序的效率和响应速度。
下面是一些典型的Java池化技术实例:

  • 数据库连接池
    • 实现库:Apache DBCP, C3P0, HikariCP, Tomcat JDBC Pool等。
    • 作用:管理数据库连接,避免了每次数据库操作都新建和销毁连接的开销。
  • 线程池
    • 实现库:java.util.concurrent.ExecutorService接口及其实现类,如ThreadPoolExecutor。
    • 作用:预先创建一定数量的线程,将任务提交给线程池处理,提高了并发处理能力,同时也限制了系统创建过多线程导致的资源耗尽风险。
  • 对象池
    • 实现库:Apache Commons Pool。
    • 作用:适用于任何需要重用的对象,如大对象、网络连接、图形对象等,减少垃圾回收压力和创建对象的成本。
  • 缓冲池(Buffer Pool)
    • 在某些IO密集型应用中,如NIO(非阻塞I/O)编程,通过重用缓冲区可以提升读写效率。

使用池化技术的关键在于合理配置池的大小,过大可能导致资源浪费,过小则可能因为资源争抢而影响性能。此外,池化技术还需要考虑资源的分配与回收策略、超时处理、异常处理等机制,确保资源的有效管理和利用。

代码优化

通过优化代码逻辑,减少调用链路,减少数据库查询次数,提前校验流程。

JVM调优

主要是系统根据业务情况和机器配置设置合理的JVM参数。

预热

通过执行定时任务等方式提前将数据加载到缓存。通过预热,能够避免缓存刚开始没有数据时全量请求查数据库的行为。
如果秒杀要走正常的加入购物车流程,然后去来锁库存,最终去支付,这样整个流程太慢了,在高并发系统里边肯定会出现整个级联崩溃的情况。我们应该先做到预热库存,比如现在要秒杀的商品,数量有400件,我们给 redis 里面存一个 400 的信号量,想要秒杀的人进来之后,必须要先拿到信号量,这一块我们会对 redis 的信号量进行快速扣减,直接扣减1个数,所以无论有多少请求进来,即使有百万请求,最终也只有 400个人能拿到这个信号量的值。然后我们会将这 400 个人放行给我们后台的集群系统,这些请求即使走正常的下单逻辑,系统也不会出现什么问题。

如果是单台机器,也可以使用一些简单的办法实现,但是不太灵活。比如:

监听启动事件

  • 使用ApplicationListener监听ContextRefreshEvent或ApplicationReadyEvent等应用上下文初始化完成事件,在这些事件触发后执行数据加载的操作。
@Component
public class CacheWarmer implements ApplicationListener<ContextRefreshedEvent> {@Overridepublic void onApplicationEvent(ContextRefreshedEvent event) {// 执行缓存预热业务...cacheManager.put("key", dataList);}
}
@Component
public class CacheWarmer implements ApplicationListener<ApplicationReadyEvent> {@Overridepublic void onApplicationEvent(ApplicationReadyEvent event) {// 执行缓存预热业务...cacheManager.put("key", dataList);}
}

PostConstuct注解

该注解是Java jdk提供的注解,而不是Spring框架提供的。该注解的功能是当依赖注入完成后用于执行初始化的方法,并且只会被执行一次

@Component
public class CachePreloader {@Autowiredprivate YourCacheManager cacheManager;// 注解@PostConstructpublic void preloadCache() {// 执行缓存预热业务...cacheManager.put("key", dataList);}
}

实现InitializingBean接口

InitializingBean是Spring提供的拓展性接口,为bean提供了属性初始化后的处理方法,它唯一的方法便是afterPropertiesSet,凡是实现该接口的类,在bean属性初始化后都会执行该方法。

@Component
public class CachePreloader implements InitializingBean {@Autowiredprivate YourCacheManager cacheManager;@Overridepublic void afterPropertiesSet() throws Exception {// 执行缓存预热业务...cacheManager.put("key", dataList);}
}

hi,你好,我是松语。985软件工程研究生毕业,一个工作三年的程序员。

这里有:

  1. 技术分享,包括编程技巧和踩坑记录等;
  2. 求职经验,校招、副业、社招跳槽经验等;
  3. 诗和远方。

亲爱的你,切莫辜负有梦想的自己,萍水相逢的感情,以及良辰美景好时光。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/38271.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SSH版本升级-openssh-9.7p1

SSH版本升级-openssh-9.7p1 1、查看当前版本2、安装openssl2.1、编译安装ssl 3、下载新版本SSH4、备份原有的SSH配置5、上传文件并解压6、卸载原有的openssh包7、编译安装openssh7.1、在解压后的目录&#xff0c;初始化openssh7.2、将文件拷回7.3、修改配置文件 最终实现&#…

DDD学习笔记五

模型引力场&#xff1a;聚合 强作用力体现&#xff1a; 某个领域模型是另一些模型存在的前提&#xff0c;没有前者&#xff0c;后者就失去了生存的意义。 一组领域模型之间存在关联的领域逻辑&#xff0c;任何时候都不能违反。 一组领域模型必须以一个完整的、一致的状态呈现给…

CSDN写文章时需要上、下标字号怎么输?

上标&#xff1a;​^^&#xff0c;符号中间加字 下标&#xff1a;~~&#xff0c;符号中间加字 前题是用MD编辑器&#xff0c;不然白搭&#xff1a; 我是感觉CSDN这个文本编辑比较拉&#xff0c;非常想吐槽。

dB分贝入门

主要参考资料&#xff1a; dB&#xff08;分贝&#xff09;定义及其应用: https://blog.csdn.net/u014162133/article/details/110388145 目录 dB的应用一、声音的大小二、信号强度三、增益 dB的应用 一、声音的大小 在日常生活中&#xff0c;住宅小区告知牌上面标示噪音要低…

vue2 element ui 表单 动态增加表单项 表单项值不可重复 select多选

案例 <template><el-form :model"form" ref"form" label-width"70px"><el-form-item><el-button icon"el-icon-plus" type"primary" plain click"add">新增</el-button><el-b…

VUE3-Elementplus-form表单-笔记

1. 结构相关 el-row表示一行&#xff0c;一行分成24份 el-col表示列 (1) :span"12" 代表在一行中&#xff0c;占12份 (50%) (2) :span"6" 表示在一行中&#xff0c;占6份 (25%) (3) :offset"3" 代表在一行中&#xff0c;左侧margin份数 el…

后劳动经济学(PLE):AI时代的工作未来

引言 随着人工智能&#xff08;AI&#xff09;和自动化技术的飞速发展&#xff0c;我们迎来了一个新的经济范式——后劳动经济学&#xff08;PLE&#xff09;。这一概念主要讨论在AI和自动化技术超越人类能力的关键领域后&#xff0c;机器将不可避免地在许多经济活动中取代人类…

如何玩单机版:QQ音速

前言 我是研究单机的老罗&#xff0c;今天教大家带来一款怀旧游戏QQ音速 的教程。根据我的文章&#xff0c;一步一步就可以玩了。 如今市面上的资源参差不齐&#xff0c;大部分的都不能运行&#xff0c;本人亲自测试&#xff0c;运行视频如下&#xff1a; QQ音速 搭建教程 此…

vscode下无法识别node、npm的问题

node : 无法将“node”项识别为 cmdlet、函数、脚本文件或可运行程序的名称 因为node是在cmd安装的&#xff0c;是全局安装的&#xff0c;并不是在这个项目里安装的。 解决方案&#xff1a; 1.在vscode的控制台&#xff0c;针对一个项目安装特定版本的node&#xff1b; 2.已经…

C++(Python)肥皂泡沫普拉托边界膜曲面模型算法

&#x1f3af;要点 &#x1f3af;肥皂泡二维流体模拟 | &#x1f3af;泡沫普拉托边界膜曲面模型算法演化厚度变化 | &#x1f3af;螺旋曲面三周期最小结构生成 &#x1f4dc;皂膜用例&#xff1a;Python计算物理粒子及拉格朗日和哈密顿动力学 | Python和MATLAB粘性力接触力动…

鸿蒙开发设备管理:【@ohos.multimodalInput.inputEventClient (注入按键)】

注入按键 InputEventClient模块提供了注入按键能力。 说明&#xff1a; 本模块首批接口从API version 8开始支持。后续版本的新增接口&#xff0c;采用上角标单独标记接口的起始版本。本模块接口均为系统接口&#xff0c;三方应用不支持调用。 导入模块 import inputEventCli…

爱情再启:庄国栋笑谈“玫瑰人生”爱情觉悟

庄国栋&#xff0c;这位电视剧《玫瑰的故事》中的男主角&#xff0c; 最近在一次采访中坦言&#xff1a;“如果给我一次重来的机会&#xff0c; 我绝对会毫不犹豫地选择爱情&#xff01;” 听到这话&#xff0c; 我不禁想&#xff0c;庄先生&#xff0c;您是不是被剧里的玫瑰…

Solidworke学习(装配体3)

目录 本节学习内容&#xff1a; 一、高级配合 &#xff08;1&#xff09;对称配合 &#xff08;2&#xff09;宽度配合 &#xff08;3&#xff09;距离配合 二、机械配合 &#xff08;1&#xff09;凸轮配合 &#xff08;2&#xff09;槽口配合 三、快捷菜单 本节学习…

python工作目录与文件目录

工作目录 文件目录&#xff1a;文件所在的目录 工作目录&#xff1a;执行python命令所在的目录 D:. | main.py | ---data | data.txt | ---model | | model.py | | train.py | | __init__.py | | | ---nlp | | | bert.py | …

计算机网络期末复习(大题+小题)

计算机网络期末复习 一、计算机网络概述 Point 1 计算机网络就是以传输信息为基本目的&#xff0c;用通信线路和通信设备将多个计算机连接起来的计算机系统的集合。由自治的计算机互联起来的结合体。 Point 2 按网络的覆盖范围进行分类 &#xff08;1&#xff09;局域网*…

人机交互新维度|硕博电子发布双编码器操作面板、无线操作面板等新品

6月15日&#xff0c;硕博电子召开了一场新品发布会&#xff0c;向业界展示了多项前沿技术成果&#xff0c;其中备受瞩目的当属SPM-KEYP-D08双编码器操作面板、SPM-KEYP-D16W无线操作面板、SPR-HT-XK12A无线手持发射端以及SPQ-WT-B01洒水车专用控制面板。这些创新产品的亮相&…

文心一言 VS 讯飞星火 VS chatgpt (292)-- 算法导论21.3 5题

五、证明&#xff1a;任何具有 m 个 MAKE-SET、UNION 和 FIND-SET 操作的序列&#xff0c;这里所有的 LINK 操作都出现在 FIND-SET 操作之前&#xff0c;如果同时使用路径压缩和按秩合并启发式策略&#xff0c;则这些操作只需 O(m) 的时间。在同样情况下&#xff0c;如果只使用…

Class Constructors and Destructors (类的构造函数和析构函数)

Class Constructors and Destructors [类的构造函数和析构函数] 1. Declaring and Defining Constructors (声明和定义构造函数)2. Using Constructors (使用构造函数)3. Default Constructors (默认构造函数)4. Destructors (析构函数)5. Improving the Stock Class (改进 Sto…

前端小案例,用锚点(哈希值)实现Tab组件切换

在前端开发的世界里&#xff0c;使用现代化的技术和方法来实现常见的组件是非常重要的。今天&#xff0c;我们将通过一个具体的案例来展示如何使用现代化的CSS和ES6来创建一个优雅且功能丰富的Tab组件。本文将详细介绍实现思路、代码分析&#xff0c;并提供一些实用的开发技巧。…

25 防火墙基础操作

1 防火墙进入WEB页面操作 华三防火墙的默认用户:admin/密码:admin 将IP地址改在同一网段的信息 在防火墙的管理地址 GE/0/0/1&#xff1a;192.168.0.1 主机的地址是:192.168.0.101 思考一下为什么Ping不通 security-zone name Management import interface GigabitEthernet1/…