【kafka】Golang实现分布式Masscan任务调度系统
要求:
输出两个程序,一个命令行程序(命令行参数用flag)和一个服务端程序。
命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽,然后将消息推送到kafka里面。
服务端程序:
- 从kafka消费者接收扫描任务信息
- 通过调用masscan启动探测任务,获取进度和结果信息,进度写入Redis,结果信息写入Kafka。
- 要求对启动任务、kafka、整理流程进行封装。
- 要求启动2个server端,通过命令行程序下发2个不同网段,可以均匀的分配到2个server上面执行完成。
测试要求:
- 启动两个server端程序。
- 通过命令行程序下发两个任务,IP不一样。
- 看server端程序日志,是否均匀的扫描了两个任务。
前置准备:
安装docker
思路:
1. 系统架构设计
采用生产者-消费者模式:
- 命令行客户端作为生产者,将扫描任务发布到Kafka
- 两个服务端实例作为消费者,从Kafka获取任务并执行
2. 关键组件设计
-
任务表示:
- 使用JSON格式表示扫描任务,包含:
- IP范围(单个IP或CIDR格式)
- 端口范围
- 扫描带宽限制
- 任务状态
- 进度信息
- 使用JSON格式表示扫描任务,包含:
-
Kafka设计:
- 创建一个主题(如
scan-tasks
) - 使用单个分区确保任务顺序性(或根据需求设计分区策略)
- 考虑使用消费者组实现两个服务端的负载均衡
- 创建一个主题(如
-
Redis设计:
- 存储任务进度信息
- 使用Hash结构存储每个任务的进度百分比
- 设置适当的TTL防止数据无限增长
-
服务端负载均衡:
- 两个服务端加入同一个Kafka消费者组
- Kafka会自动将任务均匀分配给两个消费者
3. 执行流程
-
客户端流程:
- 解析命令行参数(IP范围、端口、带宽)
- 验证输入格式
- 创建Kafka生产者
- 将任务发布到Kafka主题
-
服务端流程:
- 初始化Kafka消费者(加入消费者组)
- 初始化Redis连接
- 循环消费任务:
a. 从Kafka获取任务
b. 更新Redis中任务状态为"running"
c. 调用masscan执行扫描:- 构造masscan命令行参数
- 启动masscan进程
- 监控进程输出和退出状态
d. 实时解析masscan输出,更新Redis中的进度
e. 扫描完成后: - 更新Redis中任务状态为"completed"
- 将完整结果发布到另一个Kafka主题(如
scan-result
)
4. 关键技术点
-
Masscan集成:
- 使用
exec.Command
启动masscan进程 - 实时解析masscan的标准输出和错误输出
- 根据输出计算扫描进度
- 使用
-
错误处理:
- 处理无效IP格式
- 处理masscan执行失败
- 处理Kafka/Redis连接问题
-
日志记录:
- 记录服务端操作日志
- 记录任务执行状态变化
- 记录错误信息
5. 测试验证思路
- 启动两个服务端实例
- 使用客户端提交两个不同网段的任务
- 观察:
- 两个服务端的日志输出
- 任务是否被均匀分配(一个服务端处理一个任务)
- 扫描进度是否正确更新
- 最终结果是否正确输出
6. 扩展考虑
-
任务优先级:
- 可以在任务中添加优先级字段
- 服务端根据优先级处理任务
-
任务超时:
- 添加任务超时机制
- 超时后重新分配任务
-
结果存储:
- 可以考虑将结果存入数据库而不仅是Kafka
-
水平扩展:
- 设计支持更多服务端实例的扩展方案
这个设计实现了基本的分布式扫描任务调度系统,核心是利用Kafka的消息队列特性实现任务分发,通过消费者组机制实现负载均衡,使用Redis作为共享状态存储。
实现:
项目结构:

kafka:
consumer
package kafkaimport ("context""errors""fmt""github.com/IBM/sarama""log""sync"
)type MessageHandler func([]byte) errortype SaramaConsumer struct {client sarama.ConsumerGrouphandlers map[string]MessageHandlerready chan boolctx context.Contextcancel context.CancelFuncconsuming sync.WaitGroupmemberId stringgroupId string
}func NewKafkaConsumer(brokers []string, groupId string, topic []string) (*SaramaConsumer, error) {config := sarama.NewConfig()config.Version = sarama.V2_5_0_0 // 使用适当的 Kafka 版本config.Consumer.Offsets.Initial = sarama.OffsetOldest //config.Consumer.Group.Rebalance.GroupStrategies = []sarama.BalanceStrategy{sarama.NewBalanceStrategyRoundRobin()}client, err := sarama.NewConsumerGroup(brokers, groupId, config)if err != nil {return nil, fmt.Errorf("failed to create consumer: %v", err)}ctx, cancelFunc := context.WithCancel(context.Background())return &SaramaConsumer{client: client,handlers: make(map[string]MessageHandler),ready: make(chan bool),ctx: ctx,cancel: cancelFunc,groupId: groupId,}, nil
}func (sc *SaramaConsumer) RegisterHandler(topic string, handler MessageHandler) {sc.handlers[topic] = handler
}func (sc *SaramaConsumer) StartConsuming(topics []string) {sc.consuming.Add(1)go func() {defer sc.consuming.Done()for {if err := sc.client.Consume(sc.ctx, topics, sc); err != nil {if errors.Is(err, sarama.ErrClosedConsumerGroup) {return // 正常关闭}log.Printf("Error from consumer: %v", err)}if sc.ctx.Err() != nil {return}sc.ready = make(chan bool)}}()<-sc.readylog.Println("Sarama consumer up and running!...")
}func (sc *SaramaConsumer) Setup(session sarama.ConsumerGroupSession) error {sc.memberId = session.MemberID()claims := session.Claims()log.Printf("Rebalance: Consumer [%s] SETUP - Assigned partitions: %v",sc.memberId, claims)close(sc.ready)return nil
}
func (sc *SaramaConsumer) Cleanup(session sarama.ConsumerGroupSession) error {claims := session.Claims()log.Printf("Rebalance: Consumer [%s] CLEANUP - Releasing partitions: %v",sc.memberId, claims)return nil
}func (sc *SaramaConsumer) ConsumeClaim(session sarama.ConsumerGroupSession, claim sarama.ConsumerGroupClaim) error {log.Printf("Rebalance: Consumer [%s] STARTED consuming partition %d (offset %d)",sc.memberId, claim.Partition(), claim.InitialOffset())defer log.Printf("Rebalance: Consumer [%s] STOPPED consuming partition %d",sc.memberId, claim.Partition())for message := range claim.Messages() {if handler, ok := sc.handlers[message.Topic]; ok {if err := handler(message.Value); err != nil {log.Printf("Error from consumer: %v", err)}session.MarkMessage(message, "")} else {log.Printf("Error from consumer: %v", message.Topic)}}return nil
}func (sc *SaramaConsumer) Close() error {sc.cancel()sc.consuming.Wait()return sc.client.Close()
}
producer
package kafkaimport ("encoding/json""fmt""github.com/IBM/sarama""log"
)type SaramaProducer struct {producer sarama.SyncProducer
}func NewSaramaProducer(brokers []string) (*SaramaProducer, error) {config := sarama.NewConfig()config.Producer.RequiredAcks = sarama.WaitForAll // 等待所有副本确认config.Producer.Retry.Max = 5 // 重试次数config.Producer.Return.Successes = true // 需要成功交付的返回config.Producer.Partitioner = sarama.NewRoundRobinPartitioner //轮询策略producer, err := sarama.NewSyncProducer(brokers, config)if err != nil {return nil, fmt.Errorf("failed to create Sarama producer: %v", err)}return &SaramaProducer{producer: producer}, nil
}func (sp *SaramaProducer) SendMessage(topic string, value interface{}) error {jsonValue, err := json.Marshal(value)if err != nil {return fmt.Errorf("fail to marshal value: %v", err)}msg := sarama.ProducerMessage{Topic: topic,Value: sarama.ByteEncoder(jsonValue),}partition, offset, err := sp.producer.SendMessage(&msg)if err != nil {return fmt.Errorf("fail to send message: %v", err)}log.Printf("Message sent to partition %d at offset %d\n", partition, offset)return nil
}func (sp *SaramaProducer) Close() error {return sp.producer.Close()
}
main
server
package mainimport ("context""encoding/json""fmt""log""os""os/signal""syscall""time""week/v3/kafka""week/v3/progress""week/v3/scanner""week/v3/task"
)type Server struct {consumer *kafka.SaramaConsumerproducer *kafka.SaramaProducerprogressTracker *progress.ProgressTrackerscanner *scanner.MasscanExecutor
}func NewServer(brokers []string, groupId string, topic []string, redisAddr string) (*Server, error) {consumer, err := kafka.NewKafkaConsumer(brokers, groupId, topic)if err != nil {return nil, fmt.Errorf("failed to create Kafka consumer: %w", err)}producer, err := kafka.NewSaramaProducer(brokers)if err != nil {return nil, fmt.Errorf("failed to create Kafka producer: %w", err)}tracker := progress.NewProgressTracker(redisAddr)return &Server{consumer: consumer,producer: producer,progressTracker: tracker,scanner: scanner.NewMasscanExecutor(),}, nil
}func (s *Server) Start(ctx context.Context) {s.consumer.RegisterHandler("scan-tasks", func(msg []byte) error {var t task.Taskif err := json.Unmarshal(msg, &t); err != nil {return fmt.Errorf("failed to unmarshal task: %v", err)}log.Printf(" Received task: %+v\n", t)// 更新任务开始状态if err := s.progressTracker.UpdateProgress(ctx, t.TaskId, 0); err != nil {return fmt.Errorf("failed to update progress: %v", err)}// 执行 masscan 扫描resultChan, errChan := s.scanner.Execute(ctx, t.IPRange, t.Ports, t.BandWidth)log.Println("Masscan Execute called")select {case results := <-resultChan:log.Printf(" Scan complete. %d results.\n", len(results))for _, result := range results {scanResult := struct {TaskID string `json:"task_id"`scanner.ScanResultTimestamp int64 `json:"timestamp"`}{TaskID: t.TaskId,ScanResult: result,Timestamp: time.Now().Unix(),}// 发到 scan-result topicjsonResult, err := json.Marshal(scanResult)if err != nil {return fmt.Errorf("failed to marshal scan result: %v", err)}if err := s.producer.SendMessage("scan-result", jsonResult); err != nil {log.Printf(" Failed to send scan result to Kafka: %v", err)} else {log.Printf(" Sent scan result: %+v", scanResult)}}// 更新任务完成状态if err := s.progressTracker.UpdateProgress(ctx, t.TaskId, 100); err != nil {return fmt.Errorf("failed to update progress: %v", err)}case err := <-errChan:log.Printf(" Scan error: %v\n", err)// 更新任务失败状态if err := s.progressTracker.UpdateProgress(ctx, t.TaskId, 0); err != nil {return fmt.Errorf("failed to update progress: %v", err)}return fmt.Errorf("processing task failed: %v", err)}return nil})// 启动 Kafka 消费go s.consumer.StartConsuming([]string{"scan-tasks"})log.Println(" Server is running and waiting for tasks...")// 等待退出信号<-ctx.Done()log.Println(" Shutting down...")if err := s.consumer.Close(); err != nil {log.Printf("Error closing consumer: %v", err)}if err := s.producer.Close(); err != nil {log.Printf("Error closing producer: %v", err)}if err := s.progressTracker.Close(); err != nil {log.Printf("Error closing progress tracker: %v", err)}log.Println(" Server shutdown complete")
}func main() {if len(os.Args) < 2 {log.Fatal("Usage: server <consumer-group-id>")}groupID := os.Args[1]brokers := []string{"localhost:9092"}redisAddr := "localhost:6379"server, err := NewServer(brokers, groupID, []string{"scan-tasks"}, redisAddr)if err != nil {log.Fatalf("Failed to create server: %v", err)}// 监听中断信号ctx, cancel := context.WithCancel(context.Background())sigChan := make(chan os.Signal, 1)signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)go func() {<-sigChancancel()}()server.Start(ctx)
}
client
package mainimport ("flag""fmt""log""strings""week/v3/task"
)func main() {ipRange := flag.String("ip", "", "ip地址")ports := flag.String("ports", "", "端口范围,如 80,443")bandwidth := flag.String("bandwidth", "1000", "扫描带宽")kafkaBroker := flag.String("kafka", "localhost:9092", "kafka broker 地址")topic := flag.String("topic", "scan-tasks", "kafka topic")flag.Parse()if *ipRange == "" || *ports == "" {fmt.Println("必须指定 ip 和 ports 参数")flag.PrintDefaults()return}brokers := strings.Split(*kafkaBroker, ",")taskManager, err := task.NewTaskManager(*topic, brokers)if err != nil {log.Fatalf("Failed to create task manager: %v", err)}defer taskManager.Close()taskID, err := taskManager.SubmitTask(*ipRange, *ports, *bandwidth)if err != nil {log.Fatalf("Failed to submit task: %v", err)}fmt.Printf(" Task submitted successfully. Task ID: %s\n", taskID)
}
progress
package progressimport ("context""encoding/json""fmt""github.com/go-redis/redis/v8""time"
)type Progress struct {TaskID string `json:"task_id"`Progress float64 `json:"progress"`Status string `json:"status"`Timestamp int64 `json:"timestamp"`
}type ProgressTracker struct {redisClient *redis.Client
}func NewProgressTracker(redisAddr string) *ProgressTracker {return &ProgressTracker{redisClient: redis.NewClient(&redis.Options{Addr: redisAddr,}),}
}func (pt *ProgressTracker) UpdateProgress(ctx context.Context, taskID string, progress float64) error {p := Progress{Progress: progress,}jsonData, err := json.Marshal(p)if err != nil {return fmt.Errorf("failed to marshal progress: %v", err)}err = pt.redisClient.Set(ctx, taskID, string(jsonData), time.Hour).Err()if err != nil {return fmt.Errorf("failed to update progress tracker: %v", err)}return nil
}func (pt *ProgressTracker) Close() error {return pt.redisClient.Close()
}
scanner
package scannerimport ("bufio""bytes""context""encoding/json""fmt""os/exec"
)type ScanResult struct {IP string `json:"ip"`Port string `json:"port"`Status string `json:"status"`
}type MasscanExecutor struct{}func NewMasscanExecutor() *MasscanExecutor {return &MasscanExecutor{}
}func (me *MasscanExecutor) Execute(ctx context.Context, ipRange, ports, bandWidth string) (<-chan []ScanResult, <-chan error) {resultChan := make(chan []ScanResult)errorChan := make(chan error)go func() {defer close(resultChan)defer close(errorChan)args := []string{"-p", ports,"--rate", bandWidth,"-oJ", "-",ipRange,}cmd := exec.CommandContext(ctx, "masscan", args...)output, err := cmd.CombinedOutput()if err != nil {errorChan <- fmt.Errorf("masscan command error: %v, output: %s", err, string(output))return}// 打印输出用于调试fmt.Printf("masscan output:\n%s\n", string(output))scanner := bufio.NewScanner(bytes.NewReader(output))var results []ScanResultfor scanner.Scan() {line := scanner.Bytes()// 过滤非JSON行if len(line) == 0 || (line[0] != '{' && line[0] != '[') {continue}var r struct {IP string `json:"ip"`Ports []struct {Port int `json:"port"`Status string `json:"status"`} `json:"ports"`}if err := json.Unmarshal(line, &r); err != nil {errorChan <- fmt.Errorf("failed to unmarshal line: %v", err)return}for _, p := range r.Ports {results = append(results, ScanResult{IP: r.IP,Port: fmt.Sprintf("%d", p.Port),Status: p.Status,})}}if err := scanner.Err(); err != nil {errorChan <- fmt.Errorf("scanner error: %v", err)return}resultChan <- results}()return resultChan, errorChan
}
task
package taskimport ("encoding/json""fmt""github.com/IBM/sarama""github.com/google/uuid""strings"
)type Task struct {TaskId string `json:"task_id"`IPRange string `json:"ip_range"`Ports string `json:"ports"`BandWidth string `json:"band_width"`
}type TaskManager struct {producer sarama.SyncProducertopic string
}func NewTaskManager(topic string, brokers []string) (*TaskManager, error) {config := sarama.NewConfig()config.Producer.RequiredAcks = sarama.WaitForAllconfig.Producer.Retry.Max = 5config.Producer.Return.Successes = trueconfig.Producer.Partitioner = sarama.NewRoundRobinPartitionerproducer, err := sarama.NewSyncProducer(brokers, config)if err != nil {return nil, err}return &TaskManager{producer: producer, topic: topic}, nil
}func (tm *TaskManager) SubmitTask(ipRange, ports, bandWidth string) ([]string, error) {ipList := strings.Split(ipRange, ",")var taskIDs []stringfor _, ip := range ipList {task := &Task{TaskId: uuid.New().String(),IPRange: ip, // 这里只发送一个 IPPorts: ports,BandWidth: bandWidth,}jsonTask, err := json.Marshal(task)if err != nil {return nil, fmt.Errorf("failed to marshal task: %v", err)}msg := sarama.ProducerMessage{Topic: tm.topic,Value: sarama.ByteEncoder(jsonTask),}_, _, err = tm.producer.SendMessage(&msg)if err != nil {return nil, fmt.Errorf("failed to send message: %v", err)}taskIDs = append(taskIDs, task.TaskId)}return taskIDs, nil
}func (tm *TaskManager) Close() error {return tm.producer.Close()
}
docker-compose
version: '3.8'services:zookeeper:image: confluentinc/cp-zookeeper:7.5.0container_name: zookeeperports:- "2181:2181"environment:TZ: Asia/ShanghaiZOOKEEPER_CLIENT_PORT: 2181ZOOKEEPER_TICK_TIME: 2000kafka:image: confluentinc/cp-kafka:7.5.0container_name: kafkaports:- "9092:9092"depends_on:- zookeeperenvironment:TZ: Asia/ShanghaiKAFKA_BROKER_ID: 1KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181KAFKA_LISTENERS: PLAINTEXT://0.0.0.0:9092KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1redis:image: redis:7.2container_name: redisports:- "6379:6379"environment:TZ: Asia/Shanghaivolumes:- redis-data:/datavolumes:redis-data:
验证
起两个server端,一个client。先进入docker中起的kafka服务
docker exec -it kafka bash
查看kafka中的topic,在服务端和客户端未开启时,kafka中无topic,启动后注册三个topic。
scan-tasks存放扫描任务,scan-results存放扫描结果,__consumer_offsets存放偏移量
因为要两个server负载平衡,所以topic中要有两个partition,
kafka-topics --alter --bootstrap-server localhost:9092 --topic scan-tasks --partitions 2
kafka-topics --describe --bootstrap-server localhost:9092 --topic scan-tasks
使用命令行工具起两个server端
启动一个client下发命令
服务端能均匀消费信息。
感心趣可以自行查看扫描结果和写入redis的进度。
相关文章:

【kafka】Golang实现分布式Masscan任务调度系统
要求: 输出两个程序,一个命令行程序(命令行参数用flag)和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽,然后将消息推送到kafka里面。 服务端程序: 从kafka消费者接收…...

iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...

TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
【Linux】shell脚本忽略错误继续执行
在 shell 脚本中,可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行,可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令,并忽略错误 rm somefile…...

stm32G473的flash模式是单bank还是双bank?
今天突然有人stm32G473的flash模式是单bank还是双bank?由于时间太久,我真忘记了。搜搜发现,还真有人和我一样。见下面的链接:https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...

springboot 百货中心供应链管理系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,百货中心供应链管理系统被用户普遍使用,为方…...

调用支付宝接口响应40004 SYSTEM_ERROR问题排查
在对接支付宝API的时候,遇到了一些问题,记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...
Linux链表操作全解析
Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表?1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...

智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...
应用升级/灾备测试时使用guarantee 闪回点迅速回退
1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间, 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点,不需要开启数据库闪回。…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

微信小程序之bind和catch
这两个呢,都是绑定事件用的,具体使用有些小区别。 官方文档: 事件冒泡处理不同 bind:绑定的事件会向上冒泡,即触发当前组件的事件后,还会继续触发父组件的相同事件。例如,有一个子视图绑定了b…...
ES6从入门到精通:前言
ES6简介 ES6(ECMAScript 2015)是JavaScript语言的重大更新,引入了许多新特性,包括语法糖、新数据类型、模块化支持等,显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var…...

RocketMQ延迟消息机制
两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数,对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后…...

CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...

docker详细操作--未完待续
docker介绍 docker官网: Docker:加速容器应用程序开发 harbor官网:Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台,用于将应用程序及其依赖项(如库、运行时环…...
java_网络服务相关_gateway_nacos_feign区别联系
1. spring-cloud-starter-gateway 作用:作为微服务架构的网关,统一入口,处理所有外部请求。 核心能力: 路由转发(基于路径、服务名等)过滤器(鉴权、限流、日志、Header 处理)支持负…...

label-studio的使用教程(导入本地路径)
文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...
利用ngx_stream_return_module构建简易 TCP/UDP 响应网关
一、模块概述 ngx_stream_return_module 提供了一个极简的指令: return <value>;在收到客户端连接后,立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量(如 $time_iso8601、$remote_addr 等)&a…...
CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型
CVPR 2025 | MIMO:支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题:MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者:Yanyuan Chen, Dexuan Xu, Yu Hu…...

python打卡day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...

基于FPGA的PID算法学习———实现PID比例控制算法
基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容:参考网站: PID算法控制 PID即:Proportional(比例)、Integral(积分&…...
<6>-MySQL表的增删查改
目录 一,create(创建表) 二,retrieve(查询表) 1,select列 2,where条件 三,update(更新表) 四,delete(删除表…...

大话软工笔记—需求分析概述
需求分析,就是要对需求调研收集到的资料信息逐个地进行拆分、研究,从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要,后续设计的依据主要来自于需求分析的成果,包括: 项目的目的…...
云计算——弹性云计算器(ECS)
弹性云服务器:ECS 概述 云计算重构了ICT系统,云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台,包含如下主要概念。 ECS(Elastic Cloud Server):即弹性云服务器,是云计算…...

51c自动驾驶~合集58
我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留,CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制(CCA-Attention),…...

Prompt Tuning、P-Tuning、Prefix Tuning的区别
一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法
树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作,无需更改相机配置。但是,一…...

Spark 之 入门讲解详细版(1)
1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室(Algorithms, Machines, and People Lab)开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目,8个月后成为Apache顶级项目,速度之快足见过人之处&…...