第26关 K8s日志收集揭秘:利用Log-pilot收集POD内业务日志文件
------> 课程视频同步分享在今日头条和B站
大家好,我是博哥爱运维。
OK,到目前为止,我们的服务顺利容器化并上了K8s,同时也能通过外部网络进行请求访问,相关的服务数据也能进行持久化存储了,那么接下来很关键的事情,就是怎么去收集服务产生的日志进行数据分析及问题排查,下面会以生产中的经验来详细讲解这些内容。
K8S日志收集体系
现在市面上大多数课程都是以EFK来作来K8s项目的日志解决方案,它包括三个组件:Elasticsearch
, Fluentd(filebeat)
, Kibana
;Elasticsearch 是日志存储和日志搜索引擎,Fluentd 负责把k8s
集群的日志发送给 Elasticsearch, Kibana 则是可视化界面查看和检索存储在 Elasticsearch 的数据。
但根据生产中实际使用情况来看,它有以下弊端:
1、日志收集笼统
EFK是在每个kubernetes的NODE节点以daemonset的形式启动一个fluentd的pod,来收集NODE节点上的日志,如容器日志(/var/log/containers/*.log
),但里面无法作细分,想要的和不想要的都收集进来了,带来的后面就是磁盘IO压力会比较大,日志过滤麻烦。
2、无法收集对应POD里面的业务日志
上面第1点只能收集pod的stdout日志,但是pod内如有需要收集的业务日志,像pod内的/tmp/datalog/*.log,那EFK是无能为力的,只能是在pod内启动多个容器(filebeat)去收集容器内日志,但这又会带来的是pod多容器性能的损耗,这个接下来会详细讲到。
3、fluentd的采集速率性能较低,只能不到filebeat的1/10的性能。
基于此,我通过调研发现了阿里开源的智能容器采集工具 Log-Pilot,github地址:https://github.com/AliyunContainerService/log-pilot
下面以sidecar 模式和log-pilot这两种方式的日志收集形式做个详细对比说明:
第一种模式是 sidecar 模式,这种需要我们在每个 Pod 中都附带一个 logging 容器来进行本 Pod 内部容器的日志采集,一般采用共享卷的方式,但是对于这一种模式来说,很明显的一个问题就是占用的资源比较多,尤其是在集群规模比较大的情况下,或者说单个节点上容器特别多的情况下,它会占用过多的系统资源,同时也对日志存储后端占用过多的连接数。当我们的集群规模越大,这种部署模式引发的潜在问题就越大。
另一种模式是 Node 模式,这种模式是我们在每个 Node 节点上仅需布署一个 logging 容器来进行本 Node 所有容器的日志采集。这样跟前面的模式相比最明显的优势就是占用资源比较少,同样在集群规模比较大的情况下表现出的优势越明显,同时这也是社区推荐的一种模式。
经过多方面测试,log-pilot对现有业务pod侵入性很小,只需要在原有pod的内传入几行env环境变量,即可对此pod相关的日志进行收集,已经测试了后端接收的工具有logstash、elasticsearch、kafka、redis、file,均OK,下面开始部署整个日志收集环境。
我们这里用一个tomcat服务来模拟业务服务,用log-pilot分别收集它的stdout以及容器内的业务数据日志文件到指定后端存储,2023课程会以真实生产的一个日志传输架构来做测试:
模拟业务服务 日志收集 日志存储 消费日志 消费目的服务
tomcat ---> log-pilot ---> kafka ---> filebeat ---> elasticsearch ---> kibana
1、部署测试用的kafka
Apache Kafka是一种流行的分布式消息传递系统,设计用于处理大规模的数据流。它在日志传输和流数据处理领域尤为重要。以下是Kafka的一些关键特性,以及它们如何适用于日志传输体系:
- 高吞吐量和可伸缩性:
- Kafka能够处理高速数据流,支持大量数据的读写操作。它通过分区(partitions)和分布式架构来实现高吞吐量和水平扩展。
- 在日志传输中,这意味着Kafka可以高效地收集和分发大量的日志数据,满足大型系统的需求。
- 持久性和可靠性:
- Kafka将数据存储在磁盘上,并支持数据的复制,确保信息不会因为单点故障而丢失。
- 对于日志管理来说,这确保了日志数据的安全和完整性,即使在系统故障的情况下也能保持日志的可用性。
- 实时处理:
- Kafka支持实时数据流处理,使得数据在产生后立即可用。
- 在日志系统中,这允许实时监控和分析日志数据,有助于快速故障排除和系统性能监控。
- 分布式架构:
- Kafka的分布式特性意味着它可以跨多个服务器和数据中心运行,提高了容错能力和系统的稳定性。
- 在分布式日志系统中,这有助于管理跨地域或多个服务的日志数据,提供更好的可扩展性和冗余。
- 灵活的消费模型:
- Kafka支持发布-订阅和队列两种消息模式,使消费者能够灵活地读取数据。
- 日志传输中,这使得不同的系统和应用可以根据需要订阅特定类型的日志数据。
- 低延迟:
- Kafka设计用于低延迟消息传递,这对于需要快速响应的日志分析和监控系统至关重要。
结合日志传输体系,Kafka的这些特性使其成为一个理想的中央日志聚合点。它不仅能够高效地收集来自不同源的日志数据,还能将这些数据实时分发给各种日志分析和监控工具,支持大数据分析、实时监控和快速故障检测。
在Apache Kafka中,几个核心概念包括主题(Topic)、分区(Partition)和消费组(Consumer Group)。这些概念是Kafka高效消息处理和分布式数据流管理的基石。下面是对这些概念的简要介绍:
- 主题 (Topic):
- Kafka中的主题是消息的分类或者说是一个消息通道。生产者(Producers)将消息发送到特定的主题,而消费者(Consumers)从主题中读取消息。
- 主题可以被视为消息的逻辑分类。每个主题可以有多个生产者向其发送数据,也可以有多个消费者从中读取数据。
- 分区 (Partition):
- 为了提高可伸缩性和并行处理能力,Kafka中的每个主题可以被分割成多个分区。
- 分区允许主题中的消息在多个服务器(Broker)之间分布,从而实现数据的负载均衡和并行处理。每个分区都是有序且不变的消息序列。
- 每条消息在被添加到分区时都会被赋予一个唯一的序列号,称为偏移量(Offset)。
- 生产者在发送消息时可以指定消息应该发送到哪个分区,或者让Kafka根据消息的Key自动选择分区。
- 消费组 (Consumer Group):
- 消费者可以单独工作,也可以作为消费组的一部分来消费消息。消费组允许一组消费者共同订阅一个或多个主题,并协作消费消息。
- 在一个消费组内,每个分区的消息只会被组内的一个消费者读取。这保证了消息只被消费一次,同时实现了负载均衡。
- 如果一个消费组有多个消费者,Kafka会自动将主题的分区分配给不同的消费者,以实现并行处理。
- 消费组的概念使得Kafka可以灵活地支持多种消费模式,包括发布-订阅和点对点。
结合日志传输体系,这些特性使Kafka能够有效地处理来自多个源的大量日志数据。主题和分区支持高吞吐量的数据写入和读取,而消费组则允许多个消费者协作,确保日志数据的高效处理和分析。通过这种方式,Kafka可以作为一个强大的中央日志聚合系统,支持复杂的日志处理和分析需求。
准备一个测试用的kafka服务
# 部署前准备 10.0.1.201(这台作为二进制k8s集群的部署节点,上面会是装好docker服务的状态)# 准备好 docker-compose 命令
ln -svf /etc/kubeasz/bin/docker-compose /usr/bin/docker-compose# 准备好文件 docker-compose.yml:
#——------------------------------
version: '2'
services:zookeeper:image: bogeit/zookeeperports:- "2181:2181"restart: unless-stoppedkafka:image: bogeit/kafka:2.8.1ports:- "9092:9092"environment:DOCKER_API_VERSION: 1.22KAFKA_ADVERTISED_HOST_NAME: 10.0.1.201KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181volumes:- /var/run/docker.sock:/var/run/docker.sock- /mnt/kafka:/kafkarestart: unless-stopped#——------------------------------# 1. docker-compose setup:
# docker-compose up -d
Recreating kafka-docker-compose_kafka_1 ... done
Starting kafka-docker-compose_zookeeper_1 ... done# 2. result look:
# docker-compose psName Command State Ports
--------------------------------------------------------------------------------------------------------------------
kafka-docker-compose_kafka_1 start-kafka.sh Up 0.0.0.0:9092->9092/tcp
kafka-docker-compose_zookeeper_1 /bin/sh -c /usr/sbin/sshd ... Up 0.0.0.0:2181->2181/tcp, 22/tcp, 2888/tcp, 3888/tcp
# 3. run test-docker
bash-4.4# docker run --rm -v /var/run/docker.sock:/var/run/docker.sock -e HOST_IP=10.0.1.201 -e ZK=10.0.1.201:2181 -i -t wurstmeister/kafka /bin/bash# 4. list topic
bash-4.4# kafka-topics.sh --zookeeper 10.0.1.201:2181 --list
tomcat-access
tomcat-syslog# 5. consumer topic data:
bash-4.4# kafka-console-consumer.sh --bootstrap-server 10.0.1.201:9092 --topic tomcat-access --from-beginning
2、部署日志收集服务 log-pilot (适配容器运行时 Containerd)
# 先创建一个namespace
kubectl create ns ns-elastic# 部署yaml---
apiVersion: v1
kind: ConfigMap
metadata:name: log-pilot5-configurationnamespace: ns-elastic
data:logging_output: "kafka"kafka_brokers: "10.0.1.201:9092"kafka_version: "0.10.0"kafka_topics: "tomcat-syslog,tomcat-access"#kafka_username: "user"#kafka_password: "bogeit"---
apiVersion: v1
data:filebeat.tpl: |+{{range .configList}}- type: logenabled: truepaths:- {{ .HostDir }}/{{ .File }}scan_frequency: 5sfields_under_root: true{{if eq .Format "json"}}json.keys_under_root: true{{end}}fields:{{range $key, $value := .Tags}}{{ $key }}: {{ $value }}{{end}}{{range $key, $value := $.container}}{{ $key }}: {{ $value }}{{end}}tail_files: falseclose_inactive: 2hclose_eof: falseclose_removed: trueclean_removed: trueclose_renamed: false{{end}}kind: ConfigMap
metadata:name: filebeat5-tplnamespace: ns-elastic---
apiVersion: v1
data:config.filebeat: |+#!/bin/shset -eFILEBEAT_CONFIG=/etc/filebeat/filebeat.ymlif [ -f "$FILEBEAT_CONFIG" ]; thenecho "$FILEBEAT_CONFIG has been existed"exitfimkdir -p /etc/filebeat/prospectors.dassert_not_empty() {arg=$1shiftif [ -z "$arg" ]; thenecho "$@"exit 1fi}cd $(dirname $0)base() {cat >> $FILEBEAT_CONFIG << EOFpath.config: /etc/filebeatpath.logs: /var/log/filebeatpath.data: /var/lib/filebeat/datafilebeat.registry_file: /var/lib/filebeat/registryfilebeat.shutdown_timeout: ${FILEBEAT_SHUTDOWN_TIMEOUT:-0}logging.level: ${FILEBEAT_LOG_LEVEL:-info}logging.metrics.enabled: ${FILEBEAT_METRICS_ENABLED:-false}logging.files.rotateeverybytes: ${FILEBEAT_LOG_MAX_SIZE:-104857600}logging.files.keepfiles: ${FILEBEAT_LOG_MAX_FILE:-10}logging.files.permissions: ${FILEBEAT_LOG_PERMISSION:-0600}${FILEBEAT_MAX_PROCS:+max_procs: ${FILEBEAT_MAX_PROCS}}setup.template.name: "${FILEBEAT_INDEX:-filebeat}"setup.template.pattern: "${FILEBEAT_INDEX:-filebeat}-*"filebeat.config:prospectors:enabled: truepath: \${path.config}/prospectors.d/*.ymlreload.enabled: truereload.period: 10sEOF}es() {if [ -f "/run/secrets/es_credential" ]; thenELASTICSEARCH_USER=$(cat /run/secrets/es_credential | awk -F":" '{ print $1 }')ELASTICSEARCH_PASSWORD=$(cat /run/secrets/es_credential | awk -F":" '{ print $2 }')fiif [ -n "$ELASTICSEARCH_HOSTS" ]; thenELASTICSEARCH_HOSTS=$(echo $ELASTICSEARCH_HOSTS|awk -F, '{for(i=1;i<=NF;i++){printf "\"%s\",", $i}}')ELASTICSEARCH_HOSTS=${ELASTICSEARCH_HOSTS%,}elseassert_not_empty "$ELASTICSEARCH_HOST" "ELASTICSEARCH_HOST required"assert_not_empty "$ELASTICSEARCH_PORT" "ELASTICSEARCH_PORT required"ELASTICSEARCH_HOSTS="\"$ELASTICSEARCH_HOST:$ELASTICSEARCH_PORT\""ficat >> $FILEBEAT_CONFIG << EOF$(base)output.elasticsearch:hosts: [$ELASTICSEARCH_HOSTS]index: ${ELASTICSEARCH_INDEX:-filebeat}-%{+yyyy.MM.dd}${ELASTICSEARCH_SCHEME:+protocol: ${ELASTICSEARCH_SCHEME}}${ELASTICSEARCH_USER:+username: ${ELASTICSEARCH_USER}}${ELASTICSEARCH_PASSWORD:+password: ${ELASTICSEARCH_PASSWORD}}${ELASTICSEARCH_WORKER:+worker: ${ELASTICSEARCH_WORKER}}${ELASTICSEARCH_PATH:+path: ${ELASTICSEARCH_PATH}}${ELASTICSEARCH_BULK_MAX_SIZE:+bulk_max_size: ${ELASTICSEARCH_BULK_MAX_SIZE}}EOF}default() {echo "use default output"cat >> $FILEBEAT_CONFIG << EOF$(base)output.console:pretty: ${CONSOLE_PRETTY:-false}EOF}file() {assert_not_empty "$FILE_PATH" "FILE_PATH required"cat >> $FILEBEAT_CONFIG << EOF$(base)output.file:path: $FILE_PATH${FILE_NAME:+filename: ${FILE_NAME}}${FILE_ROTATE_SIZE:+rotate_every_kb: ${FILE_ROTATE_SIZE}}${FILE_NUMBER_OF_FILES:+number_of_files: ${FILE_NUMBER_OF_FILES}}${FILE_PERMISSIONS:+permissions: ${FILE_PERMISSIONS}}EOF}logstash() {assert_not_empty "$LOGSTASH_HOST" "LOGSTASH_HOST required"assert_not_empty "$LOGSTASH_PORT" "LOGSTASH_PORT required"cat >> $FILEBEAT_CONFIG << EOF$(base)output.logstash:hosts: ["$LOGSTASH_HOST:$LOGSTASH_PORT"]index: ${FILEBEAT_INDEX:-filebeat}-%{+yyyy.MM.dd}${LOGSTASH_WORKER:+worker: ${LOGSTASH_WORKER}}${LOGSTASH_LOADBALANCE:+loadbalance: ${LOGSTASH_LOADBALANCE}}${LOGSTASH_BULK_MAX_SIZE:+bulk_max_size: ${LOGSTASH_BULK_MAX_SIZE}}${LOGSTASH_SLOW_START:+slow_start: ${LOGSTASH_SLOW_START}}EOF}redis() {assert_not_empty "$REDIS_HOST" "REDIS_HOST required"assert_not_empty "$REDIS_PORT" "REDIS_PORT required"cat >> $FILEBEAT_CONFIG << EOF$(base)output.redis:hosts: ["$REDIS_HOST:$REDIS_PORT"]key: "%{[fields.topic]:filebeat}"${REDIS_WORKER:+worker: ${REDIS_WORKER}}${REDIS_PASSWORD:+password: ${REDIS_PASSWORD}}${REDIS_DATATYPE:+datatype: ${REDIS_DATATYPE}}${REDIS_LOADBALANCE:+loadbalance: ${REDIS_LOADBALANCE}}${REDIS_TIMEOUT:+timeout: ${REDIS_TIMEOUT}}${REDIS_BULK_MAX_SIZE:+bulk_max_size: ${REDIS_BULK_MAX_SIZE}}EOF}kafka() {assert_not_empty "$KAFKA_BROKERS" "KAFKA_BROKERS required"KAFKA_BROKERS=$(echo $KAFKA_BROKERS|awk -F, '{for(i=1;i<=NF;i++){printf "\"%s\",", $i}}')KAFKA_BROKERS=${KAFKA_BROKERS%,}cat >> $FILEBEAT_CONFIG << EOF$(base)output.kafka:hosts: [$KAFKA_BROKERS]topic: '%{[topic]}'codec.format:string: '%{[message]}'${KAFKA_VERSION:+version: ${KAFKA_VERSION}}${KAFKA_USERNAME:+username: ${KAFKA_USERNAME}}${KAFKA_PASSWORD:+password: ${KAFKA_PASSWORD}}${KAFKA_WORKER:+worker: ${KAFKA_WORKER}}${KAFKA_PARTITION_KEY:+key: ${KAFKA_PARTITION_KEY}}${KAFKA_PARTITION:+partition: ${KAFKA_PARTITION}}${KAFKA_CLIENT_ID:+client_id: ${KAFKA_CLIENT_ID}}${KAFKA_METADATA:+metadata: ${KAFKA_METADATA}}${KAFKA_BULK_MAX_SIZE:+bulk_max_size: ${KAFKA_BULK_MAX_SIZE}}${KAFKA_BROKER_TIMEOUT:+broker_timeout: ${KAFKA_BROKER_TIMEOUT}}${KAFKA_CHANNEL_BUFFER_SIZE:+channel_buffer_size: ${KAFKA_CHANNEL_BUFFER_SIZE}}${KAFKA_KEEP_ALIVE:+keep_alive ${KAFKA_KEEP_ALIVE}}${KAFKA_MAX_MESSAGE_BYTES:+max_message_bytes: ${KAFKA_MAX_MESSAGE_BYTES}}${KAFKA_REQUIRE_ACKS:+required_acks: ${KAFKA_REQUIRE_ACKS}}EOF}count(){cat >> $FILEBEAT_CONFIG << EOF$(base)output.count:EOF}if [ -n "$FILEBEAT_OUTPUT" ]; thenLOGGING_OUTPUT=$FILEBEAT_OUTPUTficase "$LOGGING_OUTPUT" inelasticsearch)es;;logstash)logstash;;file)file;;redis)redis;;kafka)kafka;;count)count;;*)defaultesackind: ConfigMap
metadata:name: config5.filebeatnamespace: ns-elastic---
apiVersion: apps/v1
kind: DaemonSet
metadata:name: log-pilot5namespace: ns-elasticlabels:k8s-app: log-pilot5
spec:updateStrategy:type: RollingUpdateselector:matchLabels:k8s-app: log-pilot5template:metadata:labels:k8s-app: log-pilot5spec:tolerations:- key: node-role.kubernetes.io/mastereffect: NoSchedule- effect: NoSchedulekey: ToBeDeletedByClusterAutoscaleroperator: Existscontainers:- name: log-pilot5image: williamguozi/log-pilot-filebeat:containerdimagePullPolicy: IfNotPresentenv:- name: "LOGGING_OUTPUT"valueFrom:configMapKeyRef:name: log-pilot5-configurationkey: logging_output- name: "KAFKA_BROKERS"valueFrom:configMapKeyRef:name: log-pilot5-configurationkey: kafka_brokers- name: "KAFKA_VERSION"valueFrom:configMapKeyRef:name: log-pilot5-configurationkey: kafka_version- name: "KAFKA_USERNAME"valueFrom:configMapKeyRef:name: log-pilot5-configurationkey: kafka_username- name: "KAFKA_PASSWORD"valueFrom:configMapKeyRef:name: log-pilot5-configurationkey: kafka_password- name: "NODE_NAME"valueFrom:fieldRef:fieldPath: spec.nodeNamevolumeMounts:- name: sockmountPath: /var/run/containerd/containerd.sock- name: logsmountPath: /var/log/filebeat- name: statemountPath: /var/lib/filebeat- name: rootmountPath: /hostreadOnly: true- name: localtimemountPath: /etc/localtime- name: config-volumemountPath: /etc/filebeat/config- name: filebeat-tplmountPath: /pilot/filebeat.tplsubPath: filebeat.tpl- name: config-filebeatmountPath: /pilot/config.filebeatsubPath: config.filebeatsecurityContext:capabilities:add:- SYS_ADMINterminationGracePeriodSeconds: 30volumes:- name: sockhostPath:path: /var/run/containerd/containerd.socktype: Socket- name: logshostPath:path: /var/log/filebeattype: DirectoryOrCreate- name: statehostPath:path: /var/lib/filebeattype: DirectoryOrCreate- name: roothostPath:path: /type: Directory- name: localtimehostPath:path: /etc/localtimetype: File- name: config-volumeconfigMap:name: log-pilot5-configurationitems:- key: kafka_topicspath: kafka_topics- name: filebeat-tplconfigMap:name: filebeat5-tpl- name: config-filebeatconfigMap:name: config5.filebeatdefaultMode: 0777
3、部署测试用的tomcat服务
vim tomcat-test.yaml
apiVersion: apps/v1
kind: Deployment
metadata:labels:app: tomcatname: tomcat
spec:replicas: 1selector:matchLabels:app: tomcattemplate:metadata:labels:app: tomcatspec:tolerations:- key: "node-role.kubernetes.io/master"effect: "NoSchedule"containers:- name: tomcatimage: "tomcat:7.0"env: # 注意点一,添加相应的环境变量(下面收集了两块日志1、stdout 2、/usr/local/tomcat/logs/catalina.*.log)- name: aliyun_logs_tomcat-syslog # 如日志发送到es,那index名称为 tomcat-syslogvalue: "stdout"- name: aliyun_logs_tomcat-access # 如日志发送到es,那index名称为 tomcat-accessvalue: "/usr/local/tomcat/logs/catalina.*.log"volumeMounts: # 注意点二,对pod内要收集的业务日志目录需要进行共享,可以收集多个目录下的日志文件- name: tomcat-logmountPath: /usr/local/tomcat/logsvolumes:- name: tomcat-logemptyDir: {}
4、部署es 和 kibana
这里的elasticsearch和kibana服务我们就用上节课部署的服务接着使用即可
第25关 利用operator部署生产级别的Elasticserach集群和kibana
5、部署 filebeat 服务
---
apiVersion: v1
kind: ConfigMap
metadata:name: filebeat-config-test
data:filebeat.yml: |filebeat.inputs:- type: kafkahosts: ["10.0.1.201:9092"]topics: ["tomcat-syslog"]group_id: "filebeat"#username: "$ConnectionString"#password: "<your connection string>"ssl.enabled: falsefilebeat.shutdown_timeout: 30soutput:elasticsearch:enabled: truehosts: ['quickstart-es-http.es:9200']username: elasticpassword: 5e84VTJBPO3H84Ec5xt43fc3indices:- index: "test-%{+yyyy.MM.dd}"logging.level: info---apiVersion: apps/v1
kind: Deployment
metadata:labels:app-name: filebeatname: filebeat-test
spec:replicas: 1selector:matchLabels:app-name: filebeattemplate:metadata:labels:app-name: filebeatspec:containers:- command:- filebeat- -e- -c- /etc/filebeat.ymlenv:- name: TZvalue: Asia/Shanghaiimage: docker.io/elastic/filebeat:8.11.3imagePullPolicy: IfNotPresentname: filebeatresources:limits:cpu: 100mmemory: 200Mrequests:cpu: 100mmemory: 200MvolumeMounts:- mountPath: /etc/filebeat.ymlname: filebeat-configsubPath: filebeat.ymlvolumes:- configMap:defaultMode: 420name: filebeat-config-testname: filebeat-config
相关文章:

第26关 K8s日志收集揭秘:利用Log-pilot收集POD内业务日志文件
------> 课程视频同步分享在今日头条和B站 大家好,我是博哥爱运维。 OK,到目前为止,我们的服务顺利容器化并上了K8s,同时也能通过外部网络进行请求访问,相关的服务数据也能进行持久化存储了,那么接下来…...

芯科科技以卓越的企业发展和杰出的产品创新获得多项殊荣
2023年共获颁全球及囯內近20个行业奖项 Silicon Labs(亦称“芯科科技”)日前在全球半导体联盟(Global Semiconductor Alliance,GSA)举行的颁奖典礼上,再次荣获最受尊敬上市半导体企业奖,这是公…...

计算机视觉基础(11)——语义分割和实例分割
前言 在这节课,我们将学习语义分割和实例分割。在语义分割中,我们需要重点掌握语义分割的概念、常用数据集、评价指标(IoU)以及经典的语义分割方法(Deeplab系列);在实例分割中,需要知…...

CNAS中兴新支点——什么是软件压力测试?软件压力测试工具和流程
一、含义:软件压力测试是一种测试应用程序性能的方法,通过模拟大量用户并发访问,测试应用程序在压力情况下的表现和响应能力。软件压力测试的目的是发现系统潜在的问题,如内存泄漏、线程锁、资源泄漏等,以及在高峰期或…...

jQuery: 整理3---操作元素的内容
1.html("内容") ->设置元素的内容,包含html标签(非表单元素) <div id"html1"></div><div id"html2"></div>$("#html1").html("<h2>上海</h2>") …...

22、商城系统(四):项目jar包配置(重要),网关配置,商品服务基础数据设置
目录 0.重要:整个项目的配置 最外层的pom.xml renren-fast renren-generator xpmall-common xpmall-coupon...

循环链表的学习以及问题汇总
[TOC](循环链表常见的问题) # 问题一: **报错**  **报错原因:**因为没有提前对_tag_CircleListNode重命名为CircleListNode,所以,在定义…...

C++期末复习总结继承
继承是软件复用的一种形式,他是在现有类的基础上建立新类,新类继承了现有类的属性和方法,并且还拥有了其特有的属性和方法,继承的过程称为派生,新建的类称为派生类(子类),原有的成为…...

CloudCanal x Debezium 打造实时数据流动新范式
简述 Debezium 是一个开源的数据订阅工具,主要功能为捕获数据库变更事件发送到 Kafka。 CloudCanal 近期实现了从 Kafka 消费 Debezium 格式数据,将其 同步到 StarRocks、Doris、Elasticsearch、MongoDB、ClickHouse 等 12 种数据库和数仓,…...

Nodejs+Express搭建HTTPS服务
最近开发需要搭建一个https的服务,正好最近在用nodejs和express,于是乎想到就近就使用这两东西来搭建一个https的服务吧。这里搭建过程总共需要两步,第一步生成证书,第二步使用https模块启动服务。 生成自签名证书 这里因为是自…...

设计模式之-策略模式,快速掌握策略模式,通俗易懂的讲解策略模式以及它的使用场景
系列文章目录 设计模式之-6大设计原则简单易懂的理解以及它们的适用场景和代码示列 设计模式之-单列设计模式,5种单例设计模式使用场景以及它们的优缺点 设计模式之-3种常见的工厂模式简单工厂模式、工厂方法模式和抽象工厂模式,每一种模式的概念、使用…...

【leetcode100-019】【矩阵】螺旋矩阵
【题干】 给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。 【思路】 不难注意到,每进行一次转向,都有一行/列被输出(并失效);既然已经失效,那我…...

【计算机视觉中的多视图几何系列】深入浅出理解针孔相机模型
温故而知新,可以为师矣! 一、参考资料 《计算机视觉中的多视图几何-第五章》-Richard Hartley, Andrew Zisserman. 二、针孔模型相关介绍 1. 重要概念 1.1 投影中心/摄像机中心/光心 投影中心称为摄像机中心,也称为光心。投影中心位于一…...

轻量级Python IDE使用(三)——函数
1、函数 1.1、函数的概述 在程序设计中,函数的使用可以提升代码的复用率和可维护性。 系统内建函数pow()进行幂运算: a pow(2,4)自定义函数func() def func(a,b):return a ** b afunc(2,4) print(a)自定义函数func(),功能是输出a的b次幂 1.2、函数的定义 py…...

计算机图形学理论(3):着色器编程
本系列根据国外一个图形小哥的讲解为本,整合互联网的一些资料,结合自己的一些理解。 CPU vs GPU CPU支持: 快速缓存分支适应性高性能 GPU支持: 多个 ALU快速板载内存并行任务的高吞吐量(在每个片段、顶点上执行着色…...

ubuntu20.04安装timeshift最新方法
总结: 现在可以使用如下代码安装 sudo apt-get update sudo apt-get install timeshift原因: 在尝试Timeshift系统备份与还原中的方法时, sudo apt-add-repository -y ppa:teejee2008/ppa运行失败。 更改为以下代码: sudo a…...

小狐狸ChatGPT付费创作系统小程序端开发工具提示打开显示无法打开页面解决办法
最新版2.6.7版下载:https://download.csdn.net/download/mo3408/88656497 很多会员在上传小程序前端时经常出现首页无法打开的情况,错误提示无法打开该页面,不支持打开,这种问题其实就是权限问题,页面是通过调用web-v…...

DQL-基本查询
概念: 1,数据库管理系统一个重要功能就是数据查询,数据查询不应只是简单返回数据库中存储的数据,还应该根据需要对数据进行筛选以及确定数据以什么样的格式显示 2,MySQL提供了功能强大、灵活的语句来实现这些操作 3…...

漏洞复现-红帆OA iorepsavexml.aspx文件上传漏洞(附漏洞检测脚本)
免责声明 文章中涉及的漏洞均已修复,敏感信息均已做打码处理,文章仅做经验分享用途,切勿当真,未授权的攻击属于非法行为!文章中敏感信息均已做多层打马处理。传播、利用本文章所提供的信息而造成的任何直接或者间接的…...

Leetcode 2976. Minimum Cost to Convert String I
Leetcode 2976. Minimum Cost to Convert String I 1. 解题思路2. 代码实现 题目链接:2976. Minimum Cost to Convert String I 1. 解题思路 这道题思路上其实是非常直接的,本质上就是给出有向图之后,求出有向图上任意两点之间的最短距离&…...

ZKP Mathematical Building Blocks (2)
MIT IAP 2023 Modern Zero Knowledge Cryptography课程笔记 Lecture 3: Mathematical Building Blocks (Yufei Zhao) Fiat Shamir heuristic Turn an interactive proof to a non-interactive proofP can simulate V whenever V picks a random valueP can simulate V’s ran…...

blender径向渐变材质-着色编辑器
要点: 1、用纹理坐标中的物体输出连接映射中的矢量输入 2、物体选择一个空坐标,将空坐标延z轴上移一段距离 3、空坐标的大小要缩放到和要添加材质的物体大小保持一致...

2023美团机器人研究院学术年会成功举办
2023年12月19日,深圳市美团机器人研究院学术年会在清华大学深圳国际研究生院成功落下帷幕。会议回顾了研究院成立一年来的进展和成果,并邀请了各界专家共同讨论机器人技术的未来发展趋势。此外,年会期间还举办了首届低空经济智能飞行管理挑战…...

swing快速入门(二十七)
注释很详细,直接上代码 上一篇 新增内容 1.为按钮指定图标 2. 列表框的并列 3.菜单项绑定快捷键 4.控件悬浮提示信息 5.菜单项设置小图标 6.五种布局风格右键选择切换 package swing21_30;import javax.swing.*; import java.awt.*; import java.awt.event.…...

Vue 封装echarts柱状图(Bar)组件
目的:减少重复代码,便于维护 显示效果 组件代码 <template><div class"ldw-data-content-box"><div class"ldw-chilren-box"><div class"title" v-if"title">{{ title }}</div>…...

异常(Java)
1.异常的概念 在 Java 中,将程序执行过程中发生的不正常行为称为异常 。 1.算数异常 System.out.println(10 / 0); // 执行结果 Exception in thread "main" java.lang.ArithmeticException: / by zero 2.数组越界异常 int[] arr {1, 2, 3}; System.out.…...

vue的插槽解析
插槽 好处:组件的内容结构可定制 用slot插槽进行占位 语法: 子组件中通过slot进行占位 理解:父组件,在子组件标签嵌套的内容就会被渲染到slot地方 一、默认插槽 //子组件 <slot>slot插槽</slot> //方法一<slot name"…...

Spring(3)Spring从零到入门 - Spring整合技术及AOP事务管理
Spring(3)Spring从零到入门 - Spring整合技术及AOP事务管理 文章目录 Spring(3)Spring从零到入门 - Spring整合技术及AOP事务管理4 Spring整合技术示例4.1 Spring整合Mybatis4.1.1 Mybatis开发回顾4.1.2 整合Spring分析4.1.3 Spri…...

适配器模式学习
适配器模式(Adapter)将一个类的接口转换成客户希望的另外一个接口。Adapter 模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。 适配器模式分为类适配器模式和对象适配器模式两种,前者类之间的耦合度比后者高,且要…...

NET中使用Identity+CodeFirst+Jwt实现登录、鉴权
目录 前言 一、创建上下文类 1.自定义MyContext上下文类继承IdentityDbContext 2.在Program中添加AddDbContext服务 二、使用Migration数据迁移 1.在控制台中 依次使用add-migration 、updatebase 命令 2.如何修改表名 3.如何自定义字段 三、使用Identity实现登录、修改密码 …...