- 博客(103)
- 收藏
- 关注
原创 异步优化看板查询接口,从29s优化至2.8s
该接口的业务需要查询出所有的测试项目,然后根据测试项目,进行查询该时间段内的每个项目对应的所有执行任务,根据任务的执行情况,返回成功失败比例。1、添加数据库索引优化性能,发现数据库原本已经添加了索引,并且每次查询耗时并不是很长,主要时间可能发生在了数据库 IO 上。所以就需要遍历所有的测试项目,目前测试项目有 200+, 后续的查询就需要遍历查询 200 多次测试记录的数据库。3、遍历 totalPageSize 页,将原本执行的任务分割成 10 条一个线程查询处理,添加任务到线程池中。
2024-10-17 11:40:37
640
原创 BigKey问题以及解决方案——Java全栈知识(52)
在 Redis 中,一个字符串类型最大可以到 512 MB,一个二级数据结构(比如 hash、list、set、zset 等)可以存储大约 40 亿个 (2^32-1)个元素,但实际上不会达到这么大的值,一般情况下如果达到下面的情况,就可以认为它是 Bigkey 了。【字符串类型】: 单个 string 类型的 value 值超过 1 MB,就可以认为是 Bigkey。【非字符串类型】:哈希、列表、集合、有序集合等,它们的元素个数超过 2000 个,就可以认为是 Bigkey。
2024-10-15 09:44:48
714
原创 线程池中常见的阻塞队列——Java全栈知识(51)
3. DelayedWorkQueue :是一个优先级队列,它可以保证每次出队的任务都是当前队列中执行时间最靠前的。左边是LinkedBlockingQueue加锁的方式,右边是ArrayBlockingQueue加锁的方式。比较常见的有4个,用的最多是ArrayBlockingQueue和LinkedBlockingQueue。workQueue - 当没有空闲核心线程时,新来任务会加入到此队列排队,队列满会创建救急线程执行任务。是懒惰的,创建节点的时候添加数据。Node需要是提前创建好的。
2024-10-09 16:15:00
382
原创 线程池的核心参数——Java全栈知识(50)
如果核心或临时线程执行完成任务后会检查阻塞队列中是否有需要执行的线程,如果有,则使用非核心线程执行任务。3,如果阻塞队列也满了,则判断线程数是否小于最大线程数,如果满足条件,则使用临时线程执行任务。1,任务在提交的时候,首先判断核心线程数是否已满,如果没有满则直接添加到工作线程执行。2,如果核心线程数满了,则判断阻塞队列是否已满,如果没有满,当前任务存入阻塞队列。2.CallerRunsPolicy:用调用者所在的线程来执行任务;4,如果所有线程都在忙着(核心线程+临时线程),则走拒绝策略。
2024-10-09 15:45:00
487
原创 锁升级机制——Java全栈知识(49)
在 JDK 1.6 之前,使用 synchronized 关键字需要依赖于底层操作系统的 Mutex Lock 实现,挂起线程和恢复线程都需要转入内核态来完成,也就是说阻塞或唤醒一个 Java 线程都需要系统去切换 CPU 状态,这种状态的切换需要消耗处理器时间。这也就是为什么 synchronized 属于重量级锁的原因,因为需要切换 CPU 状态导致效率低下,时间成本相对较高,特别是当同步代码的内容过于简单时,可能切换的时间还要比代码执行的时间长。
2024-10-09 11:28:05
385
原创 线上热迁移数据库
2、如果你使用 Binlog 同步的方式,在同步完成后再修改代码,将主库修改为新的数据库,这样就不满足可回滚的要求,一旦迁移后发现问题,由于已经有增量的数据写入了新库而没有写入旧库,不可能再将数据库改成旧库。3、迁移的过程需要做到可以回滚,这样一旦迁移的过程中出现问题,可以立刻回滚到源库不会对系统的可用性造成影响。2、数据应该保证完整性,也就是说在迁移之后需要保证新的库和旧的库的数据是一致的;1、迁移应该是在线的迁移,也就是在迁移的同时还会有数据的写入;5、第四阶段:查新库,写新库。
2024-09-30 15:26:18
607
原创 死锁产生的条件——Java全栈知识(46)
此时程序并没有结束,这种现象就是死锁现象...线程 t1持有 A 的锁等待获取 B 锁,线程 t2持有 B 的锁等待获取 A 的锁。能够监控线程,内存情况,查看方法的CPU时间和内存中的对 象,已被GC的对象,反向查看分配的堆栈。用于对jvm的内存,线程,类 的监控,是一个基于 jmx 的 GUI 性能监控工具。第二:使用jstack查看线程运行的情况,下图是截图的关键信息。t1 线程获得A对象锁,接下来想获取B对象的锁。t2 线程获得B对象锁,接下来想获取A对象的锁。第一:查看运行的线程。
2024-09-06 09:55:58
427
原创 ReentrantLock的原理——Java全栈知识(45)
可中断可以设置超时时间可以设置公平锁支持多个条件变量 (类似于 wait 等待)与 synchronized 一样,都支持重入注意:一定要去释放锁,要不然就会死锁。
2024-08-17 20:39:45
364
原创 什么是AQS——Java全栈知识(44)
全称是 AbstractQueuedSynchronizer(API),是阻塞式锁和相关的同步器工具的框架,它是构建锁或者其他同步组件的基础框架AQS与Synchronized的区别AQS关键字,c++ 语言实现java 语言实现悲观锁,自动释放锁悲观锁,手动开启和关闭锁竞争激烈都是重量级锁,性能差锁竞争激烈的情况下,提供了多种解决方案AQS常见的实现类ReentrantLock 阻塞式锁Semaphore 信号量CountDownLatch 倒计时锁。
2024-08-17 20:38:59
388
原创 volatile的理解——Java全栈知识(43)
一个当前内存值V、旧的预期值A、即将更新的值B,当且仅当旧的预期值A和内存值V相同时,将内存值修改为B并返回true,否则什么都不做,并返回false。如果CAS操作失败,通过自旋的方式等待并再次尝试,直到成功。Java内存模型(Java Memory Model)描述了Java程序中各种变量(线程共享变量)的访问规则,以及在JVM中将变量存储到内存和从内存中读取变量这样的底层细节。需要不断尝试获取共享内存V中最新的值,然后再在新的值的基础上进行更新操作,如果失败就继续尝试获取新的值,直到更新成功。
2024-08-17 20:38:27
977
原创 CAS的理解——Java全栈知识(42)
一个当前内存值V、旧的预期值A、即将更新的值B,当且仅当旧的预期值A和内存值V相同时,将内存值修改为B并返回true,否则什么都不做,并返回false。如果CAS操作失败,通过自旋的方式等待并再次尝试,直到成功。Java内存模型(Java Memory Model)描述了Java程序中各种变量(线程共享变量)的访问规则,以及在JVM中将变量存储到内存和从内存中读取变量这样的底层细节。需要不断尝试获取共享内存V中最新的值,然后再在新的值的基础上进行更新操作,如果失败就继续尝试获取新的值,直到更新成功。
2024-08-10 11:05:49
311
原创 轻量级锁和偏向锁——Java全栈知识(41)
Java中的synchronized有偏向锁、轻量级锁、重量级锁三种形式,分别对应了锁只被一个线程持有、不同线程交替持有锁、多线程竞争锁三种情况。锁的等级描述重量级锁底层使用的Monitor实现,里面涉及到了用户态和内核态的切换、进程的上下文切换,成本较高,性能比较低。轻量级锁线程加锁的时间是错开的(也就是没有竞争),可以使用轻量级锁来优化。轻量级修改了对象头的锁标志,相对重量级锁性能提升很多。每次修改都是CAS操作,保证原子性偏向锁。
2024-08-10 11:04:37
426
原创 Synchronized 的底层原理——Java全栈知识(40)
我们都知道 Synchronized 关键字会给代码上互斥锁,但是上锁的位置分为两种,分别是对象锁和类锁。
2024-08-10 11:04:02
545
原创 线程的状态,wait和sleep——Java全栈知识(39)
也就是调用 run()方法就是相当于在主进程中执行一次,调用 start() 方法就是开启一个新的线程去执行 run()方法中的内容。我们在使用 Callable 创建现成的时候需要指定泛型的类型,泛型的类型与 call 方法返回的值一致。Callable 创建线程适合于需要返回值的时候,我们只要使用 ft. get ()方法即可取出返回值。
2024-08-10 11:03:14
445
原创 创建线程的方法——Java全栈知识(38)
也就是调用 run()方法就是相当于在主进程中执行一次,调用 start() 方法就是开启一个新的线程去执行 run()方法中的内容。我们在使用 Callable 创建现成的时候需要指定泛型的类型,泛型的类型与 call 方法返回的值一致。Callable 创建线程适合于需要返回值的时候,我们只要使用 ft. get ()方法即可取出返回值。
2024-07-28 11:45:00
354
原创 并发基础——Java全栈知识(37)
进程是正在运行程序的实例,进程中包含了线程,每个线程执行不同的任务不同的进程使用不同的内存空间,在当前进程下的所有线程可以共享内存空间线程更轻量,线程上下文切换成本一般上要比进程上下文切换低(上下文切换指的是从一个线程切换到另一个线程)并发:并发在微观层面上是串行,但是由于切换比较快,所以说我们在宏观层面可以认为是并行(多个任务同时执行)并行:多个任务同时进行,四核CPU同时执行四个任务。
2024-07-28 08:45:00
492
原创 冷热分离——Java全栈知识(36)
冷热分离指的是在处理数据时将数据库分为冷库和热库,冷库指用于存放走到了终态的数据(冷数据)的数据库,热库用于存放还需要修改的数据(热数据)的数据库。
2024-07-27 23:28:21
541
原创 主从同步延迟——Java全栈知识(35)
当数据库主库有较大更新并发操作时,可能会导致主从同步延迟,因为从库里面读取 binlog 的线程仅有一个,当某个SQL 在从库上执行的时间稍长或者由于某个 SQL 要进行锁表就会导致主从同步延迟,主库的 SQL 大量积压,未被同步到从库里。例如,对于一个用户管理系统来说,注册+登录的业务读军操作全部访问主库,用户的介绍、爱好、等级等业务,可以采用读写分离,因为即使用户改了自己的自我介绍,在查询时却看到了自我介绍还是旧的,业务影响与不能登录相比就小很多,业务上一般可以接受。
2024-07-14 13:50:52
429
原创 MySQL的主从复制——Java全栈知识(34)
主从复制是指将主数据库的 DDL 和 DML 操作通过二进制日志传到从库服务器中,然后在从库上对这些日志重新执行(也叫重做),从而使得从库和主库的数据保持同步。MySQL 支持一台主库同时向多台从库进行复制,从库同时也可以作为其他从服务器的主库,实现链状复制。主从复制之后所有数据都一致,从库也可以作为主库给其他从库复制。
2024-07-14 13:49:59
399
原创 页分裂和页合并——Java全栈知识(33)
上篇文章我们讲到了 MySQL 的数据页,我们说到了 InnoDB 的索引是以 B+树的形式构建的,而且 B+树的节点都是一个数据页。但是 B+树在使用过程中难免会有节点分裂和节点合并的过程。因为我们是以数据页为基本单位构造的 B+树,那么 B+树的节点分裂和节点合并就会造成数据页的页分裂和页合并。我们都是知道,B+树是按照索引字段建立的,并且在 B+树中是有序的,假如有下面一个索引的树结构,其中的索引字段的值并不连续。
2024-06-28 20:39:51
594
原创 MySQL的数据页——Java全栈知识(32)
通过这种方式,InnoDB 利用 B+树和数据页的组合,实现了高效的数据存储和检索。B+树的非叶子节点对应着数据页,其中存储着主键+指向子节点(即其他数据页)的指针。B+树的叶子节点包含实际的数据行,每个数据行存储在一个数据页中。InnoDB 是以数据页为单位进行磁盘读写和文件 IO 的,也就是一次从磁盘到内存的最小单位就是 16KB,每次从内存到磁盘存储也是 16KB。通过 B+树的搜索过程,可以从根节点开始逐层遍历,最终到达叶子节点,找到所需的数据行。
2024-06-28 20:38:40
330
原创 MySQL事务——Java全栈知识(31)
缓冲池(buffer pool): 主内存中的一个区域,里面可以缓存磁盘上经常操作的真实数据,在执行增删改查操作时,先操作缓冲池中的数据(若缓冲池没有数据,则从磁盘加载并缓存),以一定频率刷新到磁盘,从而减少磁盘 IO,加快处理速度。通过名字我们就可以知首,在这种事务隔离级别下,一个事务可以读到另外一个事务未提交的数据。所以,这种隔离级别是可以避免脏读的发生的。可串行化 (Serializable)是最高的隔离级别,前面提到的所有的隔离级别都无法解决的幻读,在可串行化的隔离级别中可以解决。
2024-06-28 20:33:46
836
原创 索引创建原则和索引失效情况——Java全栈知识(30)
也就是说我们的联合索引(索引多列)必须要符合最左前缀法则,在查询的时候必须按照索引创建的顺序,不能跳跃前缀的列,否则索引将失效。5). 尽量使用联合索引,减少单列索引,查询时,联合索引很多时候可以覆盖索引,节省存储空间,避免回表,提高查询效率。6). 要控制索引的数量,索引并不是多多益善,索引越多,维护索引结构的代价也就越大,会影响增删改的效率。3). 尽量选择区分度高的列作为索引,尽量建立唯一索引,区分度越高,使用索引的效率越高。索引列不能参与运算,如果作为条件的索引列参与运算的话,索引也会失效,如下。
2024-06-27 10:24:57
376
原创 索引的分类和回表查询——Java全栈知识(29)
Mysql 的索引按照类型可以分为以下几类,但是我们使用的 InnoDB 只支持主键索引,唯一索引,普通索引,并不支持全文索引。
2024-06-24 22:39:38
709
原创 Mysql索引底层数据结构——Java全栈知识(28)
索引在项目中还是比较常见的,它是帮助MySQL高效获取数据的,主要是用来提高数据检索的效率,降低数据库的IO成本,同时通过索引列对数据进行排序,降低数据排序的成本,也能降低了CPU的消耗。
2024-06-24 22:32:15
951
原创 如何处理优化这个慢查询——Java全栈知识(27)
如果一条 sql 执行很慢的话,我们通常会使用 mysql 自动的执行计划 explain 来去查看这条 sql 的执行情况,比如在这里面可以通过 key 和 key_len 检查是否命中了索引,如果本身已经添加了索引,也可以判断索引是否有失效的情况,第二个,可以通过 type 字段查看 sql 是否有进一步的优化空间,是否存在全索引扫描或全盘扫描,第三个可以通过 extra 建议来判断,是否出现了回表的情况,如果出现了,可以尝试添加索引或修改返回字段来修复。那这个 SQL 语句执行很慢, 如何分析呢?
2024-06-24 08:45:00
249
原创 什么是慢查询——Java全栈知识(26)
慢查询:也就是接口压测响应时间过长,页面加载时间过长的查询原因可能如下:1、聚合查询2、多表查询3、单表数据量过大4、深度分页查询(limit)
2024-06-23 20:21:41
394
原创 为什么说 Redis 是单线程的?——Java全栈知识(25)
我们常说的 Redis 是单线程的,但是我前面在讲持久化机制的时候又说 RDB 的持久化是通过主进程 fork 出一个子进程来实现 RDB 持久化。那么 Redis 到底是多线程还是单线程的呢?但是在 Redis4.0 之后,Redis 引入了多线程模型,但是 IO 部分还是由单线程完成,而其他的如持久化存储模块、集群支撑模块等是多线程的。(Redis 6.0 之后将网络 IO 改为了多线程)info]前面我们讲到的 RDB 持久化,以及 Redis 集群支撑都是基于多线程完成的。
2024-05-20 21:32:01
515
原创 Redis如何解决缓存击穿问题——Java全栈知识(24)
我们在正常使用缓存的时候的流程大概就是这样的:请求访问缓存,缓存有数据就返回,缓存无数据就去数据库里面查数据写入到缓存中。
2024-05-18 22:53:12
306
原创 Redis如何应对缓存穿透问题——Java全栈知识(23)
我们在正常使用缓存的时候的流程大概就是这样的:请求访问缓存,缓存有数据就返回,缓存无数据就去数据库里面查数据写入到缓存中。
2024-05-18 22:19:13
396
原创 Redis 主从同步的原理——Java全栈知识(21)
简述全量同步和增量同步区别?全量同步:master 将完整内存数据生成 RDB,发送 RDB 到 slave。后续命令则记录在 repl_baklog,逐个发送给 slave。增量同步:slave 提交自己的 offset 到 master,master 获取 repl_baklog 中从 offset 之后的命令给 slave什么时候执行全量同步?slave 节点第一次连接 master 节点时slave 节点断开时间太久,repl_baklog 中的 offset 已经被覆盖时。
2024-05-18 16:51:22
612
原创 Redis的集群模式——Java全栈知识(20)
哨兵架构下 client 端第一次从哨兵找出 redis 的主节点,后续就直接访问 redis 的主节点,不会每次都通过 sentinel 代理访问 redis 的主节点,当 redis 的主节点挂掉时,哨兵会第一时间感知到。针对于分片,主节点只负责读和写,从节点只负责读操作,从节点的数据是依靠主节点同步过来,也就是和主从模式一样。Redis Cluster 能够自动检测节点的故障。当一个节点失去连接或不可达时,Redis Cluster 会尝试将该节点标记为不可用,并从可用的从节点中提升一个新的主节点。
2024-05-14 18:18:25
816
原创 Redis的数据淘汰策略——Java全栈知识(19)
数据过期策略是 redis 中设置了 TTL 的数据过期的时候 Redis 的处理策略。数据淘汰策略是 Redis 内存不够的时候,数据的淘汰策略:当 Redis 中的内存不够用时,此时在向 Redis 中添加新的 key, 那么 Redis 就会按照某一种规则将内存中的数据删除掉,这种数据的删除规测被称之为内存的淘汰策略。redis 的内存删除策略有:·noeviction: 不会淘汰任何键值对,而是直接返回错误信息。
2024-05-12 20:46:47
612
1
原创 Redis的数据过期策略——Java全栈知识(18)
定期删除会在 Redis 设置的过期键的过期时间达到一定阈值时进行一次扫描,将过期的键删除,但不会立即释放内存,而是把这些键标记为“已过期”,并放入一个专门的链表中。然后,在 Redis 的内存使用率达到定阈值时,Redis会对这些“已过期”的键进行一次内存回收操作,释放被这些键占用的内存空间。惰性删除是 Redis 的被动删除策略,它可以节省 CPU 资源,但是会导致过期的 key 始终保存在内存中,占用内存空间。定期删除是 Redis 的主动删除策略,它可以确保过期的 key 能够及时被删除,
2024-05-11 20:18:04
359
原创 Redis持久化策略——Java全栈知识(17)
1、RDB: 以快照的方式将此刻 Redis 中的数据以二进制的文件形式保存在磁盘中。RDB 的优点是:快照文件小、恢复速度快,适合做备份和灾难恢复。RDB 的缺点是:定期更新可能会丢数据(在最后一次数据快照到服务器宕机之间的数据就会丢失)2、AOF: AOF 是将 Redis 的所有写操作追加到 AOF 文件 (Append Only File)的结尾,从而记录了 Redis 服务器运行期间所有修改操作的详细记录。当 Redis 重新启动时,可以通过执行 AOF 文件中保存的写操作来恢复数据。AO
2024-05-09 21:53:59
510
原创 RabbitMQ是如何保证消息可靠性的?——Java全栈知识(16)
每个只能配置一个,因此我们可以在配置类中统一设置。我们在 publisher 模块定义一个配置类:log . error("触发return callback,");} });} }log . error("触发return callback,");} });} }Slf4j;import orglog . error("触发return callback,");} });} }
2024-05-07 19:27:33
1133
原创 RabbitMQ 是如何做延迟消息的 ?——Java全栈知识(15)
当一个队列中的消息满足下列情况之一时,可以成为死信(dead letter):架构:由于第一个队列没有消费者,所以可以在第一个队列中设置 TTL,当消息过期的时候,这个消息就变成了死信,被丢掉私信交换机中,以此实现延迟任务功能。前面两种作用场景可以看做是把死信交换机当做一种消息处理的最终兜底方案,与消费者重试时讲的作用类似。而最后一种场景,大家设想一下这样的场景: 如图,有一组绑定的交换机()和队列()。但是没有消费者监听,而是设定了死信交换机,而队列则与死信交换机绑定,RoutingKey是blue:
2024-05-06 22:07:50
1329
3
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人