- 博客(135)
- 收藏
- 关注
原创 线程池核心线程数如何确定
理论并发数 × 并发任务数 (如果每个请求需要并发执行多个任务,实际需要的线程数要乘以任务数)= QPS × 平均响应时间 (在任意时刻,系统中有多少个请求正在处理)L(平均库存):系统中平均存在的实体数量(如顾客、产品、任务等)。这是最基础的排队论公式,用于计算系统需要的并发处理能力。λ(平均到达率):单位时间内进入系统的实体平均数量。W(平均停留时间):单个实体在系统中停留的平均时间。激进配置:追求性能,流量波动大。实际并发数 × 0.7。实际并发数 × 1.5。CPU 核心数 + 1。
2026-10-09 17:16:49
229
原创 Redis单线程和Tair多线程架构设计对比
例如,如果有 100 个客户端同时对 key "user:1001" 发起 GET 请求,这些请求会在网络层被接收,然后进入 Redis 的命令队列,主线程会逐个执行这些 GET 命令。比如两个线程同时执行 "SET key value" 操作,如果没有同步机制,最终 key 的值可能是不确定的。Tair 选择多线程架构,可能是为了支持更复杂的操作或更好的可扩展性,但在处理高并发简单请求时,锁机制成为了性能瓶颈。:根据锁的实现方式,可能会出现某些线程长期获取不到锁的情况,导致请求延迟不均。
2026-09-17 19:57:49
349
原创 怎么理解Spark中的CU(计算单元)
如果你想优化资源利用率,可以尝试将单 Executor 调整为 5 core / 11 GB——这样 CPU 维度 = 20 × 5 + 4 = 104,内存维度 = (21 × 11) / 2.25 = 102.67 ≈ 103,CU 消耗就从 150 降至 104,资源浪费减少了约 30%,同时总计算能力(总 core 数 104,总内存 220 GB)反而得到了更均衡的分布。在大多数平台中,driver 的内存也纳入总内存计算,但 driver 的 CPU 核数通常在占比较小,容易被内存维度覆盖。
2026-09-10 17:03:25
252
原创 Spark 任务如何实现幂等?
原文的确定性回放方案在批处理回库场景中提供了一条极其简洁且优雅的路径——不依赖额外的状态存储,不改目标系统,仅通过数据组织方式就天然保证了幂等。作业重试时,D 不变,则 R 也不变。确定性回放不能覆盖所有场景——当写入语义不是覆盖写,或者输出端是外部 API 时,需要针对目标存储选择不同的幂等方案。对于需要持续运行的流式作业,短暂的幂等写入还不够——还需要保证作业重启后能从正确的位点恢复,不丢数据也不重复处理。与原文讨论的输入保持不变的假设不同,实际生产环境中,反复重试可能面临输入数据发生变化的场景。
2026-09-10 16:54:49
266
原创 Outbox 投递器:事务性发件箱模式详解
的事实标准方案,目前已被广泛集成到各种框架和工具中,如 .NET 的 CAP、Go 的 go-outbox、Java 的 Spring Modulith 等。,它们是两个独立的系统。如果数据库写入成功,但消息发布失败(网络抖动、MQ 宕机),事件就丢了,下游服务永远不知道这笔订单发生了什么事,数据最终不一致。由于业务数据和事件记录在同一个本地事务中,要么一起成功,要么一起回滚,想象一个典型的电商场景:用户下单后,你需要同时做两件事——联合索引,支撑投递器高效轮询。问题是,这两个操作分别针对。
2026-08-30 18:48:05
407
原创 本地缓存 vs 分布式缓存的一致性保障
将某个数据的所有写操作都路由到同一个实例处理(如一致性哈希),该实例在更新 DB 后直接失效自己的本地缓存。最通用的做法,写操作完成后,通过 MQ 或 Redis Pub/Sub 广播一条缓存失效消息,所有订阅的实例收到后删除本地缓存中的对应条目。因为每个应用实例各自维护一份独立的内存副本,当数据发生变更时,必须让所有实例都知道"你的缓存过期了"。,所有应用实例共享同一个缓存视图,不需要跨实例同步。这与本地缓存面临的问题本质相同——写入 DB 后,缓存中的旧数据如何更新?分布式缓存的数据集中在。
2026-08-29 17:14:36
257
原创 各数据结构操作的时间复杂度汇总
维护头指针(front)和尾指针(rear),在数组逻辑上形成环,避免数组头部删除后大量移动元素。非连续存储,每个节点包含数据和指向下一节点的指针(单向链表)或前驱/后继指针(双向链表)。节点结构(数据 + 左孩子指针 + 右孩子指针),递归定义:左子树所有节点 < 根节点 < 右子树所有节点。,通常为几百到上千,因此树的高度很低(通常 3~4 层),磁盘 I/O 次数极少。链表不需要连续内存,插入/删除只需修改指针,因此是 O(1)。,重新分配更大的数组并将所有元素重新哈希,摊还成本为 O(1)。
2026-08-28 22:43:51
375
原创 垂直分库和水平分库分别解决了什么问题
先按业务模块做垂直分库,再对数据量大的业务表(如订单表、用户表)做水平分库,形成"先垂直后水平"的分层拆分策略,这也是大型互联网系统常见的数据库拆分方案。按照某种拆分规则(如取模、哈希、范围)分散到多个数据库实例中,每个库存储表的一部分数据行,但所有库的表结构完全相同。将数据库拆分成多个独立的库。例如,将原本在一个库中的用户表、订单表、商品表分别拆分到。分到 4 个库中,每个库各存 1/4 的用户数据。中,每个库只负责自己业务域的数据。
2026-08-28 20:07:38
370
原创 为什么数据库不能无限制的通过增加从库数量来解决容量问题
面对容量问题时,想到的第一个解决办法可能就是增加数据库从节点/从库。但是这种解决办法是否会带了现在的问题?
2026-08-28 19:56:21
199
原创 读书笔记-《重构:改善既有代码的设计》
1.13如果你要给程序添加一个特性,但发现代码因缺乏良好的结构而不易于进行更改,那就先重构那个程序,使其比较容易添加该特性,然后再添加该特性。准备好测试case,用于验证重构前后是否结果一致。(bug检测器)1.14每次成功的重构后我都会提交代码,如果待会不小心搞砸了,我便能轻松回滚到上一个可工作的状态。把代码推送(push)到远端仓库前,我会把零碎的修改压缩成一个更有意义的提交(commit)。变量接近调用地方;减少临时变量,改为作为参数传入方法;主方法简单;重构时先不用管性能问题。1.15。
2026-01-29 21:16:36
363
原创 Spring集合注入Bean
在Spring框架中,注入Bean集合是一种非常实用的功能,它允许你将同一类型的所有Bean自动收集到一个集合中。以下是实现这一功能的几种主要方式:1.2 使用注入Map2. 更精细的控制方式2.1 使用进行筛选2.2 使用自定义注解筛选3. Java配置类方式4. 排序注入的Bean集合4.1 使用注解4.2 实现接口5. 条件化Bean集合注入最佳实践建议接口设计:为可注入的Bean集合定义清晰的接口命名规范:使用有意义的Bean名称,便于在Map中识别空安全:
2025-04-22 17:15:17
725
原创 浅谈Java泛型的类型推断
function2T 返回类型是 T,但 map 方法并不知道 T 的具体类型,编译器无法从 function2T 的返回类型 T 推断出 R 的具体类型,因为 T 是一个泛型类型参数,而不是具体的类型。在这里,T 的类型是由 Set< T > 的声明决定的。编译器知道 result 的类型是 Set< T >,因此可以推断出的返回类型是 T。是一个新的泛型类型参数。编译器需要从上下文中推断出 R 的具体类型。诶,我这function2T明明返回的就是T类型的呀?中,map 方法的返回类型是。
2025-03-03 20:05:44
538
原创 Java常用注解--@FunctionalInterface 函数式接口
必须是一个接口有且仅有一个抽象方法(允许包含默认方法或静态方法)。使用注解标记,编译器会强制校验是否符合条件。// 唯一抽象方法// 什么也不干,谁实现的就干什么// 默认方法不计入抽象方法数量// 模拟异步操作}).start();// 调用如何简化?// 定义回调接口// 使用回调try {// 调用时需实现所有方法(即使不关心某些情况)@Override@Override// 即使不需要处理失败,也必须实现空方法});问题。
2025-02-20 16:46:54
2240
原创 TiDB热点问题
按时间不停写入的数据,不停的在增长的有序数据,与AUTO_INCREMENT的主键类似,它也会不停的往最后一个range进行写入,因此最后一个range会成为热点。常见的 increment 类型自增主键就是顺序递增的,默认情况下,在主键为整数型时,会用主键值当做 RowID ,此时 RowID 为顺序递增,在大量 insert 时形成表的写入热点。TiDB的数据是按照有序的range进行划分的,主键自增,会导致写入都发生在做最后的range上,因此最后的range会是热点。来生成主键,将主键做了随机化。
2024-07-17 17:30:17
1116
原创 Spring aop切面编程
注解用于标记在需要进行审计日志记录的方法上,通过指定操作类型和目标表来描述该方法的行为。这种标记方式为 AOP 提供了一个“切入点”(Pointcut),使得 AOP 可以识别出哪些方法需要进行特定的处理。,它通过 AOP 拦截所有标记了。
2024-05-08 14:51:56
679
1
原创 Java CompletableFuture结合线程池 - 异步多线程
CompletableFuture是对Future的扩展和增强。CompletableFuture实现了Future接口,并在此基础上进行了丰富的扩展,完美弥补了Future的局限性,同时 CompletableFuture 实现了对任务编排的能力。借助这项能力,可以轻松地组织不同任务的运行顺序、规则以及方式。
2024-04-09 11:18:00
734
原创 TiDB分布式关系型数据库
TiDB 是一个开源的分布式关系型数据库,由 PingCAP 公司主导开发。它的设计目标是提供水平可扩展的高性能分布式事务数据库,同时保持与 MySQL 协议的兼容性和事务的 ACID(原子性、一致性、隔离性和持久性)特性。水平扩展:TiDB 支持无缝的水平扩展,能够通过增加新节点来应对增长的数据量和事务负载。分布式事务:TiDB 提供完全的分布式事务支持,采用了基于 Google Percolator 模型的事务算法,可以提供跨节点的一致性。
2024-03-15 17:35:43
704
原创 HBase非关系型数据库
HBase – Hadoop Database,是一个高可靠性、高性能、面向列、可伸缩、 实时读写的分布式数据库。HBase是一个NoSQL数据库,把数据存在HDFS上,低成本来存储海量的数据并且支持高并发随机写和实时查询。HBase 的原型: Google 的 BigTable 论文。
2024-03-11 16:15:15
1410
原创 Spark scala如何本地运行
运行一个spark任务需要打包任务并上传到spark集群上运行,但是往往远端运行时间较长、众多处理器的日志收集困难,导致spark任务的调试时间成本很高,几个小时的等待可能换来的只是一个低级的错误。Apache Spark是一个开源的大数据处理框架,它提供了一个接口用于编程大规模分布式计算,且提供了很多高级工具,包括支持SQL查询、流数据处理、机器学习和图计算等。那么如何不提交远端Spark集群,在本地就像调试Java代码一样调试Spark scala。
2024-02-06 17:29:24
1072
原创 Spark如何用repartition来提升执行效率
在这种情况下,Spark会尽量保证每个分区中的数据量大致相等,但并不能保证每个分区中的数据在业务逻辑上的均匀分布。也就是说,如果你的数据在某个特定的列上有特定的分布模式,那么在重新分区后,这种分布模式可能会被打乱。果在调用 repartition 方法时没有指定列,那么Spark会将数据均匀地分布到指定数量的分区中,但具体的分区策略是不确定的。需要注意的是,repartition 操作会引发全量数据的洗牌,可能会消耗大量的计算和I/O资源,因此在使用时需要谨慎考虑。
2024-02-02 17:03:50
1381
原创 Spark如何用累加器Accumulator收集日志
Spark任务的实际运算是交由众多executor来执行的,如果再执行算子内部打印日志,是需要到对应的executor上才能看到。当不知道对应executor的情况下就需要挨个查询日志,是否不方便。是否有办法可以收集所有executor上的日志内容打印在driver上呢?这样就可以直接在stdout里看到所有日志。
2024-01-30 17:00:58
713
原创 Spark性能调优
2.1 增加大数据量位置的repartition数。2.2 增加spark session的超时时间。1 首先可以尝试开大executor的内存分配。
2024-01-30 15:24:36
895
原创 为什么写进MySQL里的数据顺序乱了?
使用Collectors.groupingBy收集器对流(Stream)中的元素进行分组时,默认情况下会使用ArrayList来收集同一组内的元素,List的顺序是按照它们在流中出现的顺序添加的。但是因为因为HashMap不保证顺序,key的迭代顺序可能与元素被插入到Map中的顺序不同。
2024-01-23 11:31:07
1232
原创 Http请求类型GET, POST, PUT
用于提交请求,可以更新或者创建资源,是非幂等的,举个例子:在用户注册功能上,每次提交都是创建一个用户账号,这个时候就用POST。目的在于提交数据并用于服务器端的存储,而不允许用户过多的更改相应数据。用于向指定URL传送更新资源,是幂等的。每次请求都只是覆盖原先的值,当操作没有达到预期的目标时,我们可以不停的重试,而不会对资源产生副作用。跟GET功能类似,但是报文中不返回文件主体(只返回到head line)。用于检查文件,而不是真的获取文件内容。
2023-10-07 16:12:09
258
原创 Hive实战-表创建
ORC的全称是(Optimized Row Columnar),ORC文件格式是一种Hadoop生态圈中的列式存储格式。通过实测,储存空间被压缩为默认的1/3。对比默认数据储存格式。
2023-09-27 10:34:42
916
原创 Java中使用Thrift
需要注意的是,transport 客户端要和服务端对应,比如如果要对 NIO 模型的服务端进行调研,transport 就必须使用 TFramedTransport或TFastFramedTransport。业务代码中只需要注入 SimpleService.Iface,并直接调用接口方法,而完全不需要关注内部逻辑实现。通过 thrift compiler 生成 java 代码。client端可以直接调用接口,二不用关心具体的实现类。之后将相应的 Iface 注册到 IOC 容器中即可。
2023-07-19 15:01:39
1829
原创 O/R Mapping 对象关系映射
ORM(Object-Relational Mapping)是一种将对象模型和关系型数据库之间的映射关系进行自动化转换的技术。ORM 的目标是将对象模型和关系型数据库之间的转换过程自动化,使开发人员可以使用面向对象的方式来操作数据库,从而提高开发效率和代码质量。对象和关系之间的映射关系定义。数据库操作的自动化,包括 CRUD 操作、事务管理等。
2023-07-17 20:31:04
557
原创 Spring Actuator 监控管理
Spring Actuator 是 Spring Boot 提供的一个功能强大的监控和管理端点。它提供了一系列的 HTTP 端点,可以用来监控应用程序的运行状态、健康状况、性能指标等信息。这些端点可以通过 HTTP 或 JMX 访问。但是因为安全因素,所以需要另外设置才能打开這些 endpoint。引入依赖后,SpringBoot 在运行时就會自动开启。这两个endpoint。
2023-07-17 15:14:54
742
原创 Java虚拟机(JVM)
类模板对象,其实就是 Java 类在 JVM 内存中的一个快照,JVM 将从字节码文件中解析出的常量池、类字段、类方法等信息存储到模板中,这样 JVM 在运行期便能通过类模板而获取 Java 类中的任意信息,能够对 Java 类的成员变量进行遍历,也能进行 Java 方法的调用。初始化(Initialization):在初始化阶段,JVM会执行类的初始化代码,包括静态变量的赋值和静态代码块的执行。类的初始化是在首次使用该类时进行的,它确保类的静态资源被正确初始化,并且只会执行一次。
2023-07-12 15:04:34
331
原创 解释执行和编译执行
C, C++, Java(Java是一种特殊的编译执行语言,它将源代码编译为字节码文件,然后在Java虚拟机上解释执行字节码)
2023-07-10 18:59:42
729
原创 Java Spring多线程
对于 Future.get()方法返回的结果,一个重要的事情是,只有提交的任务实现了java.util.concurrent.Callable接口时才返回 Future。如果所有的线程都在忙于执行任务并且又有新的任务到来了,这个线程池将创建一个新的线程并将其提交到 Executor。此方法用于取消已提交任务的执行。如果任务完成,结果将立即返回给调用者,否则调用者将被阻塞,直到 Executor 完成此操作的执行并计算出结果。但是,如果管理得不合理,或者任务不是很短的,则线程池将包含大量的活动线程。
2023-06-30 11:05:58
1381
原创 Aviator-Java轻量级高性能Java表达式求值
在上述代码中,首先定义表达式字符串,然后使用AviatorEvaluator的compile()方法编译表达式,将表达式编译成可执行的对象。接着,准备参数并执行表达式,最后输出结果。AviatorScript 文档 https://www.yuque.com/boyan-avfmj/aviatorscript/ashevw。Aviator是一款Java语言编写的轻量级高性能Java表达式求值库,支持java基本类型、字符串、日期、集合、数组等类型的表达式求值运算。
2023-04-27 11:23:04
598
原创 Spring中的设计模式及使用示例
设计模式是指在面向对象软件设计中常见的解决特定问题的方法。设计模式不是一段可复制粘贴的代码,而是一种通用解决方案,可以帮助开发者更好地组织代码、提高代码的可复用性、扩展性和可维护性。常见的设计模式包括单例模式、工厂模式、命令模式、观察者模式、责任链模式等等。每个设计模式都有其内部机制,其核心思想在于相似的问题有相似的解法,将这些解法规则化后,通过加以应用和变通,就可以避免重复的代码和架构设计。
2023-04-26 21:43:45
1030
原创 抽象同步队列AbstractQueuedSynchronizer(AQS)简要理解
AQS(AbstractQueuedSynchronizer)是 Java 中实现锁和同步器的基础设施,它是一个抽象类,提供了构建锁和同步器的基本框架,可以用于实现 ReentrantLock、Semaphore、CountDownLatch 等同步器。A Q S定义了一套多线程访问共享资源的同步模板,解决了实现同步器时涉及的大量细节问题,能够极大地减少实现工作。
2023-04-19 16:13:05
866
原创 Java基本类型和包装类型int和Integer
该错误提示表明你在处理一个Optional类型的参数时,传入的参数中包含一个名为hasRef的int类型参数,但是无法将它转换为一个null值,因为该参数被声明为基本数据类型int。基本数据类型是无法赋值为null的,因此将一个Optional的参数传递给一个接收int类型参数的方法,如果传递的参数值为null或者Optional未被设置值,则会导致此类型的错误。总结来说,基本类型用于表示普通的数据类型,快速处理数字。在这种情况下,可以使用Optional类型的参数来代替Optional类型的参数。
2023-04-17 17:26:54
448
原创 Java和Spring常用注解汇总
在Spring框架中,@Component和@Service都是用来将一个Java类标记为Spring容器中的一个组件。不过,在实际开发中,@Service通常用于标记业务层的Bean,而@Component则更为通用,可以用于标记任意层的Bean。具体而言,@Component表示通用的组件,可以用在任何层次。它是一个比较抽象的概念,可以用于标记任何需要被Spring容器管理的组件类。而@Service则表示服务层组件,用于标记服务层(业务层)的Bean。
2023-04-13 11:50:14
900
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人
RSS订阅