日常故障排查 - Java程序故障排查
Java程序故障
无论对于任何的故障而言,恢复可用性都是首要目标。但作为一个技术匠人,不能让同一个问题导致多次故障,因此故障的根因剖析以及解决也是很重要的。但是故障根因剖析是需要现场数据来进行分析,因此在故障恢复之前要尽量保护好现场的数据,为之后的根因剖析提供足够的数据支撑。
CPU高
在发现某些实例CPU高时,首先要定位的是哪些进程耗费的CPU高,其次是判断这些进程的执行过程。如果只知道进程内所有的线程,但不知道各个线程的CPU使用情况,对于排查问题来说其实还是较难的。因为你不知道CPU是集中在单个线程上还是被某几个线程所占用,只有知道谁是CPU大户才能针对特定线程中执行的任务进行优化,因此定位谁是CPU大户越精准越好。在排查的手段上大概有3中方式:
- top命令+jstack快照
show-busy-java-threads
工具(依赖top命令)- arthas工具
定位CPU大户
可以通过top
命令获取系统内所有进程的CPU使用状况。再使用top -Hp <PID>
命令获取进程内所有的子进程或线程的CPU使用情况。
通常可以在容器内部放一个工具 show-busy-java-threads 来快速获取JVM内部各个线程使用CPU的情况,其内部原理与top命令的统计是一致的。
如果java实例中不存在或无法执行top命令,则可以使用arthas
工具进行统计,其统计原理参见arthas统计线程CPU工作原理在线文档。但是使用arthas对线上的实例会带来一定的开销,而且某些情况arthas不一定能连上你的应用程序,因此在优先级上可以优先使用 show-busy-java-threads
工具完成快照分析。
分析高CPU进程
确定高CPU的进程是哪个应用程序或服务,并了解该进程的功能和用途。根据情况可能需要记录进程ID(PID)以便进一步分析。
top
命令是操作系统自带的工具,并不具备执行线程快照的能力,因此需要使用JVM自带的诊断工具 jstack
获取线程执行快照。
show-busy-java-threads
工具是一个封装好的java线程CPU高排查工具,它可以一键快速获取到线程CPU大户以及JVM线程快照并持久化到文件,
在获取到JVM线程快照之后可以通过IBM自研的 jca369.jar
工具来分析。在CPU高的场景中可以直接找CPU大户线程(注意进制转换)查看该进程的线程栈,从而在制定后续的优化思路。
线程快照分析
线程快照是实例在运行期间各个线程的栈运行状况。通过线程快照可以快速查到JVM内任意线程的运行状态及其他信息。
比较常用的快照分析工具是 IBM 提供的 jca
工具,通过该工具可以快速统计各个状态的线程。
线程快照下的运行状态主要分为:
- DeadLock:死锁。多个线程调用间,进入相互资源占用,导致一直等待无法释放的情况
- Runable:可运行或执行中的线程
- Blocked:阻塞。线程执行过程中,所需锁资源被其他线程持有
- Waiting on condition:条件等待。线程等待其他信号。与Obejct.wait()相比,Obejct.wait()是一种更具体的方式。
- Object.wait():对象等待。调用了Object.wait()方法是线程进入等待状态。
- Waiting on monitor:等待监控器检查资源
- Suspended:暂停
- Parked:停止
对于线程快照最重要的是要关注:
- 是否存在DeadLock线程
- 是否存在Blocked线程,该状态的线程数是否正常。通常高并发的接口不允许存在该状态的线程,必须通过某些设计将锁资源退化。
- 处于资源等待的线程数,是否大量集中等待同一资源,如果是则需要考虑是否优化该资源。
- 可运行状态的线程数,正常情况下数量不应该太多。如果该线程过多而CPU数不足就会频繁切换CPU上下文造成资源的浪费。
- 总的线程数是否过多,对于某些任务可以使用线程池,避免频繁开辟新的线程。毕竟单个线程的开辟需要配置2M的栈内存。
资源池化技术调优
什么是资源池化?为什么使用资源池化技术?
程序在运行过程中可能需要创建某些资源用于完成特定的功能,而这些资源的频繁创建或销毁会消耗CPU或内存资源。为提高程序的性能,可以在程序提前创建好这类资源,在使用的时候直接使用,使用完成之后放回原位,从而避免频繁的创建于销毁,而这种技术就叫做池化技术。
常见的资源池有:线程池、内存缓冲池、HTTP连接池、Redis连接池、数据库连接池等。
资源池的常见参数
- 初始化数:程序在创建资源池的时候,资源的初始化大小数目。
- 核心数:资源池中资源的核心数量,一般资源池中的资源会持续保持在这个数量,即便资源处于空闲状态也不会回收。
- 最大数:资源池中资源的最大数量。
- 空闲数:资源池中资源的最大空闲数量,一般当池内资源有超过空闲时间时会回收空闲的资源。
- 最大空闲时间:用于计算资源处于空闲状态的时长,超过这个阈值就可能会被回收。
- 存活时间:资源的存活时间,为防止内存泄漏,有些资源的存活时间超过该阈值时资源就会被销毁重建。
线程池基本原理
相比于其他资源池的参数,线程池中通常会有 任务队列 的概念。任务队列是用来存放任务的一个队列,通常来说会存在两个重要的参数:
- 容量:指存放任务的最大数
- 拒绝策略:队列满时,再次提交任务到队列的策略。常见的策略是:直接丢弃(Discard)、丢弃旧任务(DiscardOld)、调用者执行(CallerRun)、抛出异常(Abort)。
资源池化参数配置理论
对于资源池化参数配置而言,最有意义的是资源数的配置。通常来说是核心数以及最大数。核心数意味着程序在任意时间下已创建好的资源数量,而最大数则表示程序在任意的情况下可以获取的最大资源数。这两个数的配置太小容易导致程序无法获取到资源或获取资源慢而影响到程序的吞吐量和延迟。太大则可能会有大量资源处于闲置状态,浪费资源。
资源数的配置应当结合业务的吞吐量以及资源使用时长来充分考虑。如:
- 核心数的配置:应当考虑业务在长期稳定时的平均吞吐量以及单个资源的平均延迟考虑。
- 核心数的配置:应当考虑业务在高峰期的最大吞吐量以及单个资源的平均延迟考虑。然后在向上扩大20-30%左右。
而在某些场景下,由于资源的创建可能会消耗一定的时间,资源来不及创建。这时候一个队列就可以充当缓冲区,存储资源请求的同时并创建资源,然后再从队列中获取资源进行处理。但是此时仍然要考虑资源获取的等待时长阈值,否则程序的延迟可能会被无限拉高。
另一个需要注意的点是某些资源池在长期运行过程中,可能会导致某些资源无法释放或被单方面销毁。因此要注意资源的存活时长,当使用资源遇到非预期错误时就需要丢弃该资源并重新创建。常见的有:数据库连接池(Durid和Hikari)
资源等待的原因分析
当服务不正常时,我们可以通过线程快照获取到线程的执行情况。某些情况下可能会发现大量的线程处于等待某些资源的获取,从而导致服务的异常。就针对此情况而言通常从三个方面进行分析:
- 资源的创建是否存在异常:比如数据库故障时无法创建连接;网络异常时创建连接的耗时大大增加。
- 使用资源的吞吐量是否异常:高峰期流量激增,导致请求资源的数量在短时间内超过资源池的核心数(来不及扩容)甚至最大数。
- 单个资源使用的平均延时是否异常:比如数据库的sql执行耗时突然变大,导致资源一直被占用无法被其他请求获取。
案例:数据库连接池连接对象不足及优化
数据库连接资源是一种宝贵且有限的资源,连接池的配置无论如何进行配置其实都会出现不足或等待的情况。那么在配置连接数的时候就不应该随意改大或改小,也不应该发现在实例在等待数据库连接时就认为是数据库连接不对。我们应该考虑的是单个实例每秒负责执行sql的吞吐量去配置。只要连接池的对象能满足这个吞吐量就足矣,剩下的问题与连接池配置无关,即便是通过线程快照发现线程卡在获取连接的位置也不属于连接池配置的问题。
配置连接池要考虑实例执行 sql 的吞吐量。比如:单个实例通过长期的观察发现每秒平均执行200次,单次执行平均耗时100毫秒,那么在配置核心线程数的时候就应该是(200*100/1000)20个。而最大的连接数也应该按照高峰期的sql吞吐量去配置,为应对突发性流量可以酌情上升20%-30%。
连接池的配置优化不是一次性工作,而是一种持续性工作。因为sql的执行耗时是随着服务运行而变化的(通常是变慢)。另外在业务的发展或用户体量的增大下,对单个实例的并发数可能也会变大。因此,要定期关注单个服务实例的sql执行情况以及执行吞吐量,保证连接池的合理、科学配置。
GC问题
GC原理简介
Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。内存区域的唯一目的就是存放对象实例,“几乎”所有的对象实例都分配在堆中(除了栈上分配、标量替换情况)。Java堆是完全自动化管理的,通过垃圾回收机制,垃圾对象会被自动清理,而不需要显示地释放。
堆内存采用了分代结构,包括新生代和老年代。新老年代的比例可以通过 XX:NewRatio
来进行调整。新生代又分为:Eden区,From Survivor区(简称S0),To Survivor区(简称S1区),三者的默认比例为8:1:1,可以通过参数 -XX:SurvivorRatio
的值来进行调整。
堆内存之所以采用分代结构,是考虑到绝大部分对象都是短生命周期的,这样不同生命周期的对象可放在不同的区域中,然后针对新生代和老年代采用不同的垃圾回收算法,从而使得 GC 效率最高。一个对象在Java内存中的分配过程如下:
其中对象的阈值可以通过参数 -XX:PretenureSizeThreshold
完成设置,而晋升年龄可以通过参数 -XX:MaxTenuringThreshold
完成调整。Java进程的GC情况可以通过 jstat -gc <PID> 1000 10
命令获取到,每秒钟打印一次,共10次。
YGC触发时机
大多数情况下,对象直接在年轻代中的 Eden 区进行分配,如果 Eden 区域没有足够的空间,那么就会触发 YGC(Minor GC),YGC 处理的区域只有新生代。因为大部分对象在短时间内都是可收回掉的,因此 YGC 后只有极少数的对象能存活下来,而被移动到 S0 区(采用的是复制算法)。
当触发下一次YGC时,会将 Eden 区和 S0 区的存活对象移动到 S1 区,同时清空 Eden区和 S0 区。当再次触发 YGC 时,这时候处理的区域就变成了 Eden 区和 S1 区(即 S0 和 S1 进行角色交换)。每经过一次 YGC,存活对象的年龄就会加1。
OldGC触发时机
- 老年代空间不足:当晋升到老年代的对象无法放入到老年代空间时,就会触发FGC(Major GC),FGC 处理的区域同时包括新生代和老年代。
- 老年代空间使用率超过阈值:老年代的内存使用率达到了一定阈值(可通过参数调整),直接触发FGC。
- 空间分配担保:在YGC之前,会先检查老年代最大可用的连续空间是否大于新生代所有对象的总空间。如果小于,说明YGC是不安全的,则会查看参数
HandlePromotionFailure
是否被设置成了允许担保失败,如果不允许则直接触发Full GC;如果允许,那么会进一步检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,如果小于也会触发 Full GC。 - 元空间不足:Metaspace(元空间)在空间不足时会进行扩容,当扩容到了
-XX:MetaspaceSize
参数的指定值时,也会触发FGC。 - 手动GC:System.gc() 或者Runtime.gc() 被显式调用时,触发FGC。
2.4.3. 垃圾回收器
不管YGC还是FGC,都会造成一定程度的程序卡顿(即Stop The World问题:GC线程开始工作,其他工作线程被挂起),即使采用ParNew、CMS或者G1这些更先进的垃圾回收算法,也只是在减少卡顿时间,而并不能完全消除卡顿。
- FGC过于频繁:FGC通常是比较慢的,少则几百毫秒,多则几秒,正常情况FGC每隔几个小时甚至几天才执行一次,对系统的影响还能接受。但是,一旦出现FGC频繁(比如几十分钟就会执行一次),这种肯定是存在问题的,它会导致工作线程频繁被停止,让系统看起来一直有卡顿现象,也会使得程序的整体性能变差。
- YGC耗时过长:一般来说,YGC的总耗时在几十或者上百毫秒是比较正常的,虽然会引起系统卡顿几毫秒或者几十毫秒,这种情况几乎对用户无感知,对程序的影响可以忽略不计。但是如果YGC耗时达到了1秒甚至几秒(都快赶上FGC的耗时了),那卡顿时间就会增大,加上YGC本身比较频繁,就会导致比较多的服务超时问题。
- FGC耗时过长:FGC耗时增加,卡顿时间也会随之增加,尤其对于高并发服务,可能导致FGC期间比较多的超时问题,可用性降低,这种也需要关注。
- YGC过于频繁:即使YGC不会引起服务超时,但是YGC过于频繁也会降低服务的整体性能,对于高并发服务也是需要关注的。
其中,「FGC过于频繁」和「YGC耗时过长」,这两种情况属于比较典型的GC问题,大概率会对程序的服务质量产生影响。剩余两种情况的严重程度低一些,但是对于高并发或者高可用的程序也需要关注。
GC排查实践
清楚从程序角度,有哪些原因导致FGC?
- 大对象:系统一次性加载了过多数据到内存中(比如SQL查询未做分页、调用接口返回大量数据),导致大对象进入了老年代。
- 内存泄漏:频繁创建了大量对象,但是无法被回收(比如IO对象使用完后未调用close方法释放资源、ThreadLocal使用后未进行remove),先引发FGC,最后导致OOM。
- 程序频繁生成一些长生命周期的对象,当这些对象的存活年龄超过分代年龄时便会进入老年代,最后引发FGC。
- 程序BUG导致动态生成了很多新类,使得 Metaspace 不断被占用,先引发FGC,最后导致OOM。
- 代码中显式调用了 gc 方法,包括自己的代码甚至框架中的代码。(这情况少见)
- JVM参数设置问题:包括总内存大小、新生代和老年代的大小、Eden区和S区的大小、元空间大小、垃圾回收算法等等
GC排查工具
- 应用监控系统:全方位监控JVM的各项指标
- JDK自带工具:包括jmap、jstat等常用命令。
jstat -gc <PID> 1000 10
- 堆内存分析工具:MAT、JProfile
排查指南
- 通过监控分析GC问题出现的时间点与业务的某些特点场景是否有关。
- 了解JVM的参数设置,包括:堆空间各个区域的大小设置,新生代和老年代分别采用了哪些垃圾收集器,然后分析JVM参数设置是否合理。
- 通过jstat命令实时观察堆内存的使用状况以及GC的效果,主要确定是否存在大对象(Eden区是否突然变大)。
- 针对大对象或者长生命周期对象导致的FGC,可通过 jmap -histo 命令并结合dump堆内存文件作进一步分析,需要先定位到可疑对象。使用堆内存快照时快速定位可疑对象的方法是:主要关注
biggest object
。 - 通过可疑对象定位到具体代码再次分析,这时候要结合GC原理和JVM参数设置,弄清楚可疑对象是否满足了进入到老年代的条件才能下结论。
- 确认是否出现在近期有进行升级,包括底层框架是否有升级,是否升级后引入的bug。
YGC排查指南
YGC时间较长的主要原因为:
- 对存活对象标注时间过长
比如重载了Object类的Finalize方法,导致标注FinalReference耗时过长;或者String.intern方法使用不当,导致YGC扫描StringTable时间过长。可以通过 -XX:+PrintReferenceGC
参数查看不同类型的 reference 处理耗时。
- 存活对象积累过多
比如本地缓存使用不当,积累了太多存活对象;或者锁竞争严重导致线程阻塞,或者已经生成了大量的对象,但是由于某些业务处理耗时,导致局部变量的生命周期变长。这些对象可能都比较小,但是因为数量较多,不容易在堆内存快照中被发现,因此需要特别注意排查。
GC调优过程
- 首先明确GC问题是否由程序问题导致
- 制定GC调优的目的(降低GC次数、GC总耗时还是吞吐量优先)
- JVM参数调整:包括GC选择器、堆内存大小、新生代老年代比例调整、大对象阈值
- 效果观测:持续关注在调整JVM参数后的GC表现
GC的调优通常都是需要多次调整参数,对比GC的效果。对GC的效果不能追求极致,只能说在某一个预期之内即可。
服务治理
远程过程调用 RPC
在微服务大行其道的背景下,服务与服务之间的调用变得越来越复杂且难以治理。一次请求可能要经过一条很长的链路,跨多个服务调用后才能返回结果。服务与服务之间的调用也被称之为远程过程调用,简称RPC。RPC是一个定义,而常见的gRPC、FeignClient、Double则是实现。
超时、重试、熔断、降级、限流
- 超时:是为了确保服务调用方能够在规定的时间内未收到服务提供方的响应时采取其他措施,避免长时间的等待或阻塞。
- 重试:服务提供方很有可能是因为某个瞬间的网络抖动或者机器高负载引起的超时,如果直接放弃某些场景会造成业务损失。所以重试是服务调用方在超时之后采取的一种挽救策略。
- 熔断:服务调用方认为服务提供方已经出现故障无法响应而做出的快速失败,避免自身长时间的等待或阻塞的同时也降低服务提供方的压力。如:获取不到缓存数据则直接响应数据不存在。常见的熔断的实现方案在Java中大概就是是:hystrix。
- 降级:降级与熔断类似,但不同之处在与服务提供方被熔断之后而进行的一种补偿策略。如:获取不到缓存数据则直接从数据库查询并响应。降级需要与熔断结合使用,在服务提供方被熔断之后设置一个回调函数。
- 限流:是为了避免服务调用方在短期内对服务提供方进行大量的调用从而导致服务提供方负载过大而崩溃,是服务提供方的一种自我保护手段。常见的限流算法有:令牌桶。实现方案:sentinel
超时与重试副作用
在引入超时与重试的时候虽然能解决某些问题,但是也可能带来副作用:
- 重复请求:某些情况下服务提供方已接收到请求并在执行中,但未在超时时间(超时时间较短或负载较高)内完成。因此服务调用方发起重试,服务提供方因此获取到重复的请求,因此可能会带来脏数据问题,因此某些接口必须要考虑幂等性。
- 加大服务提供方的负载:如果服务提供方不是因为临时性的问题导致的超时,而是确实存在性能问题,这样重试多次也是无法成功的,反而可能会继续加大服务提供方的负载压力。
- 重试风暴:如果一个链路经历多个服务并且存在重试次数,如:A(3)->B(3)->C(3)->D。如果D服务出现超时,上游服务都将发起重试,则 A 会重试 B 3次, B 会重试 C 9次, C 会重试 D 27次。
因此熔断机制是必要的,可以避免无休止的无意义调用。
如何设置合理的超时与重试次数
RPC 接口的超时设置看似简单,实际上有很大学问。不仅涉及到很多技术层面的问题(比如接口幂等、服务降级和熔断、性能评估和优化),同时还需要从业务角度评估必要性。
- 设置调用方的超时时间之前,先了解清楚依赖服务的 TP99 响应时间是多少(如果依赖服务性能波动大,也可以看 TP95),调用方的超时时间可以在此基础上加50%。
- 如果 RPC 框架支持多粒度的超时设置,则:全局超时时间应该要略大于接口级别最长的耗时时间,每个接口的超时时间应该要略大于方法级别最长的耗时时间,每个方法的超时时间应该要略大于实际的方法执行时间。
- 区分是可重试服务还是不可重试服务,如果接口没实现幂等则不允许设置重试次数。注意:读接口是天然幂等的,写接口则可以使用请求ID或业务ID进行防避免引入脏数据。
- RPC框架最好实现服务提供方的超时以及重试设置,这样可以避免调用方不设置的情况下也存在超时设置,减少隐患。
- 重试次数越大,服务的可用性越高,业务损失通常也会越低,但性能隐患会更大,需要总和考虑(一般不会超过3次)。
- 从业务角度看,请求失败后业务损失不大,通常可以通过人工实现重试,可以有效降低接口的复杂度,有利于后期维护。
- 如果是核心服务或调用量较大的服务,则必须考虑在服务超时的情况下的熔断和降级策略。(比如超过10%的请求出错,则停止重试机制直接熔断,改成调用其他服务、异步MQ机制、或者使用调用方的缓存数据)
服务间循环依赖
服务与服务之间的RPC调用可以避免代码冗余的问题,但是在后期开发下服务之间的调用会变得越来越复杂,甚至会让某个业务域的架构负责人对其服务之间的调用也失去控制。比如最常见的服务之间的循环依赖。
循环依赖问题
如:服务A调用服务B,服务B某些接口依赖服务A。B因为被其他服务调用导致负载较高,因此A调用B时延迟相对较高,因此A中的某些资源可能无法被快速回收或释放(比如:业务线程、业务对象),因此A的负载也会变高。此时B服务的某些接口会调用A,发现A的延迟变高,因此B的某些资源可能无法被快速回收或释放(比如:业务线程、业务对象)造成B持续高负载。最终A、B两个服务形成恶性循环最终导致A、B服务都不可用。
解决循环依赖
循环依赖在系统正常运行的情况下不会形成恶性循环,但是循环中的一方出现问题之后可能就会导致循环中的各方都出现问题,严重降低服务的高可用能力。
解决循环依赖的最有效的方法是服务的合理拆分,打破循环依赖,让各个服务之间的调用形成一个有向无环图。如果短期内无法对服务进行有效的拆分,在应该在循环依赖的接口调用时设置合理的超时时长以及重试次数(这两个值应当尽量小),并且要设置熔断策略,防止加大另一方的负载压力。
相关文章:
日常故障排查 - Java程序故障排查
Java程序故障 无论对于任何的故障而言,恢复可用性都是首要目标。但作为一个技术匠人,不能让同一个问题导致多次故障,因此故障的根因剖析以及解决也是很重要的。但是故障根因剖析是需要现场数据来进行分析,因此在故障恢复之前要尽…...
ai数字人分身系统开发源码saas化
#数字人分身系统# #数字人系统源码# #ai数字人123 123# 云罗抖去推数字人分身系统是一款融合了形象克隆、声音克隆、AI数字人分身、AI智能剪辑、智能文案等各种AI技术一体化的短视频营销工具,其核心功能优势主要体现在以下几方面: 真实度高…...
DeepSeek免费部署到WPS或Office
部署到WPS - 通过OfficeAI插件接入: - 准备工作:安装最新版本的WPS Office软件;访问DeepSeek官网,点击右上角的“API开放平台”,登录账号(若无账号需先注册),登录成功后,…...
vue2和vue3插槽slot最通俗易懂的区别理解
在 Vue 的组件通信中,slot(插槽)的编译优化是一个重要的性能提升点。以下是 Vue2 和 Vue3 在 slot 处理上的差异及优化原理,用更直观的方式解释: Vue2 的 Slot 更新机制 想象一个父子组件场景: 父组件&am…...
生成式人工智能:技术革命与应用图景
(这文章有些地方看不懂很正常,因为有太多生词,需要对 计算机/人工智能 研究至深的人才能看懂,遇到不会的地方用浏览器搜索或跳过) 引言 2023年被称我们为"生成式AI元年",以GPT-4、DALL-E 3、Stable Diffusi…...
关于Dest1ny:我的创作纪念日
Dest1ny 因为这是csdn任务,我就稍微“写”了一下! 如果大家真的有什么想聊的或者想一起学习的,欢迎在评论区或者私信中与我讨论! 2025想说的话 我就把我想说的写在前面! 不用对未来焦虑,不要觉得自己走…...
AI学习记录 - 最简单的专家模型 MOE
代码 import torch import torch.nn as nn import torch.nn.functional as F from typing import Tupleclass BasicExpert(nn.Module):# 一个 Expert 可以是一个最简单的, linear 层即可# 也可以是 MLP 层# 也可以是 更复杂的 MLP 层(active function 设…...
【C++内存管理】—— 策略、陷阱及应对之道
欢迎来到ZyyOvO的博客✨,一个关于探索技术的角落,记录学习的点滴📖,分享实用的技巧🛠️,偶尔还有一些奇思妙想💡 本文由ZyyOvO原创✍️,感谢支持❤️!请尊重原创…...
分布式版本控制系统---git
Git:从基础到进阶的全面指南 Git 是一个分布式版本控制系统,广泛应用于软件开发中,用于跟踪文件的更改、支持团队协作以及管理项目代码。通过 Git,开发者可以在本地拥有完整的项目历史记录,进行离线开发,并…...
pg_sql关于时间的函数
1、时间戳和日期之间的相互转换 时间戳转日期(时间戳为数值类型,若为字符型需进行转换) # 保留到秒:2025-10-02 04:46:40 (字符型转换数值型) select to_timestamp(1759351600::bigint)# 保留到日&#x…...
【Kafka】Windows下安装Kafka(全面)
目录 1.前提条件 2.下载 3.安装 4.环境变量配置 5.验证 1.前提条件 参考版本:zookeeper为3.6.4 kafka版本为3.5.1 1.先安装zookeeper: 【Zookeeper】Windows下安装Zookeeper(全面)-CSDN博客https://blog.csdn.net/…...
【Qt】:概述(下载安装、认识 QT Creator)
🌈 个人主页:Zfox_ 🔥 系列专栏:Qt 目录 一:🔥 介绍 🦋 什么是 QT🦋 QT 发展史🦋 Qt版本🦋 QT 优点 一:🔥 搭建Qt开发环境 ǹ…...
Netty源码解析之异步处理(二):盛赞Promise中的集合设计
前言 在阅读Netty源码的过程中,我越来越相信一句话:“Netty的源码非常好,质量极高,是Java中质量最高的开源项目之一”。如果认真研究,会有一种遍地黄金的感觉。 本篇文件我将记录一下鄙人在Promise的实现类DefaultPr…...
Spring Boot 的约定优于配置,你的理解是什么?
“约定优于配置” 是 Spring Boot 极为重要的设计理念,它极大地简化了 Spring 应用的开发流程,下面从多个方面详细解释这一理念: 减少配置复杂性 传统开发的痛点 在传统的 Spring 开发里,配置工作相当繁琐。以配置 Spring MVC …...
图形渲染(一)——Skia、OpenGL、Mesa 和 Vulkan简介
1.Skia —— 2D 图形库 Skia 是一个 2D 图形库,它的作用是为开发者提供一个高层次的绘图接口,方便他们进行 2D 图形渲染(比如绘制文本、形状、图像等)。Skia 本身不直接管理 GPU 或进行底层的渲染工作,而是通过 底层图…...
git使用,注意空格
第一节 安装完成后,找个目录用于存储,打开目录右击选择git bash here 命令1 姓名 回车 git config --global user.name "li" 命令2 邮箱 回车 git config --global user.email "888163.com" 命令3 初始化新仓库,下载克隆 回…...
以用户为中心,汽车 HMI 界面设计的创新之道
在汽车智能化飞速发展的当下,汽车 HMI(人机交互界面)成为连接人与车的关键桥梁。如何打造出优秀的 HMI 界面?答案是以用户为中心,探索创新之道。 用户需求是汽车 HMI 界面设计的指南针。在设计前期,深入调…...
CentOS安装Docker,Ubuntu安装Docker,Docker解决方案
文章目录 CentOS7安装DockerUbuntu修改Docker镜像源docker设置容器自动启动启动时加--restartalways如果已经过运行的项目docker compose设置容器自启动 docker file修改时区docker在容器执行命令简单粗暴的办法安装curl docker compose命令安装docker compose Docker WEB 图形…...
c#中“事件-event”的经典示例与理解
在C#编程语言中,事件(Event)是一个非常重要的概念,它提供了一种松耦合的方式,让对象间能够通知彼此,而无需直接联系。事件的使用可以让我们的代码更加灵活、可扩展且易于维护。 事件可以视作委托的实例&…...
git bash在github的库中上传或更新本地文件
一、将本地文件上传到 GitHub 仓库 1. 创建 GitHub 仓库 如果你还没有在 GitHub 上创建仓库,首先需要创建一个新的仓库: 登录到 GitHub。点击右上角的 按钮,选择 New repository。给你的仓库起个名字,并选择 Public 或 Privat…...
【编程实践】vscode+pyside6环境部署
1 PySide6简介 PySide6是Qt for Python的官方版本,支持Qt6,提供Python访问Qt框架的接口。优点包括官方支持、LGPL许可,便于商业应用,与Qt6同步更新,支持最新特性。缺点是相比PyQt5,社区资源较少。未来发展…...
vue 文件下载(导出)excel的方法
目前有一个到处功能的需求,这是我用过DeepSeek生成的导出(下载)excel的一个方法。 1.excel的文件名是后端生成的,放在了响应头那里。 2.这里也可以自己制定文件名。 3.axios用的是原生的axios,不要用处理过的ÿ…...
服务器延迟给视频网站造成的影响
在数字化时代中,网络视频已经成为人们日常娱乐和获取信息的重要平台,网络视频的流畅性会影响着用户的体验度,那么,当服务器出现延迟会对视频网站造成哪些影响呢?本文就来共同了解一下吧! 当所使用的服务器由…...
django上传文件
1、settings.py配置 # 静态文件配置 STATIC_URL /static/ STATICFILES_DIRS [BASE_DIR /static, ]上传文件 # 定义一个视图函数,该函数接收一个 request 参数 from django.shortcuts import render # 必备引入 import json from django.views.decorators.http i…...
Mysql数据库
一.数据定义语言DDL 一.概述 DDL用于定义和管理数据库的结构 DDL关键字:1.CREATE; 2.ALTER; 3.DROP 二.SQL命名规定和规范 1.标识符命名规则 2.标识符命名规范 三.库管理 1. CREATE DATABASE 数据库名; 2. CREATE DATABASE IF NOT EXISTS 数据库名; 3. CREATE…...
机器学习 - 大数定律、可能近似正确学习理论
一、大数定律: 大数定律是概率论中的一个基本定理,其核心思想是:当独立重复的随机试验次数足够大时,样本的平均值会趋近于该随机变量的期望值。下面从直观和数学两个角度来说明这一概念: 1. 直观理解 重复试验的稳定…...
Kotlin 2.1.0 入门教程(十七)接口
接口 接口可以包含抽象方法的声明,也可以包含方法的实现。 接口与抽象类的不同之处在于,接口无法存储状态。接口可以拥有属性,但这些属性要么必须是抽象的,要么就得提供访问器的实现。 接口使用 interface 关键字来定义&#x…...
USB Flash闪存驱动器安全分析(第一部分)
翻译原文链接:Hacking Some More Secure USB Flash Drives (Part I) | SySS Tech Blog 文章翻译总结:文章对一些具有AES硬件加密的USB闪存驱动器的网络安全分析研究。研究由SySS的IT安全专家Matthias Deeg进行,他在2022年初发现了几个安全漏…...
报名丨Computer useVoice Agent :使用 TEN 搭建你的 Mac Assistant
与 TEN 相聚在「LET’S VISION 2025」大会,欢迎来展位上跟我们交流。这次我们还准备了一场聚焦「computer use」的工作坊,功能新鲜上线,线下首波体验! 📅 TEN 展位:2025年3月1日-2日 TEN workshop&#x…...
常用架构图:业务架构、产品架构、系统架构、数据架构、技术架构、应用架构、功能架构及信息架构
文章目录 引言常见的架构图I 业务架构图-案例模块功能说明1. 用户界面层 (UI)2. 应用服务层3. 数据管理层4. 基础设施层业务流程图示例技术实现II 功能架构图 -案例功能模块说明1. 船舶监控模块2. 报警管理模块3. 应急响应模块4. 通信管理模块5. 数据分析模块数据管理层基础设施…...
微信小程序的制作
制作微信小程序的过程大致可以分为几个步骤:从环境搭建、项目创建,到开发、调试和发布。下面我会为你简要介绍每个步骤。 1. 准备工作 在开始开发微信小程序之前,你需要确保你已经完成了以下几个步骤: 注册微信小程序账号&…...
C# 特性 学习记录
在C#中,特性(Attribute)是一种用于向代码元素(如类、方法、属性等)添加元数据的机制。特性本身不会直接影响代码的执行,但它们可以提供额外的信息,这些信息可以在运行时通过反射(Ref…...
DBeaver clickhouse 时区不对 时间少了8小时
选择DataBase选择Driver Manager选择clickhouse数据库点中之后,选择编辑添加两个全局属性 use_server_time_zone use_time_zone 鼠标移动到User Properties上,右键即可添加一列空白 然后断开重连...
如何测试和验证CVE-2024-1430:Netgear R7000 路由器信息泄露漏洞分析
CVE-2024-1430 是一个影响 Netgear R7000 路由器的安全漏洞,漏洞来源于该路由器 Web 管理界面的信息泄露问题。攻击者通过访问 /currentsetting.htm 文件,可能泄露敏感信息,如 Wi-Fi 密码等。 在测试和验证 CVE-2024-1430 时,您需…...
Express 中间件是什么
在 Express 里,中间件是具备访问请求对象(req)、响应对象(res)以及应用程序请求-响应循环中的下一个中间件函数(一般用next表示)的函数。 一、中间件的定义与调用顺序 在 Express 应用中&…...
【做一个微信小程序】校园地图页面实现
前言 上一个教程我们实现了小程序的一些的功能,有背景渐变色,发布功能有的呢,已支持图片上传功能,表情和投票功能开发中(请期待)。下面是一个更高级的微信小程序实现,包含以下功能:…...
(萌新入门)如何从起步阶段开始学习STM32 —— 0.碎碎念
目录 前言与导论 碎碎念 所以,我到底需要知道哪些东西呢 从一些基础的概念入手 常见的工具和说法 ST公司 MDK5 (Keil5) CubeMX 如何使用MDK5的一些常用功能 MDK5的一些常见的设置 前言与导论 非常感谢2301_77816627-CSDN博客的提问,他非常好奇…...
java nio 原理 非阻塞IO Netty
一、为什么必须去了解NIO 首先你需要之后Netty的主要实现手段就是Nio,很多人一直学不明白Netty,根本原因是 除了日常开发中很难能够实践,很大一部分原因是不熟悉NIO,事实上真正熟悉了NIO和它背后的原理之后,去查看Netty的源码就有…...
【ClickHouse】Ubuntu下离线安装ClickHouse数据库并使用DBeaver连接
目录 0. 安装前准备1 安装ClickHouse1.1 下载安装包1.2 离线安装1.3 配置密码1.4 启动ClickHouse服务 2 DBeaver连接配置2.1 下载ClickHouse驱动2.2 DBeaver配置2.2.1 配置主要参数2.2.2 配置驱动 2.3 常见问题处理2.3.1 修改远程登录配置2.3.2 更新驱动配置 0. 安装前准备 有…...
vue2打包带路径的项目,刷新404问题解决
问题描述 Vue 2 项目打包时设置了 publicPath: /web/,并通过 Nginx 配置访问 http://ip/web 时可以正常加载首页,但刷新页面时出现 404 错误 原nginx的配置 location /web {alias /www/dist; # 静态文件地址try_files $uri $uri/ /index.html;index i…...
【计算机视觉】文本识别
计算机视觉,广义的文本识别是指对输入的图像进行分析处理,识别出图像中的文字信息,这里的图像可以使传统的文档图像,也可以是现实世界中的场景图像。 简介 无论是传统方法还是基于深度深度学习的方法,完整的文本识别…...
Vue和React的区别
组件开发方式: Vue 使用单文件组件(SFC), HTML, JS 和 CSS 在一个文件内实现 <template><div class"my-component"><!-- HTML模板 --></div> </template><script> export default {// JavaScr…...
STM32 是什么?同类产品有哪些
STM32 是什么? STM32 是由意法半导体(STMicroelectronics)推出的基于 ARM Cortex-M 内核 的 32 位微控制器(MCU)系列。它专为高性能、低功耗的嵌入式应用设计,广泛应用于以下领域: 工业控制&am…...
Git学习使用笔记
目录 一、基本介绍 1.1 版本控制 1.2 版本控制软件的基础功能 1.3 多人协作开发/集中式版本控制 1.4 分布式版本控制 二、Git安装 2.1下载git 2.2 使用Github Desktop软件 2.2.1 创建本地仓库 2.2.2 删除本地仓库 2.2.3 仓库文件操作 2.2.4 多人协作 2.2.4.1 分…...
Bash 中的运算方式
目录 概述: 1. (()) 运算符 2. let 命令 3. expr 命令 4. $[] 直接运算 5. bc(计算器,支持浮点数) 6. awk(强大的文本处理工具,也可计算) 概述: Bash 本身只支持整数运算&am…...
NLP Word Embeddings
Word representation One-hot形式 在上一周介绍RNN类模型时,使用了One-hot向量来表示单词的方式。它的缺点是将每个单词视为独立的,算法很难学习到单词之间的关系。 比如下面的例子,即使语言模型已经知道orange juice是常用组合词…...
Unity UI个人总结
个人总结,太简单的直接跳过。 一、缩放模式 1.固定像素大小 就是设置一个100x100的方框,在1920x1080像素下在屏幕中长度占比1/19,在3840x2160,方框在屏幕中长度占比1/38。也就是像素长款不变,在屏幕中占比发生变化 2.…...
开发基础(8):鸿蒙图表开发
mpchart mpchart是一个包含各种类型图表的图表库,主要用于业务数据汇总,例如销售数据走势图,股价走势图等场景中使用,方便开发者快速实现图表UI,mpchart主要包括线形图、柱状图、饼状图、蜡烛图、气泡图、雷达图、瀑布图等自定义图表库。 柱状图 导入import {BarChart, …...
Vue的简单入门 一
声明:本版块根据B站学习,创建的是vue3项目,用的是vue2语法风格,仅供初学者学习。 目录 一、Vue项目的创建 1.已安装15.0或更高版本的Node.js 2.创建项目 二、 简单认识目录结构 三、模块语法中的指令 1.v-html 1.文本插值…...
vs2022支持.netframework4.0
下载nuget包 .netframework4.0 解压nuget 复制到C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework 参考 https://www.cnblogs.com/bdqczhl/p/18670152 https://blog.csdn.net/xiaomeng1998_/article/details/135979884...