利用golang_Consul代码实现Prometheus监控目标的注册以及动态发现与配置
文章目录
- 前言
- 一、prometheus发现方式
- 二、监控指标注册架构图
- 三、部分代码展示
- 1.核心思想
- 2.代码目录
- 3、程序入口函数剖析
- 4、settings配置文件
- 5、初始化配置文件及consul
- 6、全局变量
- 7、配置config
- 8、公共方法目录common
- 9、工具目录tools
- 10、service层展示
- 11、命令行参数
- 12、Makefile示例
- 13、脚本示例
- 四、演示效果
- 1、上传代码,并整理xlsx文件
- 2、脚本执行命令
- 2.1 创建go.mod文件并下载标准库
- 2.2 执行构建命令
- 2.3 执行xlsx文件解析为json文件命令
- 2.4 执行获取json文件内容并注册到命令
- 2.5 验证
- 2.6 扩展情况说明
- 总结
前言
在实际产生环境中主要以prometheus监控为主,在使用该监控时,有个很大的问题时,需要手动修改Prometheus.yml文件,将监控指标手动添加进去,当监控指标少的时候,维护和添加都很方便,但是当一套环境中监控指标多大几百个,添加工作繁琐,这时你会想到写个shell脚本,对多个监控指标进行添加,但是你有没有考虑过此时的prometheus.yaml文件的可维护性以及当添加的监控指标越来越多时,prometheus主机的cpu、内存也随之增长,这时你该怎么处理呢?因此,本篇文章带你解决此类问题,准备好开始发车了!!!
一、prometheus发现方式
prometheus主要有以下几种发现方式:1)static_configs: #静态服务发现2)file_sd_configs: #文件服务发现3)dns_sd_configs: DNS #服务发现4)kubernetes_sd_configs: #Kubernetes 服务发现5)consul_sd_configs: Consul #consul服务发现
二、监控指标注册架构图
三、部分代码展示
1.核心思想
1、本代码主要是使用golang、xlsx文件、consul三大部分将整理好的监控指标(主机监控、微服务端口监控、业务接口监控、telegraf组件监控等及部分)通过golang调用consulApi注册到consul中2、xlsx文件中的sheet页必须满足settings.yaml文件中的这部分sheet_name:- "hosts_data"- "service_data"- "serviceurl_data"或者自行定义sheet页名称,同时一定要修改settings.yaml文件中的上述部分,二者必须保持一致3、代码的主要功能就是将整理好的xlsx文件,通过`tools.ProcessExcelFiles(cmdFlags)` 函数将xlsx形式中的文件转换为以json结尾的文件,具体的转换过程看代码即可4、注册到consul时,首先通过json反序列化操作,拿到对应的json数据值,然后对注册到consul中的五大部分(主机、主机探活、业务接口、微服务端口监控、agent组件监控)分别进行相关拼接操作5、当拼接操作结束后,调用tools目录下的函数,并传参,实际tools目录下的函数都是调用了consulAPI进行的注册6、makefile定义了代码的多重操作,但是执行繁琐,因此引入了launch.sh脚本,执行launch.sh xx 即可完成xlsx文件转换、注册功能等
2.代码目录
采用Makefile和launch.sh脚本做到执行代码命令的统一管理
3、程序入口函数剖析
cmd/main.go文件主要是代码的执行入口处,包含配置文件的解析、命令行参数解析、consul初始化、代码的执行入口
package mainimport ("log""import_consul/core"myflags "import_consul/flag""import_consul/global""import_consul/service""import_consul/tools"
)func main() {// 解析命令行参数cmdFlags := myflags.Parse()//读取配置文件core.InitConf()// 初始化Consulif consulClient, err := core.ConsulConnect(); err != nil {log.Fatalf("consul connect failed: %v", err)return} else {// 将初始化的客户端实例赋值给global.ConsulClient,以便全局使用global.ConsulClient = consulClientlog.Println("consul connect success")}//执行execl转json文件tools.ProcessExcelFiles(cmdFlags)//其余代码不在展示~~~~
}
4、settings配置文件
consul:ip: "xx" #conusl主机ipport: xx #consul端口service_name: #consul-web界面中的service目录名- "Host_Status"- "ICMP"- "Telegraf"- "Service_TCP"- "Service_URL"xlsx:xlsxfile_path: "/root/test.xlsx" #xlsx监控指标文件位置sheet_name: #xlsx文件中的sheet页名称- "hostinfo"- "serviceinfo"- "serviceurlInfo"jsonfile: #xlsx文件转为json文件后的保存位置hostjson_path: "/root/jsonfile/host.json" servicejson_path: "/root/jsonfile/service.json"serviceurljson_path: "/root/jsonfile/serviceUrl.json"
5、初始化配置文件及consul
初始化settings.yaml配置文件,主要使用golang的gopkg.in/yaml.v2 标准库,指定yaml文件位置并读取yaml文件进行反序列操作
package coreimport ("log""os""path/filepath""import_consul/config""import_consul/global""gopkg.in/yaml.v2"
)func InitConf() {// 直接构建配置文件的路径ConfigFile := filepath.Join("settings.yaml")c := &config.Config{}yamlConf, err := os.ReadFile(ConfigFile)if err != nil {log.Fatalf("get yamlconf error: %s", err)}err = yaml.Unmarshal(yamlConf, c) //yaml文件反序列化if err != nil {log.Fatalf("config init Unmarsharl: %v", err)}log.Print("config init Unmarsharl success")global.Config = c
}
初始化consul,主要使用github.com/hashicorp/consul/api consul的标准库,创建一个consul客户端对象
package coreimport ("import_consul/global""github.com/hashicorp/consul/api"
)// consul 初始化
func ConsulConnect() (*api.Client, error) {config := api.DefaultConfig()config.Address = global.Config.Consul.URL()if client, err := api.NewClient(config); err != nil {return nil, err} else {return client, nil}
}
6、全局变量
因为文件都已分层处理,为了方便程序间调用相应的文件,因此在此处将Config、consul客户端对象进行全局处理,使用时直接global.Config.xxx 或global.CounsulClient.xxx即可
package globalimport ("import_consul/config""github.com/hashicorp/consul/api"
)var (Config *config.Config //接收读取到的config文件ConsulClient *api.Client //consul客户端
)
7、配置config
主要是根据settings.yaml文件中定义的变量进行结构体配置,enter.go文件是config目录下结构体文件的总入口,与global中的全局变量Config遥相呼应
enter.gopackage config//配置入口初始化 采用结构体type Config struct {Consul Consul `yaml:"consul"`Xlsx Xlsx `yaml:"xlsx"`JsonFile JsonFile `yaml:"jsonfile"`}
consul.go
#consul结构体字段package configimport "fmt"//连接consul的ip、端口type Consul struct {IP string `yaml:"ip"`Port int `yaml:"port"`ServiceName []string `yaml:"service_name"`}func (c *Consul) URL() string {return fmt.Sprintf("%s:%d", c.IP, c.Port)}
其余的结构体不在展示,自行按照settings.yaml编写对应的struct结构体即可
8、公共方法目录common
此目录下的parse_xlsx_common.go文件主要是针对定义的sheet页来做相关操作,使用xlsx标准库获取到对应sheet页中的行、列数,然后循环获取每个表格中的数据,调用 writeJSONToFile()方法,将获取到的数据转换为json形式的文件并保存
package commonimport ("bufio""encoding/json""log""os""github.com/tealeg/xlsx/v3"
)// 处理hostinfo表格
func ParseHostInfo(sheet *xlsx.Sheet, fileName string) error {hostDist := make(map[string][]string)// 从第二行开始遍历(假设第一行是标题行)for rowNumber := 1; rowNumber < sheet.MaxRow; rowNumber++ {row, _ := sheet.Row(rowNumber)ip := row.GetCell(0).String()env := row.GetCell(1).String()hostType := row.GetCell(2).String()productInfo := row.GetCell(3).String()hostDist[ip] = []string{env, hostType, productInfo}}// 将hostDist序列化为JSON并写入文件if err := writeJSONToFile(hostDist, fileName); err != nil {log.Fatalf("ParseHostInfo Failed to write JSON to file: %v", err)}log.Printf("ParseHostInfo Success to write JSON to file: %v", hostDist)return nil//其余代码不在展示~~~~
}
9、工具目录tools
这个目录下主要用于存放实现代码所需要的工具文件,例如:golang解析xlsx文件、读取json文件、创建目录文件、consul注册监控指标文件工具等,如下所示
golang解析xlsx文件
package toolsimport ("fmt""log""sync""import_consul/common"myflags "import_consul/flag""import_consul/global""github.com/tealeg/xlsx/v3"
)//定义xlsx转json所需要的结构体
type ExcelToJson struct {File *xlsx.FileSheet *xlsx.Sheet
}
//创建工厂函数,实例化结构体
func newExcelToJson(filePath, sheetName string) (*ExcelToJson, error) {file, err := xlsx.OpenFile(filePath)if err != nil {log.Fatalf("open xlsx file failed:%v\n", err)return nil, err}log.Printf("open xlsx file success:%s\n", filePath)sheet, ok := file.Sheet[sheetName]if !ok {return nil, fmt.Errorf("sheet %s not found", sheetName)}return &ExcelToJson{File: file, Sheet: sheet}, nil
}// 调用common包中的ParseHostInfo方法 将xlsx中的hostinfo页解析并存到host.json文件中
func (e *ExcelToJson) ParseXLSXHost() error {if err := EnsureDir(global.Config.JsonFile.Hostjson_Path); err != nil {return fmt.Errorf("failed to ensure directory for host json: %w", err)}return common.ParseHostInfo(e.Sheet, global.Config.JsonFile.Hostjson_Path)
}// 处理Execl文件的逻辑函数入口,使用协程和互斥锁,提高执行效率
var mutex sync.Mutex // 声明互斥锁
func ProcessExcelFiles(cmdFlags myflags.CmdFlags) {//创建匿名切片结构体并初始化sheetActions := []struct {Flag boolSheet stringAction func(*ExcelToJson) error}{{cmdFlags.ParseHost, global.Config.Xlsx.SheetName[0], (*ExcelToJson).ParseXLSXHost},}var wg sync.WaitGroup//定义保存error的管道errChan := make(chan error, len(sheetActions))for _, action := range sheetActions {if action.Flag {wg.Add(1)//开启协程go func(action struct {Flag boolSheet stringAction func(*ExcelToJson) error}) {defer wg.Done()e, err := newExcelToJson(global.Config.Xlsx.XlsxFile_Path, action.Sheet)if err != nil {log.Fatalf("实例化ExcelToJson结构体失败,%v\n", err)errChan <- errreturn}if err := action.Action(e); err != nil {errChan <- errreturn}// 示例:安全更新共享资源mutex.Lock() // 在访问共享资源前加锁mutex.Unlock() // 完成后解锁}(action)}}wg.Wait()close(errChan)//循环打印管道中的错误并输出for err := range errChan {if err != nil {log.Fatalf("Error processing sheet: %v", err)}}
}
//其余代码不在展示~~~~
此处更重要的是数据清洗转换,设置好指标注册到consul中Tag标签都展示什么,因为这关系到prometheus采集到数据后,在grafana中怎么对图形进行处理
监控指标向consul注册
package toolsimport ("log""import_consul/global""github.com/hashicorp/consul/api"
)func Add_host(ip, env, HostType, businesscode string) {// 构造服务注册的配置registration := &api.AgentServiceRegistration{ID: global.Config.Consul.ServiceName[0] + ip, // 唯一服务IDName: global.Config.Consul.ServiceName[0], // 服务名称Address: ip,Tags: []string{global.Config.Consul.ServiceName[0]},Meta: map[string]string{"ip": ip,"env": env,"type": HostType,"business_code": businesscode,},}// 调用Consul客户端及consul的注册服务函数Agent().ServiceRegister(registration)if err := global.ConsulClient.Agent().ServiceRegister(registration); err != nil {log.Fatalf("Error registering host with Consul:%v\n", err)return}log.Printf("Host %s registered successfully\n", ip)
}
//其余代码不在展示~~~~
当用上述代码对注册到consul中的相关标签进行清洗转换后,就如下图所示
10、service层展示
通过自定义类型HostInfo,调用tools目录中json文件处理函数ReadJSONFile(),对json文件进行处理,处理完成后,调用tools目录下的Add_host()函数,实现监控指标的注册
package serviceimport ("log""import_consul/global""import_consul/tools"
)// HostInfo 用于映射YAML文件结构
type HostInfo map[string][]string// Host 读取并解析host.yaml,然后添加每个主机
func Host() {var results HostInfoerr := tools.ReadJSONFile(global.Config.JsonFile.Hostjson_Path, &results)if err != nil {log.Fatalf("Error reading adn parsing JSON file: %s,error: %v\n", global.Config.JsonFile.Hostjson_Path, err)}log.Printf("Success reading and parsing JSON file: %s\n", global.Config.JsonFile.Hostjson_Path)for hostIP, info := range results {if len(info) >= 3 {tools.Add_host(hostIP, info[0], info[1], info[2])}}
}
//其余代码不在展示~~~~
11、命令行参数
因为有xlsx文件转换json文件的代码、各监控指标注册consul的代码,每次执行并不需要全部执行,因为引入命令行参数的标准库,想要执行哪些代码,直接编译程序代码,然后./xxx -parseHost=true即可执行对应的代码
package flagimport ("flag"
)// CmdFlags 用于保存命令行参数
type CmdFlags struct {ParseHost bool
}// Parse 解析命令行参数
func Parse() CmdFlags {var cmdFlags CmdFlags//只有parseHost=true时才会执行flag.BoolVar(&cmdFlags.ParseHost, "parseHost", false, "Parse hosts from XLSX and convert to YAML")flag.Parse()return cmdFlags
}
12、Makefile示例
# 定义变量
BINARY_NAME ?= default_app_name #如果BINARY_NAME没有在命令行中指定,则使用default_app_name为默认值GOBUILD=go build -o $(BINARY_NAME) ./cmd
GOCLEAN=go clean
GORUN=go run ./cmd/...
GOGET=go get
CMD=./$(BINARY_NAME)# 默认目标
all: build# 构建二进制文件
build:$(GOBUILD)# 清理构建文件
clean:$(GOCLEAN)rm -f $(BINARY_NAME)# 依赖获取,如果有外部依赖可以使用
#./...: 这是go get命令的参数,指示go get搜索当前目录(以及所有子目录)中的所有Go文件,并分析它们的导入声明
deps:$(GOGET) ./...# 根据需要执行的特定服务,可以添加更多的运行目标
run-execlTohostJson:$(CMD) -parseHost=truerun-execToAllJson:$(CMD) -parseHost=true -parseService=true -parseServiceURL=truerun-host:$(CMD) -registerHost=true//其余的不展示~~~
13、脚本示例
主要将makefile中的指令集中到脚本中,执行方便,不容易出错.前提是服务器必须提前安装好make gcc等基础命令
#!/bin/bash# 检查是否传递了参数
if [ "$#" -lt 1 ]; thenecho "Usage: $0 {build|clean|run|deps|run-execlTohostJson|...|run-all} [BINARY_NAME]"exit 1
fiACTION=$1
BINARY_NAME=${2:-} # 如果提供了第二个参数,使用它作为BINARY_NAME# 获取脚本所在的目录
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"# 推断 Makefile 所在的目录(假设 Makefile 在脚本目录的上一级)
MAKEFILE_DIR="$(dirname "$SCRIPT_DIR")"# nohup.out 文件路径
NOHUP_FILE="$SCRIPT_DIR/nohup.out"# binary_name 文件路径,用于存储和读取 BINARY_NAME
BINARY_NAME_FILE="$SCRIPT_DIR/.binary_name"# 检查 nohup.out 文件是否存在,如果不存在则创建
if [ ! -f "$NOHUP_FILE" ]; thentouch "$NOHUP_FILE"
fi# 如果提供了 BINARY_NAME,则将其保存到文件中
if [ -n "$BINARY_NAME" ]; thenecho "$BINARY_NAME" > "$BINARY_NAME_FILE"
elif [ -f "$BINARY_NAME_FILE" ]; then# 如果没有提供 BINARY_NAME 但文件存在,则从文件中读取BINARY_NAME=$(cat "$BINARY_NAME_FILE")
fi# 根据参数执行相应的 make 命令
case "$ACTION" inbuild)echo "===== Starting $ACTION with BINARY_NAME=$BINARY_NAME at $(date) =====" >> "$NOHUP_FILE"BINARY_NAME=$BINARY_NAME make -C "$MAKEFILE_DIR" $ACTION &>> "$NOHUP_FILE";;clean)# 清理时,需要确保使用之前存储的 BINARY_NAMEif [ -n "$BINARY_NAME" ]; thenecho "===== Cleaning with BINARY_NAME=$BINARY_NAME at $(date) =====" >> "$NOHUP_FILE"BINARY_NAME=$BINARY_NAME make -C "$MAKEFILE_DIR" $ACTION &>> "$NOHUP_FILE"# 清理操作完成后,删除 BINARY_NAME 文件rm -f "$BINARY_NAME_FILE"elseecho "No BINARY_NAME specified or found. Please provide a binary name or run a build first."exit 1fi;;run|deps|run-execlTohostJson|run-registerServices|run-all)echo "===== Starting $ACTION with BINARY_NAME=$BINARY_NAME at $(date) =====" >> "$NOHUP_FILE"BINARY_NAME=$BINARY_NAME make -C "$MAKEFILE_DIR" $ACTION &>> "$NOHUP_FILE";;*)echo "Invalid option: $ACTION"echo "Usage: $0 {build|clean|run|deps|run-execlTohostJson|...|run-all} [BINARY_NAME]"exit 1;;
esac
四、演示效果
1、上传代码,并整理xlsx文件
1、上传代码至prometheus或与pormetheus机器相同的机器2、机器必须已安装golang环境 go>=1.18版本3、整理xlsx文件,xlsx模板如下截图所示
2、脚本执行命令
上传完代码后,cd /xxx/xxx/xxx/ 目录下
2.1 创建go.mod文件并下载标准库
[root@python2 import_consul]# go mod init import_consul
[root@python2 import_consul]# go mod tidy #下载依赖
2.2 执行构建命令
[root@python2 root]# cd scripts
[root@python2 scripts]# ./launch.sh build service_register_consul
2.3 执行xlsx文件解析为json文件命令
第一种: 只解析某一个sheet页[root@python2 scripts]# ./launch.sh run-execlTohostJson
第二种: 解析全部sheet页[root@python2 scripts]# ./launch.sh run-execlToALLJson
2.4 执行获取json文件内容并注册到命令
第一种: 只注册某个监控指标[root@python2 scripts]# ./launch.sh run-host
第二种: 注册全部指标[root@python2 scripts]# ./launch.sh run-registerServices
2.5 验证
1、查看scripts/nphup.out文件中命令执行是否有报错2、查看consul中是否已注册到指标
2.6 扩展情况说明
如下截图所示,显示服务健康检查失败,这是因为我在指标注册到consul的代码中配置了健康检查机制checks,又因为本地开发环境与预发环境的网段不通,所有才会导致健康检查失败,并不是代码是失败的。
指标注册到consul的代码的健康检查 部分代码示例:Check: &api.AgentServiceCheck{TTL: "10s", //心跳检测时间DeregisterCriticalServiceAfter: "5m", // 如果服务1分钟内处于critical状态,则自动注销},
至此,整个代码的演示也就完成了
总结
写这个代码的原因有两个,其一就是我刚开始所说的维护prometheus.yml文件的成本越来越高,且服务器资源日益不足;其二刚才最近在学习golang,也借此机会提高一下golang的基础语法知识以及标准库的使用方法。因此才有此代码的诞生.主要给大家一个思路,像代码中的consul标签处理部分也仅适用于我司,如果要想看源码.见本博客下载即可。
相关文章:

利用golang_Consul代码实现Prometheus监控目标的注册以及动态发现与配置
文章目录 前言一、prometheus发现方式二、监控指标注册架构图三、部分代码展示1.核心思想2.代码目录3、程序入口函数剖析4、settings配置文件5、初始化配置文件及consul6、全局变量7、配置config8、公共方法目录common9、工具目录tools10、service层展示11、命令行参数12、Make…...

Python爬虫介绍
Python 作为一种广泛应用的编程语言,在 Web 开发、大数据开发、人工智能开发和嵌入式开发等领域都有着重要的应用。 Python 的易学性、清晰性和可移植性等特点使它得到很多技术人士的喜爱。对于数据科学和机器学习领域的程序员来说,Python 提供了强大的…...

Linux 进程管理
一、查看进程 使用ps -aux进行查看,其中a表示列出所有进程信息,u以用户格式显示进程信息,x显示后台进程参数,也可以使用| grep 进行进程的筛选 以下是显示进程后的示意 USER为进程执行的用户 PID为进程号 %CPU为该进程的cpu占用…...

【车载测试】CAN协议、CAN- FD协议和FlexRay协议 区别
【上半场电动化,下半场智能化】 一、CAN协议 和 CAN- FD协议的区别 CAN(Controller Area Network)协议是一种广泛用于汽车和工业控制系统等领域的现场总线协议。CAN- FD(Flexible Data Rate)协议是对CAN协议的扩展&am…...

对日期的处理
对日期的处理 对编码进行统一,在脚本最开始: # -*- coding: utf-8 -*-这里涉及到两个操作,一个是将数据进行标准化,比如有些日期是2024/05/06这并不符合日期的标准格式,需要转换成这样的2024-05-06 def tran_std(st…...

赵丽颖纯白茉莉绽放温柔之美
赵丽颖纯白茉莉,绽放温柔之美在这个繁忙喧嚣的娱乐圈,赵丽颖以其独特的魅力,成为了无数人心中的白月光。近日,赵丽颖工作室发布了一组live图,她身着一袭温柔白裙,宛如一朵盛开的纯白茉莉花,美得…...

软考高级论文真题“论湖仓一体架构及其应用”
论文真题 随着5G、大数据、人工智能、物联网等技术的不断成熟,各行各业的业务场景日益复杂,企业数据呈现出大规模、多样性的特点,特别是非结构化数据呈现出爆发式增长趋势。在这一背景下,企业数据管理不再局限于传统的结构化OLTP…...

CentOS系统查看版本的各个命令
cat /etc/centos-release 查看CentOS版本 uname -a 命令的结果分别代表:当前系统的内核名称、主机名、内核发型版本、节点名、系统时间、硬件名称、硬件平台、处理器类型以及操作系统名称 cat /proc/version 命令用于查看Linux内核的版本信息。执行该命令后…...

[保姆级教程]uniapp实现底部导航栏
文章目录 前置准备工作安装HBuilder-X新建uniapp项目教程使用HBuilder-X启动uniapp项目教程 实现底部导航栏package.json中配置导航栏详细配置内容 前置准备工作 安装HBuilder-X 详细步骤可看上文》》 新建uniapp项目教程 详细步骤可看上文》》 使用HBuilder-X启动uniapp项…...

STM32多功能交通灯系统:从原理到实现
一、功能说明 本交通灯系统采用先进的stm32f103c8t6微处理器为核心控制单元。系统设置东南西北四个方向各配置两位数码管,用以精准展示5至99秒的时间范围,并且允许用户根据实际需求进行灵活调整。 在信号灯配置方面,每个方向均配备左转、直…...

Pip换源秘籍:让你的Python包飞行起来!
在Python的包管理中,Pip是最重要的工具之一。它允许开发者从Python Package Index (PyPI)安装包,但有时由于网络问题或服务器负载过高,直接从PyPI安装包可能会非常慢。这时,更换Pip源到一个更快的镜像站点是一个常见的解决方案。本…...

Flutter TIM 项目配置
目录 1. 设计说明 2. 参考资料索引 Flutter SDK 服务端 Rest API 腾讯后台 其他 3. TIM 整体架构 第一部分:APP 端 第二部分:腾讯服务器 第三部分:三方服务 第四部分:你自己的服务器 4. TIM SDK 集成 TUIK 含 UI 集成…...

【深海王国】小学生都能玩的单片机?零基础入门单片机Arduino带你打开嵌入式的大门!(8)
Hi٩(๑o๑)۶, 各位深海王国的同志们,早上下午晚上凌晨好呀~辛勤工作的你今天也辛苦啦 (o゜▽゜)o☆ 今天大都督继续为大家带来系列——小学生都能玩的单片机!带你一周内快速走进嵌入式的大门,let’s go! (8&#x…...
第5天:视图与模板进阶
第5天:视图与模板进阶 目标 掌握视图逻辑和模板渲染,包括不同类型的视图、自定义模板标签和过滤器,以及模板继承和包含的概念。 任务概览 学习函数视图和类视图的使用。编写自定义模板标签和过滤器。理解模板的继承和包含机制。 详细步骤…...

线程间通信方式(互斥(互斥锁)与同步(无名信号量、条件变量))
1通信机制:互斥与同步 线程的互斥通过线程的互斥锁完成; 线程的同步通过无名信号量或者条件变量完成。 2 互斥 2.1 何为互斥? 互斥是在多个线程在访问同一个全局变量的时候,先让这个线程争抢锁的资源,那个线程争抢…...
Android使用data uri启动activity或service
设定AndroidManifest.xml 在AndroidManifest.xml文件中,我们可以设定activity或service的data。 <!-- activity定义方式 --> <activityandroid:name".page.main.MainActivity"><intent-filter><action android:name"an…...

能理解你的意图的自动化采集工具——AI和爬虫相结合
⭐️我叫忆_恒心,一名喜欢书写博客的研究生👨🎓。 如果觉得本文能帮到您,麻烦点个赞👍呗! 近期会不断在专栏里进行更新讲解博客~~~ 有什么问题的小伙伴 欢迎留言提问欧,喜欢的小伙伴给个三连支…...

基于SpringBoot+大数据城市景观画像可视化设计和实现
💗博主介绍:✌全网粉丝10W,CSDN作者、博客专家、全栈领域优质创作者,博客之星、平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌💗 🌟文末获取源码数据库🌟 感兴趣的可以先收藏起来,…...
Oracle表中的数据量达到30万条
当Oracle表中的数据量达到30万条,并且查询性能过慢时,增加索引是一个有效的优化方案。以下是一些建议来增加索引以提高查询性能: 分析查询需求: 首先,需要明确哪些查询是经常执行的,以及这些查询的WHERE子…...

【python】python学生成绩数据分析可视化(源码+数据+论文)【独一无二】
👉博__主👈:米码收割机 👉技__能👈:C/Python语言 👉公众号👈:测试开发自动化【获取源码商业合作】 👉荣__誉👈:阿里云博客专家博主、5…...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...

centos 7 部署awstats 网站访问检测
一、基础环境准备(两种安装方式都要做) bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats࿰…...
Python爬虫实战:研究feedparser库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...

Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...

MySQL 8.0 OCP 英文题库解析(十三)
Oracle 为庆祝 MySQL 30 周年,截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始,将英文题库免费公布出来,并进行解析,帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...

分布式增量爬虫实现方案
之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面,避免重复抓取,以节省资源和时间。 在分布式环境下,增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路:将增量判…...
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问(基础概念问题) 1. 请解释Spring框架的核心容器是什么?它在Spring中起到什么作用? Spring框架的核心容器是IoC容器&#…...

人机融合智能 | “人智交互”跨学科新领域
本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...

push [特殊字符] present
push 🆚 present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中,push 和 present 是两种不同的视图控制器切换方式,它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...