Java web应用性能分析之【java进程问题分析定位】

Java web应用性能分析之【java进程问题分析概叙】-CSDN博客

Java web应用性能分析之【java进程问题分析工具】-CSDN博客

Java web应用性能分析之【jvisualvm远程连接云服务器】-CSDN博客

        由于篇幅限制、前面三篇讲了准备工作和分析小结,这里将详细操作java进程问题分析定位。

1.java进程常见问题汇总


        Java Web应用中的java进程问题从系统表象来看归结起来总共有四方面:CPU、内存、磁盘、网络。具体包括:

        CPU问题:CPU 使用率峰值突然飚高问题(cpu占用率、ws上下文切换频繁、load avg飙高),死循环或者循环嵌套,锁等待问题、死锁问题,GC问题、线程池大小配置是否合理等等。

        内存问题:物理内存不足、溢出 (泄露)、OOM(堆、栈、元空间、线程)、找jvm中的大对象、jvm配置是否合理(堆大小是否合适、元空间大小是否合适、NewRatio和SurvivorRatio是否合适、线程栈大小是否合适、如何选择GC收集器、等等jvm调优问题)

        磁盘问题:磁盘空间不足或者满了、log4j日志写磁盘慢阻塞业务请求、物理磁盘性能差、操作系统的io调度算法(elevator=deadline,这个算法试图把每次请求的延迟降至最低。该算法重排了请求的顺序来提高性能);

        网络问题:网络流量异常、网络攻击、服务器带宽不足、网络io(零拷贝,dubbo支持零拷贝)、web服务器io模型(Nginx、Tomcat等)。

        业务问题:业务高并发带来的PV 量过高、服务调用耗时异常、线程死锁、多线程并发问题、频繁进行 Full GC等问题;业务逻辑问题(具体场景具体分析)、如何定位某个方法耗时很久,如何统计业务逻辑内每个环节(方法)的耗时。

        备注:上面把问题分成5个方面,其实这些问题之间都是相互关联的,在我们分析问题时不应该将其独立对待,简单的归类分析。比如jvm的堆内存不足,会导致频繁的fullGC,此时的服务器表象可能是cpu飙高,甚至大于100%;磁盘io性能不足,阻塞cpu,也可能导致cpu繁忙。

2.问题分析定位一般操作步骤

        一般我们的问题都来自监控的报警,cpu、内存、磁盘、业务服务接口耗时等等超过了监控平台的阈值,就会有短信、邮件发给相关责任人。当然这个时候一般就比较严重了,因为已经是生产问题,可能涉及到你的kpi和白花花的银子。而且在生产环境排查问题,比较麻烦,很有可能你连登录服务器的权限都没有。所以尽量在开发环境、测试环境,提前发现和解决问题。

        在开发环境、测试环境一般没有生产环境的数据,尽量模拟产生大量数据的生产环境。还有一个就是通过ab等压测工具模拟高并发,尽量还原生产环境的现场。针对环境,一般分成离线分析和在线分析。

压测工具参考:Java web应用性能分析之【压测工具ab】-CSDN博客

Java web应用性能分析之【高并发之缓存-多级缓存】-CSDN博客

Java web应用性能分析之【高并发之限流】_web服务限流-CSDN博客

Java web应用性能分析之【高并发之降级】-CSDN博客

        2.1离线分析

1.查看日志文件:检查java应用程序的日志文件,通常位于/logs目录下,或者由日志配置文件指定。一般可以通过启动springboot进程的bash脚本来查看具体日志文件路径。

2.分析堆栈跟踪:如果应用程序崩溃,在日志文件中查找异常堆栈跟踪。如oom后的内存dump文件,在java进程启动时添加参数,确保发生oom时保存现场  -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=log/ 

分析内存使用情况:使用诸如JVisualVM, JProfiler, 或MAT (Memory Analyzer Tool) 等工具分析内存使用情况和潜在的内存泄漏。

分析线程活动:使用线程分析工具(如JVisualVM, YourKit, 或MAT)来查看线程的状态和死锁。

3.分析JVM参数:如果可用,分析启动Spring Boot应用程序时使用的JVM参数。一般启动springboot进程的bash脚本,在bash脚本中可以查看jvm参数设置,如果时查询线上的  则可以用ps -ef|grep java  或者 jinfo pid来查看。

4.分析系统属性和环境变量:查看系统属性和环境变量,这些可能影响应用程序的行为。

5.分析配置文件:检查application.properties或application.yml配置文件,查看是否有不正确的配置。

6.分析GC日志:如果有GC日志,分析垃圾收集器的行为和内存回收情况。要求jvm启动参数配置-XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+PrintHeapAtGC -XX:+PrintCommandLineFlags -Xloggc:log/gc.log   将gc日志单独保存出来。分析jvm的堆栈元空间大小是否合适?结合分析堆栈跟踪文件,定位oom、死锁触发的点,再去调整代码。

7.历史监控:如发生问题时间段的zabbix、prometheus等等,通过监控分析这段时间的cpu、内存、io、网络、qps统计、耗时统计。

8.分析应用的外部依赖:如数据库、Redis缓存、消息队列KFK、网络服务等等,确认是否有问题。

        综合上述情况,再分析定位问题。

        2.2 在线分析

        再次申明“在线分析”这个只针对开发环境和测试环境,如果是生产环境,出了问题概不负责。在线分析一般步骤如下:通过top命令找出资源占用高的java进程,然后通过top -Hp或者pidstat -p 定位高消耗的线程,再通过jstack或者jmap 导出堆栈信息,最后用分析工具(如JVisualVM, YourKit, 或MAT)来分析线程的状态和死锁,以及分析内存使用情况和潜在的内存泄漏,更加这些问题触发点,再去调整代码,然后再接着更新代码验证问题是否解决。

        当然,在已知要分析功能服务的情况下,可以直接用JVisualVM远程连接该进程,查看具体的资源消耗情况,这个图形工具更直观。

        JVisualVM参考:Java web应用性能分析之【jvisualvm远程连接云服务器】-CSDN博客

        ab压测,模拟并发环境,参考:Java web应用性能分析之【压测工具ab】-CSDN博客

        

     步骤1.找出耗时线程 ,18281,转成16进制  printf “%x\n”  18281

 pidstat -p 18227 -t  1   10  (和top比,pidstat是留痕的,每次打印都是能看到,top是实时刷新;但是top可以选择按照cpu或者内存来排序)

步骤2.定位线程在干嘛 jstack 18227 |grep '4769'  -C5 --color 

步骤3.查看代码“at com.zxx.study.web.task.FullCPUTask.run(FullCPUTask.java:15)”,找到触发点,分析原因,再进行修正,而且更新代码,验证问题是否修复。

2.用JVisualVM来监控分析,就简单多了,可以很清晰看到cpu和内存消耗情况

抽样器中很直接就能找到占用cpu时间较多的线程

很容易找到触发点,和上面的jstack找的位置一样“at com.zxx.study.web.task.FullCPUTask.run(FullCPUTask.java:15)”,找到触发点,分析原因,再进行修正,而且更新代码,验证问题是否修复。

3.用arthas来分析定位,稍后补充。

2.CPU问题

        CPU问题:CPU 使用率峰值突然飚高问题(cpu占用率、ws上下文切换频繁、load avg飙高),死循环或者循环嵌套,锁等待问题、死锁问题,GC问题、线程池大小配置是否合理等等。

        cpu飙升带来的影响

响应时间延长:CPU使用率过高会导致进程无法及时处理请求,从而导致Web应用的响应时间延长,影响用户体验。
性能下降:高CPU使用率会消耗系统资源,导致其他进程或服务的性能下降,可能引起整体系统的不稳定性。
可用性降低:CPU使用率过高持续一段时间,可能导致Web应用崩溃或无法正常运行,从而降低系统可用性。

        java进程导致cpu飙升的原因和解决方法:

Java进程导致CPU使用率飙升的原因可能有多种,以下是一些常见原因及其解决方法:


大量并发请求:大量并发请求时,可能会导致CPU使用率升高,特别是在处理复杂的请求或计算密集型任务时。
解决方法:架构优化、引入负载均衡


无限循环或长时间执行的代码:检查是否有死循环或者复杂的算法导致CPU长时间被占用。
解决方法:优化代码逻辑,确保循环有明确的退出条件。


过多的线程竞争:如果有多个线程竞争同一资源或者执行同步块,可能会导致CPU使用率升高。
解决方法:减少线程数量,优化同步策略,使用更高效的并发工具。

线程死锁:竞争资源:多个线程同时竞争有限的资源,当资源分配和释放不当时,可能会导致死锁;循环等待:线程之间相互等待对方释放资源,形成循环等待的局面。
解决方法:重新定义竞争的资源,调整循环等待。


内存泄漏:如果Java进程中存在内存泄漏,可能会导致GC频繁运行,消耗大量CPU资源。
解决方法:使用内存分析工具检查并修复内存泄漏问题。


JIT (Just-In-Time) 编译问题:Java虚拟机的JIT编译器可能会花费更多时间优化代码。
解决方法:监控应用运行情况,如果发现编译耗时过长,可能需要优化代码结构。

gc问题:频繁gc导致cpu飙升
解决方法:调整垃圾收集器的参数,或者使用不同的垃圾收集器;jvm堆设置不合理,调整堆大小设置;大对象导致频繁gc,可以分批加载数据,控制进入jvm的数据量(如mybatis中的fetchSize ;以及 jdbc:mysql://localhost:3306/mydb?cursorScrollable=true&defaultFetchSize=100
)。


外部库或依赖引起的问题:某些外部库可能在后台执行大量的计算或等待资源,导致CPU使用率升高。
解决方法:检查依赖库的文档,确保它们被正确管理和使用。

系统调用或IO操作:过多的系统调用或IO操作可能会导致CPU等待硬件资源,从而使CPU使用率升高。
解决方法:优化IO操作,减少不必要的系统调用。

外部因素:如果Java进程依赖于外部服务或资源,并且这些服务出现瓶颈或不稳定,可能会导致CPU使用率上升。
解决方法:监控和确保外部依赖的稳定性和性能。

在实际处理时,可以使用如下工具和技术来诊断和解决问题:
使用top或htop命令查看哪个Java进程的CPU使用率高。
使用jstack工具获取Java线程的堆栈信息。
使用jstat工具监控JVM的各种运行状态,如垃圾收集信息。
使用Java性能分析工具(如VisualVM, JProfiler, YourKit)进行详细分析。
优化代码逻辑,减少不必要的计算或等待。
升级或更换不够高效的组件和库。
调整系统配置,如分配更多的资源给Java进程。


总之,要解决Java进程导致的CPU使用率高的问题,需要定位具体的原因,并根据原因采取相应的解决措施。


Mybatis的游标大小fetchSize 
@Options(resultSetType = ResultSetType.FORWARD_ONLY, fetchSize = Integer.MIN_VALUE)
@Select("select domain from illegal_domain where icpstatus != #{icpstatus}")
Cursor<IllegalDomain> getDayJobDomain(@Param("icpstatus") Integer icpstatus);
注意:游标是可以前后移动的。如果resultSetType = TYPE_SCROLL_INSENSITIVE ,就是设置游标就可以前后移动。
Mybatis为了保证可以前后移动,Mybatis会把之前查询的数据一直保存在内存中。
所以并不能根本解决OOM,所以我们这里需要设置为@Options(resultSetType = ResultSetType.FORWARD_ONLY)(其实默认就是ResultSetType.FORWARD_ONLY)

3.内存问题

        内存问题:物理内存不足、溢出 (泄露)、OOM(堆、栈、元空间、线程)、找jvm中的大对象、jvm配置是否合理(堆大小是否合适、元空间大小是否合适、NewRatio和SurvivorRatio是否合适、线程栈大小是否合适、如何选择GC收集器、等等jvm调优问题)

        内存飙升分析思路:

1.排查进程占用内存

  • 使用top命令、JVisualVM工具、或者普罗米修斯等工具查看java进程内存占用情况。

2.分析内存使用情况

  • 使用jstat或者JVisualVM工具查看Full GC情况,分析full gc次数是否频繁,确认应用本身是否有问题。

  • 使用jmap、jcmd查看当前应用进程使用内存,分析是否存在内存飙升等问题。(从JDK 7开始提供,jcmd拥有jmap的大部分功能,官方推荐使用jcmd命令替代jmap命令。)

  • JVisualVM导出jvm进行分析。

  • 分析gc日志,确认gc次数和单次耗时,用来判断是否有问题。

jvm调优,稍后补充。

        导致内存飙升的原因和解决方法

原因可能包括:

内存泄漏(Memory Leak):对象不再被使用,但垃圾回收器无法回收,因为还有活跃的引用。

大量对象创建:比如在循环中创建大量的临时对象。

分配了过大的数组或集合:可能超过了JVM堆大小限制。

线程堆栈大小不足:每个线程默认有1MB的堆栈大小,过多线程可能会导致内存增加。

JNI调用:如果使用了Native方法,可能会有内存分配在C/C++层面,而不被JVM管理。

系统虚拟内存不足:系统分配的虚拟内存大小超过了物理内存加交换空间的总和。


解决方法:

使用内存分析工具(如MAT, VisualVM等)找出内存泄漏的位置,并修复代码。

优化代码,减少不必要的对象创建。

监控和调整JVM的堆大小参数,例如 -Xms 和 -Xmx 来限制JVM使用的内存。

大对象跳过年轻代、直接放入老年代。

分析线程使用情况,必要时减少线程数量或增加线程堆栈大小。

重新分配或优化JNI调用,确保正确管理内存。

检查系统资源,增加物理内存或调整交换空间的大小。

具体解决方案取决于实际情况的分析结果。

内存飙升常见原因:
其他应用(Redis、Kafka)占用总内存;
解决:top命令排除。

启动参数内存值设定的过小;
解决:-Xms,-Xmx。

内存中加载的数据量过于庞大(数据缓存、PDF字体缓存、文件传输);
解决:代码走查,观察内存波动。

List、MAP等集合中对对象的引用,使用完后未清空,使得JVM不能回收;
解决:代码走查,观察内存波动。

代码中存在死循环或循环产生过多重复的对象实体;
解决:代码走查。

4.磁盘问题

        磁盘问题:磁盘空间不足或者满了、log4j日志写磁盘慢阻塞业务请求、物理磁盘性能差、操作系统的io调度算法(elevator=deadline,这个算法试图把每次请求的延迟降至最低。该算法重排了请求的顺序来提高性能);

        java进程导致io飙升的原因和解决方法:

Java进程导致IO飙升可能是由以下几个原因造成的:

文件读写不当:可能是因为Java进程在进行大量的读写操作,尤其是在创建和写入临时文件时。

网络操作:Java进程可能在进行大量的网络输入输出,尤其是在进行大量的网络通讯或下载文件时。

内存映射文件:内存映射文件会占用较多的IO资源,尤其是在进行大文件读写时。

日志记录:过多的日志记录可能会导致IO性能下降,尤其是当日志文件过大时。

配置问题:错误的文件系统配置或者IO调度策略可能导致IO性能问题。


解决方法:

优化文件读写:减少不必要的文件读写操作,使用缓冲和合适的数据结构来减少IO次数。

优化网络操作:减少不必要的网络操作,优化网络传输效率,使用NIO来提高网络通讯性能。

优化内存映射文件:适当管理内存映射文件的使用,确保文件映射在不需要时能够正确关闭。

优化日志记录:合理控制日志级别,使用异步日志记录来避免IO性能瓶颈,适当地轮换日志文件。

调整系统配置:根据具体的IO需求调整文件系统的配置,比如调整IO调度策略等。

具体解决方案需要根据实际情况分析确定

5.网络问题

        网络问题:网络流量异常、网络攻击、服务器带宽不足、网络io(零拷贝,dubbo支持零拷贝)、web服务器io模型(Nginx、Tomcat等)。

Java进程导致网络峰值增高的原因可能有多种,常见的原因包括:

高频发送数据:Java应用可能会因为频繁发送网络请求或处理大量数据而导致网络使用率提高。

网络延迟:Java应用可能因为网络延迟或者频繁的网络连接/断开造成网络流量的增加。

内部缓冲区溢出:Java进程在处理网络数据时可能因为缓冲区不足导致不断发送数据包,增加网络负载。


解决方法:

优化网络通信:减少不必要的网络通信,实现更高效的数据传输协议。

流量控制:使用流量控制机制,比如TCP拥塞控制,限制发送速度。

缓冲区管理:确保Java应用有足够的缓冲区空间,避免溢出问题。

网络监控与分析:使用网络监控工具分析Java进程的网络使用情况,找出峰值所在,进行相应优化。

具体解决方案需要根据实际的网络使用情况和Java应用的具体行为来制定。

6.业务问题

        业务问题:业务高并发带来的PV 量过高、服务调用耗时异常、线程死锁、多线程并发问题、频繁进行 Full GC等问题;业务逻辑问题(具体场景具体分析)、如何定位某个方法耗时很久,如何统计业务逻辑内每个环节(方法)的耗时。

        业务问题,这个原因很多,解决办法倒是很直接:功能设计评审和代码走查。

        功能设计评审:复杂的业务逻辑,在编码前,给出设计逻辑,提交专家组进行评审。

        代码走查:看人

7.实验的代码

入口controller

package com.zxx.study.web.controller;

import com.zxx.study.web.task.FullCPUTask;
import com.zxx.study.web.task.FullIOTask;
import com.zxx.study.web.task.LazyTask;
import com.zxx.study.web.task.SyncThreadTask;
import com.zxx.study.web.util.ApiResult;
import com.zxx.study.web.util.ZhouxxTool;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * @author zhouxx
 * @Description:
 * @date 2024/6/2  18:33
 */
@RestController
@Slf4j
@Validated
@RequestMapping("/api/v1/lock")
public class DeadlockController {

    @Value("${upload.file-path}")
    private String filePath;

    @Value("${server.port}")
    private String serverPort;

    @SneakyThrows
    @GetMapping("/deadlock")
    public ApiResult deadlock(@RequestParam(value ="name", required = false) String name)  {
        //log.info("hi==========");
        /**
         * 死锁是两个或更多线程阻塞着等待其它处于死锁状态的线程所持有的锁。死锁通常发生在多个线程同时但以不同的顺序请求同一组锁的时候。
         *
         * 例如,如果线程1锁住了A,然后尝试对B进行加锁,同时线程2已经锁住了B,接着尝试对A进行加锁,这时死锁就发生了。
         * 线程1永远得不到B,线程2也永远得不到A,并且它们永远也不会知道发生了这样的事情。为了得到彼此的对象(A和B),
         * 它们将永远阻塞下去。这种情况就是一个死锁。
         *
         * */
        Object a = new Object();
        Object b = new Object();

        new Thread(new SyncThreadTask(a, b)).start();
        ZhouxxTool.sleep(5000);
        if(name!=null&&"zhouxx".equals(name)) {
            Thread thread = new Thread(new SyncThreadTask(b, a));
            thread.start();
            thread.join();
        }
        HashMap data=new HashMap();
        data.put("threadName",Thread.currentThread().getName());
        data.put("serverPort",serverPort);
        data.put("name",name);
        return ApiResult.success(data);
    }

    @SneakyThrows
    @GetMapping("/fullcpu")
    public ApiResult fullcpu(@RequestParam(value ="name", required = false) String name)  {
        //log.info("hi==========");

        if("zhouxx".equals(name)){
            //cpu高占用线程
            new Thread(new FullCPUTask()).start();

            //空闲线程
            new Thread(new LazyTask()).start();
            new Thread(new LazyTask()).start();
            new Thread(new LazyTask()).start();
        }

        HashMap data=new HashMap();
        data.put("threadName",Thread.currentThread().getName());
        data.put("serverPort",serverPort);
        data.put("name",name);
        return ApiResult.success(data);
    }

    @SneakyThrows
    @GetMapping("/fullio")
    public ApiResult fullio(@RequestParam(value ="name", required = false) String name)  {
        //log.info("hi==========");

        if("zhouxx".equals(name)){
            //IO高占用线程
            new Thread(new FullIOTask()).start();

            //空闲线程
            new Thread(new LazyTask()).start();
            new Thread(new LazyTask()).start();
            new Thread(new LazyTask()).start();
        }

        HashMap data=new HashMap();
        data.put("threadName",Thread.currentThread().getName());
        data.put("serverPort",serverPort);
        data.put("name",name);
        return ApiResult.success(data);
    }



}

模拟cpu飙高
package com.zxx.study.web.task;

/**
 * 这是一个占有大量CPU资源的任务
 *
 * @author lfg
 * @version 1.0
 */
public class FullCPUTask implements Runnable {

    @Override
    public void run() {
        while (true) {
            double a = Math.random() * Math.random();
        }
    }
}

package com.zxx.study.web.task;

import com.zxx.study.web.util.ZhouxxTool;

/**
 * 空闲线程
 *
 * @author lfg
 * @version 1.0
 */
public class LazyTask implements Runnable {
    @Override
    public void run() {
            while (true) {
                ZhouxxTool.sleep(10000);
            }
    }
}

模拟死锁
package com.zxx.study.web.task;

import com.zxx.study.web.util.ZhouxxTool;

/**
 * @author zhouxx
 * @Description:
 * @date 2024/6/3  14:38
 */
public class SyncThreadTask implements Runnable {

    private Object a;
    private Object b;

    public SyncThreadTask(Object a, Object b) {
        this.a = a;
        this.b = b;
    }

    @Override
    public void run() {
        String name = Thread.currentThread().getName();
        ZhouxxTool.printTimeAndThread(name + " 准备获取锁 " + a);
        synchronized (a) {
            ZhouxxTool.printTimeAndThread(name + " 已获取锁 " + a);
            doWork();
            ZhouxxTool.printTimeAndThread(name + " 准备获取锁 " + b);
            synchronized (b) {
                ZhouxxTool.printTimeAndThread(name + " 已获取锁 " + b);
                doWork();
            }
            ZhouxxTool.printTimeAndThread(name + " 释放锁 " + b);
        }
        ZhouxxTool.printTimeAndThread(name + " 释放锁 " + a);
        ZhouxxTool.printTimeAndThread(name + " 结束");
    }

    void doWork() {
        ZhouxxTool.sleep(5000);
    }
}
模拟io忙
package com.zxx.study.web.task;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * IO 操作频繁的任务
 *
 * @author lfg
 * @version 1.0
 */
public class FullIOTask implements Runnable {
    @Override
    public void run() {


        while (true) {
            try {
                FileOutputStream fileOutputStream = new FileOutputStream("tempFile.txt");
                for (int i = 0; i < 10000; i++) {
                    fileOutputStream.write(i);
                }
                fileOutputStream.close();

                FileInputStream fileInputStream = new FileInputStream("tempFile.txt");
                while (fileInputStream.read() != -1) {

                }

            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
模拟oom

参考:

Java web应用性能分析之【6种OOM模拟】_java 模拟oom-CSDN博客

Java web应用性能分析之【6种OOM监控和分析】-CSDN博客

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

The First项目报告:去中心化知识产权治理协议MON Protocol如何革新链游产业?

2023年12月&#xff0c;RPG NFT 游戏 Pixelmon 首席执行官 GiulioX 在 X 平台表示&#xff0c;确认将推出代币 MON&#xff0c;代币生成&#xff08;TGE&#xff09;时间将取决于 MON 的路线图和主流 CEX 的启动板队列。12 月 11 日&#xff0c;RPG NFT 游戏 Pixelmon 首席执行…

防爆AGV叉车在现代物流行业的应用

AGV 随着机器人技术在中国的快速发展&#xff0c;国内企业开始推出区别于传统叉车的叉车AGV&#xff0c;旨在为企业降本增效&#xff0c;降低人工成本与对人的依赖&#xff1b;同时&#xff0c;也将人工从危险恶劣的环境中解放出来。随着技术的持续提升&#xff0c;叉车AGV已经…

API低代码平台介绍4-数据库记录插入功能

数据库记录插入功能 本篇文章我们将介绍如何使用ADI平台定义一个向目标数据库插入记录的接口&#xff0c;包括手工组装报文单表插入、手工组装报文多表插入、自动组装报文多表插入三种方式。无论是单表插入还是多表插入&#xff0c;任何一条记录写入失败&#xff0c;那么默认情…

kvm学习 - 迅速上手示例

目录 kvmtool kvmsample kvmtool GitHub - kvmtool/kvmtool: Stand-alone Native Linux KVM Tool repoStand-alone Native Linux KVM Tool repo. Contribute to kvmtool/kvmtool development by creating an account on GitHub.https://github.com/kvmtool/kvmtool.git cd …

17.Redis之主从复制

1.主从复制是怎么回事&#xff1f; 分布式系统, 涉及到一个非常关键的问题: 单点问题 单点问题&#xff1a;如果某个服务器程序, 只有一个节点(只搞一个物理服务器, 来部署这个服务器程序) 1.可用性问题,如果这个机器挂了,意味着服务就中断了~ 2.性能/支持的并发量也是比较有限…

C语言学习:数据类型

一、 为什么要引入数据类型 • 计算机中每个字节都有一个地址&#xff08;类似门牌号&#xff09; • CPU通过 地址 来访问这个字节的空间 0x20001103 1 0 0 1 0 0 1 1 0x20001102 1 1 1 0 1 1 1 0 0x20001101 1 1 1 1 0 1 0 1 0x20001100 0 …

【UML用户指南】-06-面向对象建模-关系(relationship)

目录 1、面向对象建模常见的关系 2、关系的组成元素 3、依赖关系 4、泛化关系 5、关联关系 关联的四种修饰 1.名称 2.角色 3.多重性 4.聚合 6、常用建模技术 6.1、对简单依赖建模 6.2、对单继承建模 6.3、对结构关系建模 1、面向对象建模常见的关系 依赖 &#x…

flask轻松入门,概念讲解

Hello World Flask 是轻量级web框架&#xff0c;仅保留了核心功能&#xff1a; 请求响应处理模板渲染URL路由 文章目录 Hello Worldflask命令模式python命令模式两种模式对比修改入口文件配置flask命令修改python命令修改 修改端口和地址flask命令修改python命令修改 修改 URL …

jupyter之plt 画图弹出窗口展示图片以及静态图片切换方法

1. jupyter出图的三种方式 在python的Jupyter Notebook中&#xff0c;使用matplotlib绘制动态图形时&#xff0c;可能出现只显示一张静态图像。 这是因为在notebook中使用plt绘图共有三种模式&#xff1a; %matplotlib inline&#xff1a;这是默认的模式&#xff0c;输出的图片…

JavaScript 基础 - 对象

对象 对象是一种无序的数据集合&#xff0c;可以详细的描述描述某个事物。 注意数组是有序的数据集合。它由属性和方法两部分构成。 语法 声明一个对象类型的变量与之前声明一个数值或字符串类型的变量没有本质上的区别。 <script>let 对象名 {属性名&#xff1a;属性值…

【OPENMV】学习记录 (持续更新)

一、图像 1 设置彩色&#xff0f;黑白&#xff1a; sensor.set_pixformat() 设置像素模式。 sensor.GRAYSCALE: 灰度&#xff0c;每个像素8bit。sensor.RGB565: 彩色&#xff0c;每个像素16bit。 2 设置图像大小&#xff1a; sensor.set_framesize() 设置图像的大小 sensor.…

前端优化之图片压缩——tinyPNG

今天前端前辈新介绍的一个压缩图片的工具——tinyPNG&#xff0c;地址&#xff1a;TinyPNG – Compress WebP, PNG and JPEG images intelligently可以将图片压缩&#xff0c;进行优化。 一、使用方法——手动压缩 将超过200kb的图片拖到我标注的红框框里&#xff0c;拖到这里…

如何快速定位到影响mysql cpu飙升的原因——筑梦之路

通常我们只需要执行show processlist 进行查看&#xff0c;一般执行时间最长的SQL八九不离十就是罪魁祸首&#xff0c;但当show processlist的输出有近千条&#xff0c;那么很难第一眼就发现有问题的SQL&#xff0c;那么如何快速找到呢&#xff1f;其实也非常简单。我们知道mys…

多卡聚合智能融合通信设备在无人机无线视频传输应用

无人驾驶飞机简称“无人机”&#xff0c;是利用(无线电)遥控设备和自备的程序控制装置操纵的不载人飞行器&#xff0c;现今无人机在航拍、农业、快递运输、测绘、新闻报道多个领域中都有深度的应用。 无人机无线视频传输保证地面人员利用承载的高灵敏度照相机可以进行不间断的画…

HCIA--OSPF实验(复习)

实验拓扑&#xff1a; 实验思路&#xff1a; 1.规划IP&#xff0c;配置环回&#xff0c;接口IP 2.把R1&#xff0c;R2优先级改为0&#xff0c;让R1、R2放弃选举&#xff0c; [r1]interface g0/0/0 [r1-GigabitEthernet0/0/0]ospf dr-priority 0 <r1>reset ospf…

【linux】线程同步和生产消费者模型

线程同步 当我们多线程访问同一个临界资源时&#xff0c;会造成并发访问一个临界资源&#xff0c;使得临界资源数据不安全&#xff0c;我们引入了锁的概念&#xff0c;解决了临界资源访问不安全的情况&#xff0c;对于线程而言竞争锁的能力有强有弱&#xff0c;对于之前就抢到…

图形学初识--颜色混合

文章目录 前言正文为什么要有颜色混合&#xff1f;颜色混合常见实现方式&#xff1f;上述颜色混合注意点 结尾&#xff1a;喜欢的小伙伴点点关注赞哦! 前言 本章节补充一下颜色混合的内容&#xff0c;主要包含&#xff1a;为什么要有颜色混合&#xff1f;颜色混合常实现方式&a…

外星人Alienware x17R1 原厂Windows11系统

装后恢复到您开箱的体验界面&#xff0c;包括所有原机所有驱动AWCC、Mydell、office、mcafee等所有预装软件。 最适合您电脑的系统&#xff0c;经厂家手调试最佳状态&#xff0c;性能与功耗直接拉满&#xff0c;体验最原汁原味的系统。 原厂系统下载网址&#xff1a;http://w…

全文检索-ElasticSearch

1.基本概念 1.Index索引 动词&#xff1a;相当于MySQL中的insert&#xff1b; 名词&#xff1a;相当于MySQL中的DataBase&#xff1b; 2.Type&#xff08;类型&#xff09; 在Index&#xff08;索引&#xff09;中&#xff0c;可以定义一个或多个类型 类似于MySQL中的Tab…

Docker大学生看了都会系列(二、2.1Mac通过Homebrew安装Docker)

系列文章目录 第一章 Docker介绍 第二章 2.1 Mac通过Homebrew安装Docker 第二章 2.2 CentOS安装Docker 文章目录 前言Mac通过Homebrew安装本机环境系统要求terminal命令安装查看安装信息配置阿里云镜像加速登陆阿里云配置加速地址其他国内加速地址 总结 前言 在上一章了解了Do…