「布道师系列文章」宝兰德徐清康解析 Kafka 和 AutoMQ 的监控

news2024/11/26 15:43:32

作者|北京宝兰德公司解决方案总监徐清康

01

前言

当我们使用一个软件的时候,经常都会问这个软件怎么监控、监控他的哪些指标?Kafka 的监控挺长时间都是一个老大难的问题,社区在监控方面一直没有投入太大的精力。如果要实现一个全面的 Kafka 监控框架,至少应该囊括 Kafka 所在主机资源、JVM(毕竟 Kafka 的 Broker 就是一个 Java 进程)、Kafka 集群本身等的监控,监控 Kafka 集群时还需要关注其客户端程序的性能。本文关注的重点在于 Kafka 和 AutoMQ 集群的监控,对于主机监控和 JVM 监控大家应该已经非常熟悉了。为了更好的说明,先对所涉及的验证环境进行简要介绍,其中包含依赖组件 ZooKeeper、Kafka/AutoMQ 集群自身、CMAK 监控服务。

02

Kafka 监控

为了简单起见,ZooKeeper 只采用了单实例运行。Kafka Broker 则使用了 3 台主机搭建了真实的集群。CMAK 全称为 Cluster Manager for Apache Kafka,也就是以前的 Kafka Manager 改名而来,由 Yahoo 奉献的管理 Kafka 的开源软件。笔者最开始看到这个 CMAK 时老联想起跨平台编译工具“CMake”~_~。

1. 给 Kafka 开启 JMX 监控

Kafka 的官方文档中提到了可以通过 JMX 方式获取 Kafka 的 metrics 信息,可参照 https://kafka.apache.org/documentation/#monitoring。聊到 JMX,其全称为“Java Management Extensions”,它是一种用于监控和管理 Java 应用程序的框架。曾经非常流行,包含著名的 WebLogic 在内的众多 JavaEE 应用服务器中间件,其管理和监控端都可以通过 JMX 技术进行中间件配置管理和监控。很多使用 Zabbix 监控软件对应用服务器中间件监控的场景,也是通过 JMX 方式进行的。JMX 技术的几个核心要点:

  1. 在 JVM 体系里边,需要被管理或者监控的对象,最后都叫做一个 MBean(也就是 Managed Bean),我们不需要去管 MBean 有标准 MBean、动态 MBean、模型 MBean,只需要知道本质其实就是一个普通的 Java 对象即可。

  2. 每个 MBean 通过一个 ObjectName 进行标识,ObjectName 通常是多个键值对组合而成。

  3. 需要管理和监控的项,则以 Attribute 进行暴露。

以 Kafka 为例,如果需要获取一个主题中入队的消息数量统计,则需要查看 ObjecyName 为“kafka.server:type=BrokerTopicMetrics,name= MessagesInPerSec,topic=mainTopic1”的 MBean,该 MBean 会有“Count”、“OneMinuteRate”、“FiveMinuteRate”、“FifteenMinuteRate”等属性分别表示“消息总数”、“过去 1 分钟入队消息速率”、“过去 5 分钟入队消息速率”、““过去 15 分钟入队消息速率”。Kafka 默认是不开启 JMX 的,因此需要在启动之前通过设置 JMX_PORT 环境变量让 Kafka 开启 JMX。

#!/bin/sh
KAFKA_HOME=/home/xuqingkang/kafka-3.7.0
export KAFKA_HEAP_OPTS=" -Xms6g -Xmx6g"
export JMX_PORT="19009"
export KAFKA_JVM_PERFORMANCE_OPTS=" -server -XX:+UseG1GC -XX:MaxGCPauseMillis=20 -XX:InitiatingHeapOccupancyPercent=35 -XX:+ExplicitGCInvokesConcurrent -Djava.awt.headless=true"$KAFKA_HOME/bin/kafka-server-start.sh -daemon 
$KAFKA_HOME/config/server.properties

环境变量中包含 JMX_PORT 时,Kafka 启动脚本通过-D 设置 JMX 相关的几个属性,如"-Dcom.sun.management.jmxremote",便开启了 JMX 支持。

>cat kafka-run-class.sh
# JMX settings
if [ -z "$KAFKA_JMX_OPTS" ]; then
  KAFKA_JMX_OPTS="-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.authenticate=false  -Dcom.sun.management.jmxremote.ssl=false "
fi
# JMX port to use
if [  $JMX_PORT ]; then
   KAFKA_JMX_OPTS="$KAFKA_JMX_OPTS -Dcom.sun.management.jmxremote.port=$JMX_PORT "
   if ! echo "$KAFKA_JMX_OPTS" | grep -qF -- '-Dcom.sun.management.jmxremote.rmi.port=' ; then
    # If unset, set the RMI port to address issues with monitoring Kafka running in containers
    KAFKA_JMX_OPTS="$KAFKA_JMX_OPTS -Dcom.sun.management.jmxremote.rmi.port=$JMX_PORT"
  fi
fi

当 Kafka 的 Broker 开启了 JMX,使用 JDK 自带的 JConsole 工具就可以连接。打开 jconsole,通过远程的方式指定 ip 地址和端口即可。

JConsole 上正常连接后就可以在 MBean Tab 页,查看 Kafka 众多暴露的 MBean 从而查看到监控数据。如下为获取 Kafka Broker 状态的 MBean。

2. 基于 JMX 自实现 Java 客户端获取 Kafka 监控数据

在某些环境上,可能无法使用 jconsole 可视化界面,那么可以自实现 Java 类,获取 Kafka 监控信息,自实现的 Java 类不需要依赖任何 JDK 之外的 jar 包就可以运行,还是非常的方便。Java 代码的主要逻辑为获取MBeanServer 连接,通过 MBeanServer 连接进行 MBean 的查询以及属性获取。如下代码样例主要是查询 Kafka Broker 之上的所有 LogEndOffset MBean,获取各主题(Topic)分区的 LogEndOffset。

import javax.management.*;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * Created by qingkang.xu on 2024/6/2.
 */
 public class KafkaJMXMonitor {

     private static MBeanServerConnection conn;
     
     //设置Kafka Broker的JMX连接信息,包括主机ip和JMX_PORT
     private static String ipAndPort = "192.168.32.170:19009";
    
     public static void main(String[] args) {
         // 1、初始化,获取Kafka JMX MbeanServer连接
         if(!init()){
              return;
         }                
         
         // 2、通过正则表达式,获取Kafka下所有主题分区的LogEndOffset MBean
         Set<ObjectName> objectNames = null;
         try {            
             // Kafka每个主题所有分区,每个分区对应一个MBean, topic和partition设为"*"模糊查询。
             ObjectName logOffsetObjName = new ObjectName(               
                "kafka.log:type=Log,name=LogEndOffset,topic=*,partition=*");
              objectNames = conn.queryNames(logOffsetObjName,null);
         } catch (MalformedObjectNameException e) {
            e.printStackTrace();
            return;
         } catch (IOException e) {
            e.printStackTrace();
            return;
         }  
         
         if(objectNames == null){ 
             return; 
         }  
         
         //  3、获取每一个主题分区对应的LogEndOffset MBean信息,得到LogEndOffset        
         for(ObjectName objName:objectNames){
             String topicName = objName.getKeyProperty("topic");
             //  __consumer_offsets为kafka存储客户端offset的专用主题,忽略            
             if("__consumer_offsets".equals(topicName)){
                 continue; 
             }                        
             
             int partId = Integer.parseInt(objName.getKeyProperty("partition"));            
             try{ 
                 Object val = conn.getAttribute(objName,"Value");
                 if(val !=null){
                     System.out.println("{topicName:" + topicName + ",partition:" + partId + ",LogEndOffset:" + val);
                  } 
             }catch (Exception e) {
               e.printStackTrace();
               return; 
             }
          }  
      }
      
    //  初始化JMX MBeanServer连接
    public static boolean init(){
        String jmxURL = "service:jmx:rmi:///jndi/rmi://" +ipAndPort+ "/jmxrmi";  
        System.out.println("Init JMX, jmxUrl: {" + jmxURL + "}, and begin to connect it");
        try {
             JMXServiceURL serviceURL = new  JMXServiceURL(jmxURL);          
             JMXConnector connector = JMXConnectorFactory.connect(serviceURL,null); 
             conn = connector.getMBeanServerConnection(); 
             if(conn == null){
                 System.err.println("Get JMX Connection Return Null!");
                 return  false;
              }
          } catch (MalformedURLException e) {
             e.printStackTrace();
             return false; 
          } catch (IOException e) {
              e.printStackTrace();
              return false;
          }        
          return true;
    }
}

如上代码编译运行的结果类似如下:从结果可以看出该 Broker 上有 3 个主题,每个主题有两个分区,各分区的 LogEndOffset 也正常的获取到。

[xuqingkang@rhel75-170 jmx-client]$ javac KafkaJMXMonitor.java
[xuqingkang@rhel75-170 jmx-client]$ java -cp . KafkaJMXMonitor
Init JMX, jmxUrl: {service:jmx:rmi:///jndi/rmi://192.168.32.170:19009/jmxrmi}, and begin to connect it
{topicName:mainTopic1,partition:0,LogEndOffset:23
{topicName:mainTopic2,partition:2,LogEndOffset:0
{topicName:mainTopic2,partition:0,LogEndOffset:8
{topicName:mainTopic3,partition:0,LogEndOffset:0
{topicName:mainTopic3,partition:2,LogEndOffset:0
{topicName:mainTopic1,partition:1,LogEndOffset:6

3. CMAK 管理出场
如上的监控在界面体验上都不是很方便,到 CMAK 出场的时候了,通过如下几步便可以实现一个直观的 B/S 架构的 Kafka 监控。1、通过 git 从 github 获取 CMAK:

git clone https://github.com/yahoo/CMAK.git

2、编译 CMAK 和配置CMAK 的编译构建使用 sbt 即可,sbt 是专门用于构建 Scala 项目的编译构建工具,类似于大家熟知的 Maven 和 Gradle 等。但在编译构建之前,按照官方要求需要的 JDK 版本为 11 以上。因此在真正运行 sbt 之前需要将 11 版本以上的 JDK 路径进行正确的设置,参照如下命令:

PATH=/home/xuqingkang/jdk-14.0.2/bin:$PATH 
JAVA_HOME=/home/xuqingkang/jdk-14.0.2 
/home/xuqingkang/CMAK/sbt -java-home /home/xuqingkang/jdk-14.0.2 clean dist

如果一切顺利,最后将会看到"Your package is ready in"的提示告知最后编译好的 CMAK 所在路径,如下所示:

......
[info] Compiling 140 Scala sources and 2 Java sources to /home/xuqingkang/CMAK/target/scala-2.12/classes ...
[info] LESS compiling on 1 source(s)
model contains 662 documentable templates
[info] Main Scala API documentation successful.
[success] All package validations passed
[info] Your package is ready in /home/xuqingkang/CMAK/target/universal/cmak-3.0.0.7.zip
[success] Total time: 114 s (01:54), completed 2024年6月2日 上午10:39:58

使用 unzip 命令对 target/universal/cmak-3.0.0.7.zip 进行解压,解压之后修改 conf/application.conf 文件,将 cmak.zkhosts 修改为实际的 zookeeper 地址。

cmak.zkhosts="192.168.32.170:2181"

最后,就可以使用 cmak 的脚本直接启动了,因为笔者环境中有多个版本的 JDK,因此特意使用"-java-home"选项指定了 jdk 14 版本的 JDK,以满足官方要求的 11 以上。

nohup ./bin/cmak -java-home /home/xuqingkang/jdk-14.0.2/ &

3、CMAK 运行和基本使用CMAK 默认使用的端口是 9000,也可以在启动的时候使用“-Dhttp.port”选项进行修改,比如“cmak -Dhttp.port=8080”。在启动完成之后,便可以使用浏览器进行访问。当看到 CMAK 界面后,第一步应该做的事情就是在“Cluster”菜单中点击“Add Cluster”将需要管理的 Kafka 集群信息录入。

在添加 Kafka 集群的时候,最重要的信息就是设置“Cluster Zookeeper Hosts”选项,保持和真正的 Kafka 集群的 ZooKeeper 一致即可。对于“Enable JMX Polling”选项,是获取到“Combined Metric”指标必须具备选择的,他也需要 Kafka Broker 启动的时候设置 JMX_PORT 环境变量,使 Kafka 开启 JMX 监控。

如果设置正确,接下来就可以在集群清单中选择创建的 kafka 集群进行监控。

03

AutoMQ 的监控

AutoMQ 的官网给出的监控指引中,对 Metrics 集成做了比较详细的说明。如下来自 AutoMQ 官网的图中,在大家所熟知的 Grafana+Promethues 组合之间增加了 OT Receiver 和 OT Collector 这两个角色,实际上是对 OpenTelemetry 的支持。Grafana+OpenTelemetry+Promethues 的监控架构。引入的 OT Collector 和 OT Receiver 主要是让 Kafka/AutoMQ 服务作为被监控对象,可以将自己的 Metrics 信息直接以推送(Push)的方式上报。而且 OT Collector 可以完成数据过滤、聚合、转换以及将数据导出到多个后端等动作,这是当前构建云原生大规模监控的主流架构。

参照下文中几个步骤,便可以搭建好 Grafana、OTel Collector、Promethues 服务,并且将 Kafka/AutoMQ 的 Controller、Broker 接入到监控中。

1. 以 Docker 方式运行 Promethues 等核心监控服务

AutoMQ 的源码中(链接 https://github.com/AutoMQ/automq\),docker/telemetry/目录下有对应构建监控服务的脚本以及监控服务配置样例。可以直接运行 "install.sh start",该脚本主要是以 docker-compose 的方式将 Grafana、Promethues、OTel Collector 这些服务以 Docker 容器的方式运行。如下是核心代码和配置的摘录:

>cat install.sh //直接调用docker compose启动容器
start_containers() {
  docker compose -f ./docker-compose.yaml up -d
  echo "Done."
}

docker-compose.yaml 中则包含了 grafana、promethues 等各个服务的容器启动配置。

>cat docker-compose.yaml
version: '3'
services:
  grafana:
    image: grafana/grafana-enterprise
    container_name: grafana
    ......
    extra_hosts:
      - "host.docker.internal:host-gateway"
  prometheus:
    image: prom/prometheus
    ports: 
      - 9090:9090
    ......
    extra_hosts:
      - "host.docker.internal:host-gateway"
  alertmanager:
    image: prom/alertmanager
    ports:
      - "9087:9087"
    ......
    extra_hosts:
      - "host.docker.internal:host-gateway"
  otel-collector:
    image: otel/opentelemetry-collector-contrib
    ......
      - 8890:8890 # Prometheus exporter metrics
      - 13133:13133 # health_check extension
      - 4317:4317 # OTLP gRPC receiver
      - 4318:4318 # OTLP http receiver 
    extra_hosts: 
      - "host.docker.internal:host-gateway"

运行"install.sh start"之后可以在当前主机中使用 docker ps 查看监控服务对应的容器是否正常运行。一切正常的话,"http://ip:3000"应该已经可以打开 grafana 的界面了。

>docker ps
5af530eebd6c   grafana/grafana-enterprise                 "/run.sh"                33 hours ago     Up 33 hours       0.0.0.0:3000->3000/tcp, :::3000->3000/tcp                                                                                                                                                                                                                        grafana
21bbd335c5a3   prom/prometheus                            "/bin/prometheus --s…"   33 hours ago     Up 33 hours       0.0.0.0:9090->9090/tcp, :::9090->9090/tcp                                                                                                                                                                                                                        telemetry-prometheus-1
1914f31ef125   otel/opentelemetry-collector-contrib       "/otelcol-contrib --…"   33 hours ago     Up 33 hours       0.0.0.0:1888->1888/tcp, :::1888->1888/tcp, 0.0.0.0:4317-4318->4317-4318/tcp, :::4317-4318->4317-4318/tcp, 0.0.0.0:8888->8888/tcp, :::8888->8888/tcp, 0.0.0.0:8890->8890/tcp, :::8890->8890/tcp, 0.0.0.0:13133->13133/tcp, :::13133->13133/tcp, 55678-55679/tcp   telemetry-otel-collector-1
00cf4d65a6a1   phpmyadmin/phpmyadmin                      "/docker-entrypoint.…"   8 months ago     Up 3 days         0.0.0.0:19001->80/tcp, :::19001->80/tcp                                                                                                                                                                                                                          7218907947dc48c1

2. 修改 AutoMQ 的 Broker 和 Controller 配置以接入监控。

不得不说,这里本人踩了不少坑,最后发现其实很简单。核心是在启动 Broker 和 Contoller 之前,需要在其配置文件中增加 metrics 配置以使得 Broker 和 Controller 能将监控数据以 Push 推送的方式发到 OTel Collector。注意 otlp.endpoint 需改为您实际环境中的 IP 地址即可,因为在 Docker 容器中也是可以直接访问宿主机网络的,这里使用了宿主机的 IP 地址。

s3.telemetry.metrics.enable=true
s3.telemetry.metrics.exporter.type=otlp
s3.telemetry.exporter.otlp.endpoint=http://10.0.4.14:4317

以容器的方式运行,推荐在官方镜像的基础之上对关键配置文件做变更即可,重新构建“automqinc/automq”镜像,具体步骤如下:1)、构建目录,其中 config 目录下的配置文件全是从官方镜像拷贝出来的,当然也可以从 github 源码中直接拷贝。

[root@txcloud-centos8-1 addOTelinDocker]# tree
.
├── config
│   └── kraft
│       ├── broker.properties
│       ├── controller.properties
│       └── server.properties
├── Dockerfile
└── makeDocker.sh

2)、3 个 properties 文件中增加"s3.telemetry..."配置

############################# Server Basics #####
# The role of this server. Setting this puts us in KRaft modeprocess.roles=broker
# The node id associated with this instance's roles
node.id=2

# The connect string for the controller quorum
controller.quorum.voters=1@localhost:9093
############################# Socket Server Settings #############################
#     listeners = PLAINTEXT://your.host.name:9092listeners=PLAINTEXT://localhost:9092
# The Prometheus HTTP server host and port, if exporter type is set to prometheus
# s3.metrics.exporter.prom.host=127.0.0.1
# s3.metrics.exporter.prom.port=9090
# The OTel Collector endpoint, if exporter type is set to otlp or tracing is enabled
# s3.telemetry.exporter.otlp.endpoint=http://${your_host_name}:4317
s3.telemetry.metrics.enable=true
s3.telemetry.metrics.exporter.type=otlp
s3.telemetry.exporter.otlp.endpoint=http://10.0.4.14:4317

3)、完成 Dockerfile 和 makeDocker.sh 脚本,逻辑比较简单,就是在官方镜像基础之上实现配置文件覆盖,构建新镜像。直接运行 makeDocker.sh 脚本在本地构建好新镜像。

[root@txcloud-centos8-1 addOTelinDocker]# cat Dockerfile 
# pull base image
# --------------
FROM automqinc/automq:latest

# Maintainer
# --------------
MAINTAINER support  <xuqingkang2@163.com>

COPY config/kraft/server.properties /opt/kafka/kafka/config/kraft/server.properties
COPY config/kraft/broker.properties /opt/kafka/kafka/config/kraft/broker.properties
COPY config/kraft/controller.properties /opt/kafka/kafka/config/kraft/controller.properties
[root@txcloud-centos8-1 addOTelinDocker]# cat makeDocker.sh 
#!/bin/sh
docker build --force-rm=true --no-cache=true -t automqinc/automq:latest -f Dockerfile .

3、启动 AutoMQ Broker/Controller 等服务同样也是需要参照 AutoMQ 官方的文档,在本地以 Docker 的方式快速拉起 Broker 和 Controller 等服务。注意,因为上一步骤已经在本地构建了“automqinc/automq”镜像,因此 docker-compose 会使用它。

curl https://download.automq.com/community_edition/standalone_deployment/install_run.sh | bash

AutoMQ 官方提供的 install_run.sh 脚本,其核心逻辑是从官网下载 docker-compose.yaml 文件后用 docker-compose 拉起 Broker 和 Controller,如下是关键代码的摘录:

curl -O https://download.automq.com/community_edition/standalone_deployment/docker-compose.yaml
if [ ! -f "docker-compose.yaml" ]; then
    echo "[ERROR] Docker compose yaml file not exist."
        exit 4
fi
# Check if the current operating system is Linux
if [[ "$(uname)" == "Linux" ]]; then
    echo "Please enter your password for sudo:"
    sudo /usr/local/bin/docker-compose -f docker-compose.yaml up -d || exit 5
else
    docker-compose -f docker-compose.yaml up -d || exit 5
fi

docker-compose.yaml 文件则指示了 Broker 和 Controller 这些核心的服务,怎么启动其 Docker 容器。

version: "3.8"
services:
  ......
  controller:    image: automqinc/automq:latest
  ......
  command:
    - bash
    - -c
    - |
      /opt/kafka/scripts/start.sh up --process.roles controller --node.id 0 --controller.quorum.voters 0@controller:9093 --s3.bucket automq-data --s3.endpoint http://10.6.0.2:4566 --s3.region us-east-1
  networks:
    - automq_net    
  depends_on:
    - localstack
    - aws-cli
  broker1:
    image: automqinc/automq:latest
    ......
    command:
      - bash
      - -c
      - |
        /opt/kafka/scripts/start.sh up --process.roles broker --node.id 1 --controller.quorum.voters 0@controller:9093 --s3.bucket automq-data --s3.endpoint http://10.6.0.2:4566 --s3.region us-east-1

  broker2:
    ...雷同broker1

最后,通过浏览器访问 Grafana,即可看到 AutoMQ 的监控数据,包括 Controller 数量、Broker 数量、Partition 数量、每秒收发字节数、主题、消费组等等。

END

关于我们

我们是来自 Apache RocketMQ 和 Linux LVS 项目的核心团队,曾经见证并应对过消息队列基础设施在大型互联网公司和云计算公司的挑战。现在我们基于对象存储优先、存算分离、多云原生等技术理念,重新设计并实现了 Apache Kafka 和 Apache RocketMQ,带来高达 10 倍的成本优势和百倍的弹性效率提升。

🌟 GitHub 地址:https://github.com/AutoMQ/automq
💻 官网:https://www.automq.com

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MTANet: 多任务注意力网络,用于自动医学图像分割和分类| 文献速递-深度学习结合医疗影像疾病诊断与病灶分割

Title 题目 MTANet: Multi-Task Attention Network for Automatic Medical Image Segmentation and Classification MTANet: 多任务注意力网络&#xff0c;用于自动医学图像分割和分类 01 文献速递介绍 医学图像分割和分类是当前临床实践中的两个关键步骤&#xff0c;其准…

BRAVE:扩展视觉编码能力,推动视觉-语言模型发展

视觉-语言模型&#xff08;VLMs&#xff09;在理解和生成涉及视觉与文本的任务上取得了显著进展&#xff0c;它们在理解和生成结合视觉与文本信息的任务中扮演着重要角色。然而&#xff0c;这些模型的性能往往受限于其视觉编码器的能力。例如&#xff0c;现有的一些模型可能对某…

苹果Mac电脑遭恶意软件攻击 Mac第三方恶意软件删除不了

苹果Mac电脑一直以来都以安全性和稳定性著称&#xff0c;许多用户认为Mac电脑不会受到恶意软件的侵害&#xff0c;但事实上&#xff0c;Mac电脑也不是绝对安全的&#xff0c;近年来&#xff0c;有越来越多的恶意软件针对Mac电脑进行攻击&#xff0c;甚至有些恶意软件可以绕过苹…

MSPM0L1306——定时器

相关配置&#xff1a; #include "ti_msp_dl_config.h"int main(void) {SYSCFG_DL_init();//清除定时器中断标志NVIC_ClearPendingIRQ(TIMER_0_INST_INT_IRQN);//使能定时器中断NVIC_EnableIRQ(TIMER_0_INST_INT_IRQN);while (1) { } }//定时器…

Thinkpad系列产品进入Bios并设置U盘启动

Thinkpad系列产品&#xff0c;进入Bios并设置U盘启动&#xff0c;常用于以下场景&#xff1a; 1. 安装操作系统。 通过U盘启动盘&#xff0c;用户可以在电脑无法从硬盘启动或需要重装系统时&#xff0c;将操作系统安装到电脑中。这种方法简单且有效&#xff0c;节省了时间并方便…

Redis-数据结构-跳表详解

Redis概述 Redis-数据结构-跳表详解 跳表&#xff08;Skip List&#xff09;是一种基于并联的链表结构&#xff0c;用于在有序元素序列中快速查找元素的数据结构。 Redis 中广泛使用跳表来实现有序集合&#xff08;Sorted Set&#xff09;这一数据结构。 1.跳表的基本概念和…

1832javaERP管理系统之实践教学管理Myeclipse开发mysql数据库servlet结构java编程计算机网页项目

一、源码特点 java erp管理系统之实践教学管理是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助采用了servlet设计&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统采用web模式&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Mye…

早期发现,健康生活!第三届ZAODX世界肿瘤早筛大会圆满落幕!

2024年6月15日-16日&#xff0c;第三届ZAODX世界肿瘤早筛大会在雄安新区盛大开幕&#xff01;本次会议由河北雄安新区管理委员会公共服务局指导&#xff0c;第三届ZAODX世界肿瘤早筛大会组委会和早筛网主办&#xff0c;粤港澳大湾区精准医学研究院&#xff08;广州&#xff09;…

双绞线(网线)的制作与测试

实验目的 1、熟悉常用双绞线&#xff08;网线&#xff09;及其制作工具的使用&#xff1b; 2、掌握非屏蔽双绞线的直通线、交叉线的制作及连接方法&#xff1b; 3、掌握双绞线连通性的测试。 设备要求&#xff1a;RJ45压线钳&#xff0c;RJ45水晶头&#xff0c;UTP线缆&…

《跟我一起学“网络安全”》——安全设备

安全设备 一、安全设备–IDS IDS入侵检测 (1)什么是入侵检测&#xff1a; 入侵检测系统&#xff08;intrusion detection system&#xff0c;简称“IDS”&#xff09;是一种对网络传输进行即时监视&#xff0c;在发现可疑传输时发出警报或者采取主动反应措施的网络安全设备。…

50etf期权交易规则杠杆怎么计算?

今天带你了解50etf期权交易规则杠杆怎么计算&#xff1f;近年来&#xff0c;期权交易在股票市场中变得愈发流行&#xff0c;其中50ETF期权备受关注。作为一种金融衍生品&#xff0c;50ETF期权为投资者提供了更灵活的投资方式和更多的策略选择。 50etf期权交易规则杠杆怎么计算&…

Hi3861 OpenHarmony嵌入式应用入门--启动流程

目录 BootLoader的启动与运行 Hi3861 RiSC-V boot 启动文件介绍 Loaderboot 启动过程 Flashboot代码介绍 printf串口配置 内核启动任务 BootLoader的启动与运行 Hi3861 RiSC-V boot 启动文件介绍 - Hi3861 的引导程序分为两部分&#xff0c;一部分是在芯片出厂时已经固…

谷歌插件将网页转图片

将网页转换为图片并保存 /*** 给网页转换为图片上传到FTP* param ftpUtils FTP连接对象* param pdfid 上传业务对象* param type 网页类型 1 审核表 2 合同 3 申请书* return https://registry.npmmirror.com/binary.html?pathchromedriver/*/private boolean htmlToImgFtp(Ft…

汇聚荣拼多多运营策略是怎么样的?

拼多多作为中国领先的电商平台&#xff0c;其运营策略一直备受关注。拼多多的成功不仅在于其创新的“社交电商”模式&#xff0c;更在于其精细化的市场定位和高效的用户增长策略。本文将深入分析拼多多的运营策略&#xff0c;探讨其如何在激烈的电商竞争中突围而出。 一、用户增…

人民日报:高考填志愿十问十答,填报志愿时需要考虑哪些因素?

高考结束&#xff0c;志愿填报即将开始&#xff0c;填报志愿时需要考虑哪些因素&#xff1f;如何避免高分低录甚至落榜&#xff1f;高考填志愿你需要知道的事↓↓ 祝福考生考入理想大学、就读喜欢的专业。加油&#xff01; 责任编辑&#xff1a;曹继炜

初级篇-Docker容器知识

Docker容器 容器主要是解决跨平台、跨服务运行环境的问题 容器将运行业务应用所需要的东西进行打包&#xff0c;包括依赖项、配置、脚本、二进制文件等。在容器中运行镜像&#xff0c;不用担心不同环境下运行不一致的问题。 容器本质上是一个特殊的进程&#xff0c;将资源、…

Golang内存模型与分配机制

简述 mheap为堆&#xff0c;堆和进程是一对一的&#xff1b;mcentral&#xff08;小mheadp&#xff09;&#xff0c;mcahe&#xff08;GMP的P私有&#xff09;&#xff0c;分配内存顺序由后向前。 在解决这个问题&#xff0c;Golang 在堆 mheap 之上&#xff0c;依次细化粒度&a…

SQL注入-上篇

SQL注入 注入是web安全的头号大敌。注入攻击漏洞往往是应用程序缺少对输入进行安全性检查所引起的。攻击者把一些包含攻击代码当做命令或者查询语句发送给解释器&#xff0c;这些恶意数据可以欺骗解释器&#xff0c;从而执行计划外的命令或者未授权访问数据。注入漏洞通常能sq…

AI + 3D:用单个图像和文本提示创建可交互的3D世界

你是否曾经梦想过只需一张照片和一些简单的文字描述,就能立即进入一个生动的3D虚拟世界?今天,我们将介绍一个革命性的技术,它就像是一台神奇的3D场景制造机,能够根据你的想象快速构建出令人惊叹的虚拟空间。 一、技术概览 这项技术不仅仅是一个简单的图像到3D的转换工具…

线程池吞掉异常的case:源码阅读与解决方法

1. 问题背景 有一天给同事CR&#xff0c;看到一段这样的代码 try {for (param : params) {//并发处理&#xff0c;func无返回值ThreadPool.submit(func(param));} } catch (Exception e) {log.info("func抛异常啦,参数是:{}", param) } 我&#xff1a;你这段代码是…