首页 > 其他分享 >「数据密集型应用系统设计」读后感与团队高并发高性能实践案例

「数据密集型应用系统设计」读后感与团队高并发高性能实践案例

时间:2024-12-26 10:46:25浏览次数:4  
标签:读后感 主从复制 并发 复制 密集型 key 服务器 数据 节点

作者:京东物流 冯志文

一、分布式数据系统挑战

1.一致性(Consistency) :在多个节点上维护相同的数据副本,确保所有节点在任何给定时间点都能看到相同的数据状态。这是CAP理论中的C部分(一致性、可用性和分区容错性)。

2.可用性(Availability) :即使部分节点出现故障或网络分区,系统也要能够继续提供服务。这个问题与一致性相互冲突,因为为了提高可用性,可能需要牺牲一致性。

3.分区容错性(Partition Tolerance) :在网络分区情况下,系统仍然可以正常工作。网络分区可能会导致节点之间的通信中断,从而影响系统的整体性能和稳定性。

4.数据同步和复制:在多个节点上复制数据以提高可用性和减少单点故障带来的风险。但这引入了数据同步和一致性问题。

5.故障恢复和容错:当某个节点或组件发生故障时,系统需要能够自动检测并恢复到正常状态,或者在某种程度上继续运作。

6.扩展性和弹性:分布式系统应该能够根据需求灵活地扩展或收缩资源,以应对不断变化的负载。

二、理论篇

1)主从复制

1.1)为什么需要主从复制

简单来说,主从复制功能主要有以下三点作用。

1)读写分离

由于单台服务器可支持的能力有上限,故可部署1主N从,主库核心负责写,主从复制后,从库负责读(当然强一致性的比如财务金钱 读的还是主),以此提升中间件能力

2)数据容灾

任何服务器都有宕机的可能,同样可以通过主从复制功能提升中间件服务的可靠性;一旦主服务器宕机,可以立即将请求切换到从服务器,从而避免服务中断,继续提供服务。

3)分担主压力

比如mysql数据库大数据抽数,通过抽从库(数据量大),减轻主库压力

比如关闭redis主服务器持久化功能,由从服务器去执行持久化操作即可,以避免备份期间影响主服务器的服务。

1.2)mysql主从复制

1.2.1)原理

主从复制步骤:

①Master节点进行insert、update、delete操作时,会按顺序写入到binlog中。

②salve从库连接master主库。

③当Master节点的binlog发生变化时,binlog dump 线程会通知所有的salve节点,并将相应的binlog内容推送给slave节点。

④I/O线程接收到 binlog 内容后,将内容写入到本地的中继日志relay-log。

⑤SQL thread读取I/O线程写入的relay-log,并且根据 relay-log 的内容对从数据库做对应的操作。

 

 

1.2.2)主从复制模式

1、同步复制

 

 

2、异步复制:mysql默认的复制方式

 

 

3、半同步模式

 

 

1.2.3)主从复制binlog模式

MySQL 主从复制的 binlog 模式主要有以下几种:

1.基于语句的复制

◦在这种模式下,主库会将执行的每一条 SQL 语句记录到 binlog 中,然后从库会重新执行这些 SQL 语句。

◦优点:binlog 文件较小,适合大部分简单的 SQL 语句。

◦缺点:对于某些包含不确定性或依赖于环境的 SQL 语句(如NOW()UUID()),复制可能会出现不一致的情况。

2.基于行的复制

◦在这种模式下,主库会将每一行数据的变化记录到 binlog 中,而不是记录 SQL 语句本身。从库会直接应用这些行数据的变化。

◦优点:可以避免语句模式下由于某些 SQL 语句的不确定性导致的复制不一致问题,适用于复杂的 SQL 操作。

◦缺点:binlog 文件可能会变得非常大,特别是在进行批量更新或插入操作时。

3.混合模式复制

◦这种模式是 语句 和 行 的结合。在大部分情况下,MySQL 会使用 语句 模式,但在某些情况下(如无法保证语句在从库上执行结果一致时),会自动切换到 行 模式。

◦优点:结合了 语句 和 行 的优点,能够在大多数情况下保证复制的一致性和效率。

◦缺点:复杂性增加,可能需要更多的调试和监控。

具体选择哪种模式,通常取决于应用的具体需求和数据一致性的要求。

 

 

 

从 MySQL 5.7 开始,默认的binlog_format参数值是MIXED。在这种模式下,MySQL 会在大多数情况下使用基于语句的复制(SBR),但在某些需要更高一致性的情况下(例如,当语句包含不确定性或依赖于环境时),会自动切换到基于行的复制(RBR)。

1.3)Reids主从复制

本章节摘抄自 Redis5设计与源码分析

Redis 2.8提出了新的主从复制解决方案。

主从复制(全量复制)流程图:

 

 

master会在其内存中创建一个复制数据用的缓存队列,缓存最近一段时间的数据,master和它所有的

slave都维护了复制的数据下标offset和master的进程id,因此,当网络连接断开后,slave会请求master

继续进行未完成的复制,从所记录的数据下标开始。如果master进程id变化了,或者从节点数据下标

offset太旧,已经不在master的缓存队列里了,那么将会进行一次全量数据的复制。

 

 

 

主从复制初始化流程如图21-1所示。

 

 

从上图可以看到,当主服务器判断可以执行部分重同步时向从服务器返回"+CONTINUE";需要执行完整重同步时向从服务器返回"+FULLRESYNC RUN_ID OFFSET",其中RUN_ID为主服务器自己的运行ID,OFFSET为复制偏移量。

执行部分重同步的要求比较严格的:

1)RUN_ID必须相等;

2)复制偏移量必须包含在复制缓冲区中。

在生产环境中,经常会出现以下两种情况:

·从服务器重启(复制信息丢失);

·主服务器故障导致主从切换(从多个从服务器重新选举出一台机器作为主服务器,主服务器运行ID发生改变)。

这时候无法执行部分重同步的,而这两种情况又很常见,因此Redis 4.0针对主从复制又提出了两点优化,提出了psync2协议。

方案1:持久化主从复制信息。

Redis服务器关闭时,将主从复制信息(复制的主服务器RUN_ID与复制偏移量)作为辅助字段存储在RDB文件中;

Redis启动加载RDB文件,恢复主从复制信息,重新同步主服务器时携带持久化主从复制信息 ;

if(rdbSaveAuxFieldStrStr(rdb,"repl-id",server.replid)

== -1)return-1;

if(rdbSaveAuxFieldStrInt(rdb,"repl-offset",server.master_repl_offset)

== -1)return-1;

方案2:存储上一个主服务器复制信息。

/ Replication (master) /

charreplid[CONFIG_RUN_ID_SIZE+1]; / My current replication ID. /

charreplid2[CONFIG_RUN_ID_SIZE+1]; /初始化replid2为空字符串/

long longmaster_repl_offset; / My current replication offset /

long longsecond_replid_offset; **/初始化-1. /

当主服务器发生故障,自己成为新的主服务器时,便使用replid2和second_replid_offset存储之前主服务器的运行ID与复制偏移量;

voidshiftReplicationId(void) {

memcpy(server.replid2,server.replid,sizeof(server.replid));

server.second_replid_offset = server.master_repl_offset+1;

changeReplicationId();

}

判断是否能执行部分重同步的条件也改变为:

if(strcasecmp(master_replid, server.replid) &&

(strcasecmp(master_replid, server.replid2) ||

psync_offset> server.second_replid_offset))

{ ...

gotoneed_full_resync;

}

假设m为主服务器(运行ID为M_ID),A、B和C为三个从服务器;某一时刻主服务器m发生故障,从服务器A升级为主服务器(同时会记录replid2=M_ID),从服务器B和C重新向主服务器A发送"psync M_ID psync_offset"请求;显然根据上面条件,只要psync_offset满足条件,就可以执行部分重同步。

1.4)延迟复制问题

在使用延迟复制的数据库系统中,主从复制的数据传输并不是实时的,存在一定的延迟。这种延迟可能导致从服务器上的数据不是最新的,从而影响数据的一致性和系统的可靠性。以下是一些在使用延迟复制时需要注意的事项:

读写分离策略:在读写分离的系统中,确保关键的读取操作(如需要最新数据的查询)始终从主服务器读取,而非关键的读取操作可以从从服务器读取。

数据一致性要求:根据业务需求,明确哪些操作需要读取最新数据,哪些操作可以容忍一定的延迟。

2)数据分区

面单海量数据或者高并发场景的数据,主从复制技术还不够,还需要将数据拆分为多个分区。分区的目的是为了高可扩展性。

2.1)分区算法

取模

取模算法虽然使用简单,但对机器数量取模,在集群扩容和收缩时却有一定的局限性:因为在生产环境中根据业务量的大小,调整服务器数量是常有的事,而服务器数量N发生变化后hash(key)%N计算的结果也会随之变化!

 

 

比如:一个服务器节点挂了,计算公式从hash(key)% 3变成了hash(key)% 2,结果会发生变化,此时想要访问一个key,这个key的缓存位置大概率会发生改变,那么之前缓存key的数据也会失去作用与意义。

大量缓存在同一时间失效,造成缓存的雪崩,进而导致整个缓存系统的不可用,这基本上是不能接受的。为了解决优化上述情况,一致性hash算法应运而生~

Hash

散列是一种将输入数据(通常是键)转换为固定长度的值(通常是整数)的过程。这个固定长度的值称为哈希值。散列函数是执行这种转换的函数。常见的散列函数包括 MD5、SHA-256 以及更简单的 CRC16 等。

特点

•散列函数的输出是一个固定长度的哈希值。

•相同的输入总是会产生相同的输出。

•散列函数的设计目标是使不同的输入尽量均匀地分布到输出范围内,以减少冲突。

数据量和请求量分布均匀:使用散列函数将数据均匀分布到各个节点上,确保每个节点存储的数据量和处理的请求量大致相同,从而避免单个节点成为性能瓶颈。

扩容短板:当需要扩容时,增加或减少节点会导致大量数据需要重新分配,因为散列函数的结果会发生变化。这种情况下,几乎所有的数据都需要迁移到新的节点,导致扩容过程复杂且影响性能。

范围

扩容好:使用范围分片时,每个节点负责一定范围的数据。当需要扩容时,只需将新的范围分配给新节点,旧节点上的数据迁移量较小,扩容过程相对简单。

请求量不均匀:由于数据分布是基于范围的,如果某些范围的数据请求量特别大,会导致部分节点负载过高,而其他节点负载较低,造成请求量的不均匀分布。

一致性Hash

2011左右比较火的分布式缓存框架memcache就是使用的一致性hash算法。

平衡数据分布和扩容问题:一致性Hash通过将数据和节点都映射到一个虚拟的环上,使得每个节点只负责环上特定范围的数据。扩容时,只需将部分数据从现有节点迁移到新节点,迁移量较小,数据分布也相对均匀。

减少数据迁移:当添加或删除节点时,只需重新分配相邻节点的数据,大部分数据不需要移动,极大地减少了数据迁移量。

假设需要增加一台服务器CS4,经过同样的hash运算,该服务器最终落于t1和t2服务器之间,具体如下图所示:

 

 

此时,只有t1和t2服务器之间的部分对象需要重新分配。在以上示例中只有o3对象需要重新分配,即它被重新到CS4服务器。

所以一致性哈希算法对于容错性和扩展性有非常好的支持。但一致性哈希算法也有一个严重的问题,就是数据倾斜

如果在分片的集群中,节点太少,并且分布不均,一致性哈希算法就会出现部分节点数据太多,部分节点数据太少。也就是说无法控制节点存储数据的分配。

哈希槽:散列和取模的结合

Redis集群(Cluster)并没有选用上面一致性哈希,而是采用了哈希槽(SLOT)的这种概念。主要的原因就是上面所说的,一致性哈希算法对于数据分布、节点位置的控制并不是很友好。

1.散列函数:首先,使用散列函数 CRC16(key) 将键转换为一个哈希值。

2.取模运算:然后,对哈希值进行 16384 取模来得到具体槽位。HASH_SLOT = CRC16(key) mod 16384

2.2)分库分表

•个人建议能不分就不分,通过合适的索引,读写分离、冷热数据等方式,可以很好的解决性能问题:避免”过度设计"和"过早优化"

•数据量过大,正常运维已经影响到了业务访问的阶段才开始考虑分

分库分表有2种模式,分别如下

1.CLIENT模式:Apache开源社区的ShardingSphere-JDBC、阿里的TDDL

2.PROXY 模式:Apache开源社区的ShardingSphere-Proxy、公司弹性数据库JED(京东弹性数据库,个人未实践过其分表功能),阿里的cobar,MyCAT

核心的步骤基本都是一样的:SQL解析,优化,路由,执行,结果归并。

mycat架构图:

 

 

ShardingSphere混合部署架构图:

 

 

2.3)扩容理想状态

最好不要数据迁移、无数据热点的问题

1)范围求模分片案例: 优点可以避免扩容时的数据迁移,又可以一定程度上避免范围分片的热点问题 1)比如数据库刚开始预估是4000W数据量,采用2个库shard0、shard1。里面分别有2张表Table_0,Table_1。通过idhash2分别对应不同shard0、shard1数据库库。里面数据量再通过范围比如0-2000w定位到Table_0,2000-4000w定位到Table_1.

 

 

 

2)扩容(不迁移数据):比如数据量超过了4000万,需要扩容的时候,之前0-4000万数据保持不动,比如扩容到1个亿。则采用上面类似算法,把6000-1个亿的数据再次分布

 

 

 

3)热点:解决数据热点的问题(因为我们局部用了散列) 4)总结:1.多查一次数据库(字典表)2.依赖全局的ID生成

2.4)Redis高可用集群

 

 

redis集群是一个由多个主从节点群组成的分布式服务器群,它具有复制、高可用和分片特性。Redis集群不需要sentinel哨兵也能完成节点移除和故障转移的功能。需要将每个节点设置成集群模式,这种集群模式没有中心节点,可水平扩展

Redis Cluster 将所有数据划分为 16384 个 slots(槽位),每个节点负责其中一部分槽位。槽位的信息存储于每个节点中。当 Redis Cluster 的客户端来连接集群时,它也会得到一份集群的槽位配置信息并将其缓存在客户端本地。这样当客户端要查找某个 key 时,可以直接定位到目标节点。同时因为槽位的信息可能会存在客户端与服务器不一致的情况,还需要纠正机制来实现槽位信息的校验调整。

槽位定位算法

Cluster 默认会对 key 值使用 crc16 算法进行 hash 得到一个整数值,然后用这个整数值对 16384 进行取模来得到具体槽位。HASH_SLOT = CRC16(key) mod 16384

 

关于Redis集群选举原理、缓存穿透、雪崩、击穿等其他信息 网上很多资料,大家可搜索参考

三、实践篇-高并发高性能

1)数据库主从模式

采用1主2从模式,业务配置写主库,可延迟的导出或者查询采用读从库。如果对配置一致性比较强,则读主库。从库另外一个作用是大数据抽数,晚上抽数任务运行,但不影响主库

 

 

由于本身黄金链路不依赖mysql数据库,并且业务数据量在百万以下,离线数据千万及左右,主要用于大数据离线抽数表,过期数据及时结转,故没有采用分库分表策略。

踩坑案例:一条delete语句导致主从延迟问题

前提:mysql-binlog模式是row 现象: 在业务验证阶段,发现大数据抽数数据不全(数据库主库数据2800W,大数据抽到1500W数据) alpha_aging_product_info_no_degrade_v2表数据量5700W(保留2天数据)

排查过程: 通过分析,发现大数据抽数的时候数据库从库数据1500W少了,但主库数据没少,主库数据是2800万。通过查看数据库监控,发现是主从延迟较长,延迟11小时(当时没配主从延迟报警)

 

 

找规律:观察是从10.18号开始延迟明显

 

 

经过分析操作记录如下: 1.10.8号加的delete语句:delete from alpha_aging_product_info_no_degrade_v2 where create_time <'2022-10-19 00:00:00'; 主从延迟小于30分钟,可接受 2.10.18号添加了一个组合索引(仓+地址) 3.10.18号delete表数据的时候,导致主从延迟慢。 根本原因: 因为上面的sql增加了索引加剧了主从延迟,如果 delete 的数据是大量的数据,则会: 1.如果不加 limit 由于需要更新大量数据,从而索引失效变成全扫描导致锁表,同时由于修改大量的索引,产生大量的日志,导致这个更新会有很长时间,锁表锁很长时间,期间这个表无法处理线上业务。 2.由于产生了大量 binlog 导致主从同步压力变大。 3.由于标记删除产生了大量的存储碎片。由于 MySQL 是按页加载数据,这些存储碎片不仅大量增加了随机读取的次数,并且让页命中率降低,导致页交换增多。 改进点: 1.由于该数据库只为promise给路由推数不降级数据使用,数据库只有增加操作,故可让大数据抽主库 2.truncate table(VtDriver驱动是不支持truncate语法),truncate操作需要慎用,需要根据业务场景评估。 truncate表都是高危操作,特别是在生产环境要更加小心,下面列出几点注意事项,希望大家使用时可以做下参考。 1.truncate无法通过binlog回滚。 2.truncate会清空所有数据且执行速度很快。 3.truncate不能对有外键约束引用的表使用。 4.执行truncate需要drop权限,不建议给账号drop权限。 5.执行truncate前一定要再三检查确认,最好提前备份下表数据。 思考点: 1. MySQL单表记录数过大,思考是否一定要用MYSQL?比如JDQ数据传输等 2.当MySQL单表记录数过大时,增删改查性能都会急剧下降,任何的sql操作都不能根据常规思维去操作(比如加字段,加索引,删除语句,Select查询语句等) 3.XBP的SQL审批工单添加备注:表记录数,比如同一个sql 表数据10万和1千万是不一样的。

2)大key治理

2.1)扫描大key

大KEY带来的影响:

•严重影响 QPS、TP99 等指标,对大Key进行的慢操作会导致后续的命令被阻塞,从而导致一系列慢查询。

•大Key发生热点,大 String,value 大于 20K。当OPS为 10000,流量即为 200M, 达到单实例的流量配额. 导致无法正常提供服务。

集群各分片内存使用不均。某个分片占用内存较高或OOM,发送缓存区增大等,导致该分片其他Key被逐出,同时也会造成其他分片的资源浪费。

•集群各分片的带宽使用不均。某个分片被流控,其他分片则没有这种情况,且影响宿主机上的其它应用。

2.2)大key改造

2.2.1)改造list set zset hash元素个数:1000

改造案例1:清理Hash里面field过期数据,让大key瘦身

针对仓库产能大key:iwpc:xxx:yyy:2:610:14:1:0里面对应field是对应的每天日期比如2024-01-1,故集合元素个数1218个是因为运行了3年多,由于存储的Hash结构缓存没有对过期的filed删除(如下图还存在2023年数据,这些数据已经无效)。由于Redis和JIMDB本身对Hash(key,field,value)的field字段不支持自动过期。 需要代码判断并且hDel(String key, String... fields)对过期的field删除。

 

 

代码改造


//首次个人设置清空历史1000+天数据
//后面代码自动找到过去7天的fields日期,执行dele
allFields.forEach( expireDay -> {
        deleteCache(logPrefix,storeProductionKey,expireDay);
});


private void deleteCache(String logPrefix,StoreProductionKey storeProductionKey, String day){
    String key = storeProductionKey.generateConfigKey();
    CallerInfo callerInfo = umpService.registerInfo(".XXX.deleteCache");
    try{
        redisClient.hDel(logPrefix, key, day);
    }catch (Exception e){
        if(log.isErrorEnabled()){
           log.error(logPrefix +"XXX" + key + day,e);
        }
        umpService.functionError(callerInfo);
    }finally {
        umpService.registerInfoEnd(callerInfo);
    }
}

2.2.2) 把大key变小key

改造案例2:重新定义唯一key,把大key变小key 背景:大宗时效数据,系统刚开始设计的key是promise:control:${controlType} 备注:controlType是订单类型,对应value是Map<String, WhiteSkuTimeRangeCO> 其中String是#{deliveryCenterId}:#{storeId)(对应配送中心+仓库ID )


public class WhiteSkuTimeRangeCO {
    /**
     * 开始时间
     */
    @JSONField(name = "st")
    private long effectSt;

    /**
     * 结束时间
     */
    @JSONField(name = "ed")
    private long effectEd;
}

刚开始数据量不大,大key不明显,运营N年后,数据量变成1000+条,大key就体现出来了

改造后key变成promise:control:${controlType}:#{deliveryCenterId}:#{storeId),如上图。

3)热key治理

热key产生有很多原因

案例1: 流量倾斜:比如流量严重倾斜导致的,比如大促扩容机器,都是copy行云分组,导致新机器都链接到同一个config对应的S分片,如果S分片是默认读组,则新机器流量都打到这个分片上,流量高峰期则会产生热key。 解决方案:分组修改confing,让jimdb负载均衡平均。或者修改读组策略(比如轮循s分片)

 

案例2: 比如promise:xxx:yyy|:zzz这个key,固定前置,hash到固定的某个槽位,流量都打到这个机器。即是热key也是大key

解决方案: 1)首先本地缓存是一方面,但没有从根源解决。 2)如果某个关键被确认为热点,一个简单方法在关键字开头或者结尾添加一个随机数(比如两位数),这样就可以将关键字分布到100个不同的关键字上,从而分配到不同的分区上。比如上面key对应改造为 promise:xxx:yyy|:zzz:01 ...... promise:xxx:yyy|:zzz:50 ...... promise:xxx:yyy|:zzz:99

 

参考文献

1、《数据密集型应用系统设计》

2、 《Redis设计与实现 第二版》

3、《Redis5设计与源码分析》

4、Redis之哈希分片原理一致性哈希算法与crc16算法

5、一致性 Hash 算法原理&应用梳理

如果文中有任何不足之处,恳请各位不吝赐教,留言指正。谢谢大家的阅读和反馈!

标签:读后感,主从复制,并发,复制,密集型,key,服务器,数据,节点
From: https://www.cnblogs.com/Jcloud/p/18632188

相关文章

  • Java程序员如何获取高并发经验?
    现在好点的互联网公司招聘基本都要求有高并发经验,但没有高并发的经验的人感觉只有在好点的互联网才获得高并发经验,这难道不是死循环?没有高并发经验的人如何才能获取高并发方面的经验呢?如何获取高并发经验?其实并不是去了大公司就能获得高并发的经验,高并发只是一个结果,并不是过......
  • golang并发测试http demo
    packagemainimport( "bytes" "fmt" "math/rand" "net/http" "sync" "time")const( url="http://127.0.0.1:8080"//请求的URL ratePerSecond=10......
  • Redis分片集群+MQ处理高并发
    Redis的三大集群模式:主从复制、哨兵模式和Cluster模式。每种模式都有其特点和应用场景,具体如下:主从复制模式:适用于数据备份和读写分离场景,配置简单,但在主节点故障时需要手动切换。哨兵模式:在主从复制的基础上实现自动故障转移,提高高可用性,适用于高可用性要求较高的场景。Clu......
  • 数据库系统------并发控制
    基于锁的协议锁机制用于控制并发访问数据项锁协议是事务在请求和释放锁时需要遵循的一组规则。锁协议的目的是确保事务的并发执行不会导致数据的不一致性,同时帮助系统避免死锁和其他问题锁的两种模式排它锁(ExclusiveLock,X模式)目的:一个事务在对数据项进行操作时,可以对......
  • Go 并发控制:sync.WaitGroup 详解 GoCN 2024年12月24日 16:37 浙江 听全文
    Go并发控制:sync.WaitGroup详解GoCN  2024年12月24日16:37 浙江 听全文 以下文章来源于Go编程世界 ,作者江湖十年Go编程世界.不限于Golang、Docker、Kubernetes,技术博客https://jianghushinian.cn/的移动版。前段时间我在《Go并发控制:errgroup详解》......
  • 深入理解 Java 中的并发编程:线程池与锁的使用
    深入理解Java中的并发编程:线程池与锁的使用在现代应用程序开发中,特别是在高并发场景下,如何高效地管理多个线程成为一个关键问题。Java提供了多种方式来处理并发编程,其中线程池和锁机制是最常用的两种方法。本文将深入探讨Java中的并发编程,重点讲解线程池的使用和锁......
  • Lock锁并发原理
    packagecom.wb.demo.util;importcom.graphbuilder.struc.LinkedList;importjava.util.concurrent.TimeUnit;importjava.util.concurrent.locks.Condition;importjava.util.concurrent.locks.Lock;importjava.util.concurrent.locks.ReentrantLock;publicclass......
  • 并发编程相关
    相关面试题: 计算机组成 a=2+3 2,3从内存拿到cpu->计算->结果放到内存 操作系统管理线程的调度,os把app的线程指令扔到cpu调度策略,最常见的cfs 线程数不一定越多越好,线程切换  CAScompareandswap在JDK中的应用,原子类do{}while(!cas) ABA问题解决增......
  • 高级java每日一道面试题-2024年12月23日-并发篇-CAS有什么缺点吗 ?
    如果有遗漏,评论区告诉我进行补充面试官:CAS有什么缺点吗?我回答:CAS(Compare-And-Swap,比较并交换)是一种无锁算法的核心操作,广泛用于实现并发控制。它通过硬件指令直接在内存中进行原子操作,避免了传统锁机制的上下文切换开销。然而,CAS也并非完美,它具有一些缺点和局限性......
  • 高级java每日一道面试题-2024年12月23日-并发篇-多线程有什么用 ?
    如果有遗漏,评论区告诉我进行补充面试官:多线程有什么用?我回答:多线程编程是Java中非常重要的一个概念,它允许程序在同一时间执行多个任务。在现代计算机系统中,多线程技术的应用可以极大地提升应用程序的性能、响应速度以及资源利用率。以下是关于多线程用途的详细解......