电商(强一致性系统)的场景设计

news2024/11/14 6:16:46

领域拆分:如何合理地拆分系统?
一般来说,强一致性的系统都会牵扯到“锁争抢”等技术点,有较大的性能瓶颈,而电商时常做秒杀活动,这对系统的要求更高。业内在对电商系统做改造时,通常会从三个方面入手:系统拆分、库存争抢优化、系统隔离优化。

业务拆分的方法有很多,最简单便捷的方式是:先从上到下做业务流程梳理,将流程归类聚合;然后从不同的领域聚合中找出交互所需主要实体,根据流程中主要实体之间的数据依赖程度决定是否拆分(从下到上看);把不同的实体和动作拆分成多个模块后,再根据业务流程归类,划分出最终的模块(最终汇总)。这个拆分过程用一句话总结就是:从上往下看流程,从下往上看模块,最后综合考虑流程和模块的产出结果。用这种方式能快速拆出模块范围,拆分出的业务也会十分清晰。
在这里插入图片描述
强一致锁:如何解决高并发下的库存争抢问题

由于秒杀场景是库存争抢非常经典的一个应用场景,接下来我会结合秒杀需求,带你看看如何实现高并发下的库存争抢,相信在这一过程中你会对锁有更深入的认识。
锁争抢的错误做法

public class ThreadCounter {
    private static int count = 0;
 
    public static void main(String[] args) throws Exception {
        Runnable task = new Runnable() {
            public void run() {
                for (int i = 0; i < 1000; ++i) {
                    count += 1;
                }
            }
        };
 
        Thread t1 = new Thread(task);
        t1.start();
        
        Thread t2 = new Thread(task);
        t2.start();
 
        t1.join();
        t2.join();
 
        cout << "count = " << count << endl;
    }
}

这段代码,count预期是2000,但是一般都会小于2000。对于这个情况,我们一般都会用到锁或原子操作来保护库存变量:
如果是简单 int 类型数据,可以使用原子操作保证数据准确;
如果是复杂的数据结构或多步操作,可以加锁来保证数据完整性。

不过锁操作是很影响性能的,在讲锁方式之前,我先给你介绍几个相对轻量的方式。

前面我们提到当有大量用户去并行修改一个变量时,只有用锁才能保证修改的正确性,但锁争抢性能很差,那怎么降低锁的粒度、减少锁的争枪呢?
在这里插入图片描述
举个例子,当前商品库存有 100 个,我们可以把它放在 10 个 key 中用不同的 Redis 实例保存,每个 key 里面保存 10 个商品库存,当用户下单的时候可以随机找一个 key 进行扣库存操作。如果没库存,就记录好当前 key 再随机找剩下的 9 个 key,直到成功扣除 1 个库存。
除了这种方法以外,我个人更推荐的做法是使用 Redis 的原子操作,因为原子操作的粒度更小,并且是高性能单线程实现,可以做到全局唯一决策。而且很多原子操作的底层实现都是通过硬件实现的,性能很好

redis> decr prod_1475_stock_1
incr、decr 这类操作就是原子的,我们可以根据返回值是否大于 0 来判断是否扣库存成功。但是这里你要注意,如果当前值已经为负数,我们需要考虑一下是否将之前扣除的补偿回来。并且为了减少修改操作,我们可以在扣减之前做一次值检测,整体操作如下:

//读取当前库存,确认是否大于零
//如大于零则继续操作,小于等于拒绝后续
redis> get prod_1475_stock_1
1
 
//开始扣减库存、如返回值大于或等于0那么代表扣减成功,小于0代表当前已经没有库存
//可以看到返回-2,这可以理解成同时两个线程都在操作扣库存,并且都没拿到库存
redis> decr prod_1475_stock_1
-2
 
//扣减失败、补偿多扣的库存
//这里返回0是因为同时两个线程都在做补偿,最终恢复0库存
redis> incr prod_1475_stock
0

这看起来是个不错的保护库存量方案,不过它也有缺点,相信你已经猜到了,这个库存的数值准确性取决于我们的业务是否能够返还恢复之前扣除的值。如果在服务运行过程中,“返还”这个操作被打断,人工修复会很难,因为你不知道当前有多少库存还在路上狂奔,只能等活动结束后所有过程都落地,再来看剩余库存量。
而要想完全保证库存不会丢失,我们习惯性通过事务和回滚来保障。但是外置的库存服务 Redis 不属于数据库的缓存范围,这一切需要通过人工代码去保障,这就要求我们在处理业务的每一处故障时都能处理好库存问题。所以,很多常见秒杀系统的库存在出现故障时是不返还的,并不是不想返还,而是很多意外场景做不到。

令牌库存
具体是使用 Redis 中的 list 保存多张令牌来代表库存,一张令牌就是一个库存,用户抢库存时拿到令牌的用户可以继续支付:

//放入三个库存
redis> lpush prod_1475_stock_queue_1 stock_1
redis> lpush prod_1475_stock_queue_1 stock_2
redis> lpush prod_1475_stock_queue_1 stock_3

//取出一个,超过0.5秒没有返回,那么抢库存失败
redis> brpop prod_1475_stock_queue_1 0.5
在没有库存后,用户只会拿到 nil。当然这个实现方式只是解决抢库存失败后不用再补偿库存的问题,在我们对业务代码异常处理不完善时仍会出现丢库存情况。同时,我们要注意 brpop 可以从 list 队列“右侧”中拿出一个令牌,如果不需要阻塞等待的话,使用 rpop 压测性能会更好一些。
不过,当我们的库存成千上万的时候,可能不太适合使用令牌方式去做,因为我们需要往 list 中推送 1 万个令牌才能正常工作来表示库存。如果有 10 万个库存就需要连续插入 10 万个字符串到 list 当中,入库期间会让 Redis 出现大量卡顿。

多库存秒杀
如果产品侧提出“一个商品可以抢多个库存”这样的要求,也就是一次秒杀多个同种商品(比如一次秒杀两袋大米

这时候你应该发现了,在“一个商品可以抢多个库存”这个场景下,拆分并没有减少锁争抢次数,同时还加大了维护难度。当库存越来越少的时候,抢购越往后性能表现越差,这个设计已经不符合我们设计的初衷
在这里插入图片描述
系统隔离:如何应对高并发流量冲击?
我曾经在一家教育培训公司做架构师,在一次续报活动中,我们的系统出现了大规模崩溃。在活动开始有五万左右的学员同时操作,大量请求瞬间冲击我们的服务器,导致服务端有大量请求堆积,最终系统资源耗尽停止响应。我们不得不重启服务,并对接口做了限流,服务才恢复正常。究其原因,我们习惯性地将公用的功能和数据做成了内网服务,这种方式虽然可以提高服务的复用性,但也让我们的服务非常依赖内网服务。当外网受到流量冲击时,内网也会受到放大流量的冲击,过高的流量很容易导致内网服务崩溃,进而最终导致整个网站无法响应。事故后我们经过详细复盘,最终一致认为这次系统大规模崩溃,核心还是在于系统隔离性做得不好,业务极易相互影响。
在这里插入图片描述
如果系统隔离性做得好,在受到大流量冲击时,只会影响被冲击的应用服务,即使某个业务因此崩溃,也不会影响到其他业务的正常运转**。这就要求我们的架构要有能力隔离多个应用,并且能够隔离内外网流量,只有如此才能够保证系统的稳定。**
为了提高系统的稳定性,我们决定对系统做隔离改造,具体如下图:
在这里插入图片描述
也就是说,每个内、外网服务都会部署在独立的集群内,同时每个项目都拥有自己的网关和数据库。而外网服务和内网必须通过网关才能访问,外网向内网同步数据是用 Kafka 来实现的。
网关隔离和随时熔断
网关隔离和随时熔断在这个改造方案中有两种网关:外网网关和内网网关。每个业务都拥有独立的外网网关(可根据需要调整)来对外网流量做限流。当瞬时流量超过系统承受能力时,网关会让超编的请求排队阻塞一会儿,等服务器 QPS 高峰过后才会放行,这个方式比起直接拒绝客户端请求来说,可以给用户更好的体验。外网调用内网的接口必须通过内网网关。外网请求内网接口时,内网网关会对请求的来源系统和目标接口进行鉴权,注册授权过的外网服务只能访问对其授权过的内网接口,这样可以严格管理系统之间的接口调用.
同时,我们在开发期间要时刻注意,内网网关在流量增大的时候要做熔断,这样可以避免外网服务强依赖内网接口,保证外网服务的独立性,确保内网不受外网流量冲击。并且外网服务要保证内网网关断开后,仍旧能正常独立运转一小时以上。但是你应该也发现了,这样的隔离不能实时调用内网接口,会给研发造成很大的困扰。要知道常见外网业务需要频繁调用内网服务获取基础数据才能正常工作,而且内网、外网同时对同一份数据做决策的话,很容易出现混乱。

减少内网 API 互动
为了防止共享的数据被多个系统同时修改,我们会在活动期间把参与活动的数据和库存做推送,然后自动锁定,这样做可以防止其他业务和后台对数据做修改。若要禁售,则可以通过后台直接调用前台业务接口来操作;活动期间也可以添加新的商品到外网业务中,但只能增不能减。
在这里插入图片描述
这样的实现方式既可以保证一段时间内数据决策的唯一性,也可以保证内外网的隔离性.
只有保证数据同步是单向的,才能取消相互锁定操作。我们可以规定所有库存决策由外网业务服务决定,后台对库存操作时必须经过外网业务决策后才能继续操作,这样的方式比锁定数据更加灵活。而外网交易后要向内网同步交易结果,只能通过队列方式推
在这里插入图片描述

后台系统推送数据到 Redis 或数据库中,外网服务通过 Kafka 把结果同步到内网,扣减库存需通知外网服务扣减成功后方可同步操作。

外网与内网的区别:
外网是一般是针对用户端,直接对接用户使用,需要做公网解析;
内网一般是公司技术服务节点,不需要公网解析且不对外服务,都是外网服务上做单独解析才能访问内网服务,访问内网会比公网获取数据速度更快,减少了一层解析。

一般大点的公司都会做外网和内网隔离,以保障服务安全和稳定。

分布式事务:多服务的2PC、TCC都是怎么实现的?
目前业界流行微服务,DDD 领域驱动设计也随之流行起来。DDD 是一种拆分微服务的方法,它从业务流程的视角从上往下拆分领域,通过聚合根关联多个领域,将多个流程聚合在一起,形成独立的服务。相比由数据表结构设计出的微服务,DDD 这种方式更加合理,但也加大了分布式事务的实现难度。
在传统的分布式事务实现方式中,我们普遍会将一个完整的事务放在一个独立的项目中统一维护,并在一个数据库中统一处理所有的操作。这样在出现问题时,直接一起回滚,即可保证数据的互斥和统一性。**不过,这种方式的服务复用性和隔离性较差,很多核心业务为了事务的一致性只能聚合在一起。**为了保证一致性,事务在执行期间会互斥锁定大量的数据,导致服务整体性能存在瓶颈。
好在目前业内有很多实现分布式事务的方式,比如 2PC、3PC、TCC 等,但究竟用哪种比较合适呢?这是我们需要重点关注的。
XA 协议
XA 协议是一个很流行的分布式事务协议,可以很好地支撑我们实现分布式事务,比如常见的 2PC、3PC 等。而理解了 XA 协议,对我们深入了解分布式事务的本质很有帮助。
支持 XA 协议的数据库可以在客户端断开的情况下,将执行好的业务结果暂存起来,直到另外一个进程确认才会最终提交或回滚事务,这样就能轻松实现多个数据库的事务一致性。

在 XA 协议里有三个主要的角色:
应用(AP):应用是具体的业务逻辑代码实现,业务逻辑通过请求事务协调器开启全局事务,在事务协调器注册多个子事务后,业务代码会依次给所有参与事务的子业务下发请求。待所有子业务提交成功后,业务代码根据返回情况告诉事务协调器各个子事务的执行情况,由事务协调器决策子事务是提交还是回滚(有些实现是事务协调器发请求给子服务)。
事务协调器(TM):用于创建主事务,同时协调各个子事务。事务协调器会根据各个子事务的执行情况,决策这些子事务最终是提交执行结果,还是回滚执行结果。此外,事务协调器很多时候还会自动帮我们提交事务;
资源管理器(RM):是一种支持事务或 XA 协议的数据资源,比如 MySQL、Redis 等。
另外,XA 还对分布式事务规定了两个阶段:Prepare 阶段和 Commit 阶段。
在 Prepare 阶段,事务协调器会通过 xid(事务唯一标识,由业务或事务协调器生成)协调多个资源管理器执行子事务,所有子事务执行成功后会向事务协调器汇报。这时的子事务执行成功是指事务内 SQL 执行成功,并没有执行事务的最终 commit(提交),所有子事务是提交还是回滚,需要等事务协调器做最终决策。接着分布式事务进入 Commit 阶段:当事务协调器收到所有资源管理器成功执行子事务的消息后,会记录事务执行成功,并对子事务做真正提交。如果 Prepare 阶段有子事务失败,或者事务协调器在一段时间内没有收到所有子事务执行成功的消息,就会通知所有资源管理器对子事务执行回滚的操作。

我们以购物场景为例,在购物的整个事务流程中,需要协调的服务有三个:用户钱包、商品库存和用户购物订单,它们的数据都放在私有的数据库中。
在这里插入图片描述

按照业务流程,用户在购买商品时,系统需要执行扣库存、生成购物订单和扣除用户账户余额的操作 。其中,“扣库存”和“扣除用户账户余额”是为了保证数据的准确和一致性,所以扣减过程中,要在事务操作期间锁定互斥的其他线程操作保证一致性,然后通过 2PC 方式,对三个服务实现事务协调。
2PC 事务不仅容易理解,实现起来也简单。不过它最大的缺点是在 Prepare 阶段,很多操作的数据需要先做行锁定,才能保证数据的一致性。并且应用和每个子事务的过程需要阻塞,等整个事务全部完成才能释放资源,这就导致资源锁定时间比较长,并发也不高,常有大量事务排队。除此之外,在一些特殊情况下,2PC 会丢数据,比如在 Commit 阶段,如果事务协调器的提交操作被打断了,XA 事务就会遗留在 MySQL 中。而且你应该已经发现了,2PC 的整体设计是没有超时机制的,如果长时间不提交遗留在 MySQL 中的 XA 子事务,就会导致数据库长期被锁表

3PC 简述。与 2PC 相比,3PC 主要多了事务超时、多次重复尝试,以及提交 check 的功能。但因为确认步骤过多,很多业务的互斥排队时间会很长,所以 3PC 的事务失败率要比 2PC 高很多。为了减少 3PC 因资源锁定等待超时导致的重复工作,3PC 做了预操作,整体流程分成三个阶段:CanCommit 阶段:为了减少因等待锁定数据导致的超时情况,提高事务成功率,事务协调器会发送消息确认资源管理器的资源锁定情况,以及所有子事务的数据库锁定数据的情况。PreCommit 阶段:执行 2PC 的 Prepare 阶段;DoCommit 阶段:执行 2PC 的 Commit 阶段。总体来说,3PC 步骤过多,过程比较复杂,整体执行也更加缓慢,所以在分布式生产环境中很少用到它,这里我就不再过多展开了。

TCC 是 Try-Confirm-Cancel 的缩写,从流程上来看,它比 2PC 多了一个阶段,也就是将 Prepare 阶段又拆分成了两个阶段:Try 阶段和 Confirm 阶段。TCC 可以不使用 XA,只使用普通事务就能实现分布式事务。
首先在 Try 阶段,**业务代码会预留业务所需的全部资源,**比如冻结用户账户 100 元、提前扣除一个商品库存、提前创建一个没有开始交易的订单等,这样可以减少各个子事务锁定的数据量。业务拿到这些资源后,后续两个阶段操作就可以无锁进行了。
在 Confirm 阶段,业务确认所需的资源都拿到后,子事务会并行执行这些业务。执行时可以不做任何锁互斥,也无需检查,直接执行 Try 阶段准备的所有资源就行。请注意,协议要求所有操作都是幂等的,以支持失败重试,因为在一些特殊情况下,比如资源锁争抢超时、网络不稳定等,操作要尝试执行多次才会成功。
最后在 Cancel 阶段:如果子事务在 Try 阶段或 Confirm 阶段多次执行重试后仍旧失败,TM 就会执行 Cancel 阶段的代码,并释放 Try 预留的资源,同时回滚 Confirm 期间的内容。注意,Cancel 阶段的代码也要做幂等,以支持多次执行
在这里插入图片描述
最后,我们总结一下 TCC 事务的优点:并发能力高,且无长期资源锁定;当然,它的缺点也很明显:只适合短事务,不适合多阶段的事务;相关事务逻辑要求幂等;存在执行过程被打断时,容易丢失数据的情况。

目前,市面上有很多优秀的中间件,比如 DTM、Seata,它们对分布式事务协调做了很多的优化,比如过程中如果出现打断情况,它们能够自动重试

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

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

相关文章

OM | 具有弹性需求的广义随机共乘(拼车)用户均衡问题

编者按&#xff1a; 通过扩展确定性共乘用户均衡问题&#xff0c;提出了具有弹性需求的广义随机共乘用户均衡问题&#xff0c;用于具有共乘出行活动的城市交通网络分析。 1、引言​ 共乘&#xff08;ridesharing&#xff09;&#xff0c; 即生活中的“拼车”、“顺风车”&am…

华为OD机试题,用 Java 解【斗地主】问题

最近更新的博客 华为OD机试题,用 Java 解【停车场车辆统计】问题华为OD机试题,用 Java 解【字符串变换最小字符串】问题华为OD机试题,用 Java 解【计算最大乘积】问题华为OD机试题,用 Java 解【DNA 序列】问题华为OD机试 - 组成最大数(Java) | 机试题算法思路 【2023】使…

巧用 ChatGPT,让开发者的学习和工作更轻松

引言 随着人工智能技术的快速发展和广泛应用&#xff0c;ChatGPT 作为一种新兴的自然语言处理模型&#xff0c;近期备受瞩目&#xff0c;引发了广泛讨论。 ChatGPT 具有多种应用场景&#xff0c;既可以用作聊天机器人&#xff0c;实现智能问答和自然语言交互&#xff0c;也可…

2.27自动化测试

第零步 根据脑图写测试用例第一步.创建共同类防止每次进行测试不同界面的时候都重新创建驱动浪费时间注意要用static 否则后续无法直接使用getdriver方法第二步 对登录界面写测试用例先在test下创建一个登录类.每个界面用不同的类,防止混在一起并让其继承common包下的commonDri…

让马斯克反悔的毫米波雷达,被国产雷达头部厂商木牛科技迭代到了5D时代

近日&#xff0c;特斯拉或将在其HW4.0硬件系统配置一枚高精度4D毫米波雷达的消息在外网刷屏。据分析&#xff0c;“纯视觉”信仰者马斯克之所以做出这样的决定&#xff0c;一方面是减配了雷达的特斯拉自动驾驶&#xff0c;表现不尽如人意&#xff1b;另一方面也跟毫米波雷达的技…

第13天-仓储服务(仓库管理,采购管理 ,SPU规格维护)

1.仓储服务开发配置 1.1.加入到Nacos注册中心 spring:application:name: gmall-warecloud:nacos:discovery:server-addr: 192.168.139.10:8848namespace: 36854647-e68c-409b-9233-708a2d41702c1.2.配置网关路由 spring:cloud:gateway:routes:- id: ware_routeuri: lb://gmal…

CDH 6.3.2启用YARN高可用

升级原因 CDH平台即将被切换成生产环境&#xff0c;而生产环境几乎都是HA&#xff0c;所以需要将YARN升级成HA。 升级准备 CDH已经成功安装并正常使用CMS的管理员账号正常登陆 CDH启用YARN HA 登陆CMS系统->选择YARN服务->点击进入到YARN服务详情页面&#xff0c;再…

【Yolov5】保姆级别源码讲解之-模型训练部分train.py文件

本次讲解yolov5训练类train.py1.主函数2.main函数2.1 第一部分 进行校验2.2 第二部分 配置resume参数用于中断之后进行训练2.3第三部分 DDP mode2.4 第四部分3.训练结果1.主函数 opt参数部分和main方法 weights&#xff1a;权重文件路径 – cfg&#xff1a;存储模型结构的配置…

解决AAC音频编码时间戳的计算问题

1.主题音频是流式数据&#xff0c;并不像视频一样有P帧和B帧的概念。就像砌墙一样&#xff0c;咔咔往上摞就行了。一般来说&#xff0c;AAC编码中生成文件这一步&#xff0c;如果使用的是OutputStream流写入文件的话&#xff0c;就完全不需要计算时间。但在音视频同步或者使用A…

pytorch入门3--线性回归以及许多python,pytorch函数的用法

先补充一些知识点&#xff0c;这里不一定用得到&#xff0c;后面的学习过程中可能用得到。 1.batch表示批量&#xff0c;就是一批数据集的意思&#xff1b; 2.batch_size表示数据集&#xff08;样本集、训练集&#xff09;的大小&#xff08;数据的个数&#xff09;&#xff1b…

进程与线程的区别

进程和线程 进程 一个在内存中运行的应用程序。每个进程都有自己独立的一块内存空间&#xff0c;一个进程可以有多个线程&#xff0c;比如在Windows系统中&#xff0c;一个运行的xx.exe就是一个进程。 线程 进程中的一个执行任务&#xff08;控制单元&#xff09;&#xf…

深入理解跳表及其在Redis中的应用

前言跳表可以达到和红黑树一样的时间复杂度 O(logN)&#xff0c;且实现简单&#xff0c;Redis 中的有序集合对象的底层数据结构就使用了跳表。其作者威廉普评价&#xff1a;跳跃链表是在很多应用中有可能替代平衡树的一种数据结构。本篇文章将对跳表的实现及在Redis中的应用进行…

蓝桥杯:染色时间

蓝桥杯&#xff1a;染色时间https://www.lanqiao.cn/problems/2386/learning/?contest_id80 问题描述 输入格式 输出格式 样例输入输出 样例输入 样例输出 评测用例规模与约定 解题思路&#xff1a;优先队列 AC代码(Java)&#xff1a; 问题描述 小蓝有一个 n 行 m 列…

华为OD机试题,用 Java 解【任务混部】问题

最近更新的博客 华为OD机试题,用 Java 解【停车场车辆统计】问题华为OD机试题,用 Java 解【字符串变换最小字符串】问题华为OD机试题,用 Java 解【计算最大乘积】问题华为OD机试题,用 Java 解【DNA 序列】问题华为OD机试 - 组成最大数(Java) | 机试题算法思路 【2023】使…

本地docker部署mysql,IDEA直连实战

1、安装mysql镜像 前文中我们安装了docker和redis镜像&#xff0c;并在idea中成功连接&#xff0c;现在安装mysql镜像 docker pull mysql &#xff0c;默认最新版本 ps:可以参考https://www.runoob.com/docker/docker-install-mysql.html 2、启动mysql 打开powershell&…

快速掌握 Flutter 图片开发核心技能

大家好&#xff0c;我是 17。 在 Flutter 中使用图片是最基础能力之一。17 做了精心准备&#xff0c;满满的都是干货&#xff01;本文介绍如何在 Flutter 中使用图片&#xff0c;尽量详细&#xff0c;示例完整&#xff0c;包会&#xff01; 使用网络图片 使用网络图片超级简…

【035】基于java的进销库存管理系统(Vue+Springboot+Mysql)前后端分离项目,附万字课设论文

1.3 系统实现的功能 本次设计任务是要设计一个超市进销存系统&#xff0c;通过这个系统能够满足超市进销存系统的管理及员工的超市进销存管理功能。系统的主要功能包括&#xff1a;首页、个人中心、员工管理、客户管理、供应商管理、承运商管理、仓库信息管理、商品类别管理、 …

【知识图谱】架构-特点-缺点简介

架构物联网、云计算、人工智能等新一代信息技术的迅猛发展&#xff0c;带来了制造业的新一轮突破&#xff0c;推动着制造系统向智能化方向发展&#xff0c;驱动着未来制造模式的创新。其中数据和知识是实现制造业与新一代信息技术融合的基础&#xff0c;是实现智能制造的保障。…

PyQt5(二) python程序打包成.exe文件

目录一、安装 **pyinstaller**二、pyinstaller 打包2.1 pyinstaller 打包机制参考链接前言我们在 pycharm 上写的程序在发送到一台没有安装 python 解释器的机器上是不能运行的&#xff0c;甚至还要安装程序中所使用的第三方包&#xff0c;这样极其不方便。 但是 PC 是可以直接…

【C++】哈希——unordered系列容器|哈希冲突|闭散列|开散列

文章目录一、unordered系列关联式容器二、哈希概念三、哈希冲突四、哈希函数五、解决哈希冲突1.闭散列——开放定址法2.代码实现3.开散列——开链法4.代码实现六、结语一、unordered系列关联式容器 在C98中&#xff0c;STL提供了底层为红黑树结构的一系列关联式容器&#xff0c…