YoMo边缘流处理框架:基于QUIC协议实现毫秒级实时数据处理

news2026/4/30 6:43:05
1. 项目概述当实时数据处理遇上边缘计算如果你正在构建一个需要处理海量实时数据流的应用比如物联网设备监控、实时金融交易分析或者在线游戏的状态同步你肯定对“低延迟”这三个字有着近乎偏执的追求。传统的中心化数据处理架构数据从终端设备产生经过网络长途跋涉到云端服务器处理完再返回这个往返时间RTT在物理上就存在瓶颈尤其是在跨地域的场景下延迟动辄上百毫秒对于需要毫秒级响应的应用来说这简直是无法接受的。这就是yomorun/yomo这个项目试图解决的核心痛点。简单来说YoMo 是一个为边缘计算场景设计的、面向流式处理的低延迟编程框架。它不是一个简单的消息队列也不是一个传统的微服务框架而是一个将“计算”推向数据产生源头即边缘的运行时和开发套件。它的目标非常明确在数据产生的第一时间就进行处理和反应将端到端的延迟降低到个位数毫秒级别。我第一次接触 YoMo 是在一个车联网的预研项目里。我们需要处理来自车载传感器如摄像头、雷达、GPS的连续数据流进行实时的物体识别和路径规划任何超过 50 毫秒的延迟都可能导致决策失效。当时我们评估了包括 Apache Flink、Kafka Streams 在内的多种方案但它们要么太重部署在资源受限的边缘设备上很吃力要么延迟依然不够极致。直到发现了 YoMo其基于 QUIC 协议的设计和 Go 语言原生支持带来的轻量级特性让我们看到了在边缘侧实现超低延迟实时处理的可能。它适合谁呢我认为主要面向几类开发者一是物联网IoT和后端工程师需要处理海量设备数据并做出实时响应二是对延迟有极致要求的应用开发者如金融科技、在线交互、云游戏等领域三是正在探索边缘计算架构的架构师希望找到一个能简化边缘应用开发、部署和运维的工具链。接下来我会结合自己的实践深入拆解 YoMo 的设计思路、核心细节以及如何用它构建一个真正可用的边缘流处理应用。2. 核心架构与设计哲学拆解要理解 YoMo 为什么快以及它如何简化边缘计算必须深入到其架构设计的骨髓里。它的设计哲学可以概括为“为实时而生为边缘而优”。这不仅仅是一句口号而是贯穿在其每一个技术选型中的具体体现。2.1 为什么是 QUIC 协议而非 TCP这是 YoMo 最引人注目也最核心的设计选择。在绝大多数分布式系统中TCP 是可靠通信的基石。但 YoMo 却选择了相对较新的 QUICQuick UDP Internet Connections协议作为其底层传输层。原因在于TCP 虽然可靠但其固有的“队头阻塞”Head-of-Line Blocking问题在实时流处理中是致命的。想象一下你有一个数据流里面包含了A、B、C三个有序的数据包。如果包B在传输中丢失了TCP 会坚持等待重传的包B到达后才将包C交付给应用层。即使包C早已到达接收端应用也只能干等着。对于实时视频流或传感器数据最新的数据包C远比已经过时的、丢失的数据包B有价值。QUIC 在 UDP 之上实现了可靠传输并且在流级别Stream Level解决了队头阻塞。这意味着即使流1中的一个包丢失了流2、流3的数据仍然可以继续被应用层处理互不干扰。YoMo 利用 QUIC 的这一特性为每一条逻辑数据流建立独立的 QUIC 流确保了流式处理中延迟的确定性和可预测性。注意虽然 QUIC 好处很多但在某些严格的内网环境或旧有防火墙策略下UDP 端口可能被限制。在 PoC概念验证阶段务必确认网络基础设施对 UDP 端口通常是 443的支持情况。2.2 云边协同的编程模型SFN (Stream Function)YoMo 没有采用复杂的 DAG有向无环图来定义拓扑而是提出了一个更简洁的概念Stream Function流函数简称 SFN。你可以把一个 SFN 理解为一个纯粹的数据处理函数它订阅上游的数据流进行处理然后可以将结果发布到下游。整个数据处理管道就是由多个 SFN 串联或并联而成的。这种模型非常契合边缘计算的场景轻量级每个 SFN 功能单一可以用 Go 轻松编写和编译成独立的二进制文件资源占用极小。可组合通过声明式的 YAML 文件YoMo 称之为zipper配置可以灵活地将多个 SFN 组合成一个完整的数据处理流水线。位置透明SFN 可以部署在云端也可以部署在边缘节点。YoMo 框架负责它们之间的网络通信和服务发现。这意味着你可以轻松地将一个过滤逻辑放在靠近设备的边缘网关将复杂的聚合分析放在云中心而无需修改业务代码。这种设计将业务逻辑SFN与部署拓扑解耦让开发者能更专注于数据处理本身而不是繁琐的分布式通信细节。2.3 与同类技术的差异化定位为了避免混淆这里有必要将 YoMo 与几个常见技术做个对比技术栈核心场景延迟水平资源消耗部署复杂度编程模型Apache Flink有状态批流一体处理亚秒级到秒级高需要JVM常驻集群高需要独立集群管理DataStream API / SQLApache Kafka (KStreams)基于日志的流处理毫秒到百毫秒级中高依赖Kafka集群中需维护Kafka拓扑/处理器APIgRPC 自定义通用RPC通信取决于实现低中需自治理服务发现、负载均衡服务定义ProtobufYoMo边缘侧实时流处理亚毫秒到十毫秒级极低Go二进制低框架集成流函数SFN可以看到YoMo 并非要取代 Flink 或 Kafka 在复杂事件处理或大数据领域的地位而是精准地切入了一个细分市场对延迟极度敏感、需要在资源受限的边缘环境进行实时处理的场景。它的优势在于“开箱即用”的低延迟通信能力和极简的云边协同编程模型。3. 从零开始构建你的第一个 YoMo 应用理论说得再多不如动手跑一遍。我们来构建一个经典的“边缘数据清洗与转发”示例。假设我们有一个模拟的温度传感器每秒产生一条数据我们需要在边缘侧过滤掉异常值比如超过100度的离谱数据然后将有效数据实时打印出来并转发到云端进行持久化。3.1 环境准备与项目初始化首先确保你安装了 Go (1.16) 开发环境。YoMo 的安装非常简单# 安装 YoMo 命令行工具用于快速创建项目和运行 SFN go install github.com/yomorun/cli/yomolatest安装后使用yomo version检查是否成功。接下来我们创建一个项目目录并初始化mkdir yomo-temperature-demo cd yomo-temperature-demo # 初始化一个 SFN 项目我们将其命名为 edge-filter yomo init sfn edge-filter这个命令会生成一个标准的 Go module 项目结构其中最关键的文件是app.go这就是我们流函数SFN的入口。同时还会生成一个yomo.yaml配置文件用于描述这个 SFN 的元信息比如它监听的数据标签Tag。3.2 编写边缘过滤流函数SFN打开app.go你会看到一个简单的框架。YoMo 使用一个名为ObserveDataTag的函数来声明本 SFN 关心哪种类型的数据。数据在 YoMo 网络中以“标签Tag”进行路由标签是一个32位整数类似于主题Topic的轻量级标识。我们的目标是处理传感器数据假设我们定义温度数据的标签为0x01。修改app.gopackage main import ( context fmt log github.com/yomorun/yomo github.com/yomorun/yomo/pkg/trace ) // 定义一个结构体来映射我们的温度数据 type SensorData struct { DeviceID string json:device_id Temp float32 json:temp Timestamp int64 json:timestamp } func main() { // 1. 创建一个 SFN并为其命名名字用于服务发现 sfn : yomo.NewStreamFunction(edge-temperature-filter, yomo.WithZipperAddr(localhost:9000), // Zipper 协调器的地址 yomo.WithObserveDataTag(0x01), // 声明监听标签为 0x01 的数据 ) defer sfn.Close() // 2. 设置数据处理回调函数 sfn.SetHandler(handler) // 3. 连接到 YoMo 网络并开始工作 err : sfn.Connect() if err ! nil { log.Fatalf([edge-filter] connect error: %v, err) } // 阻塞等待处理数据 select {} } // 数据处理逻辑 func handler(ctx context.Context, data []byte) (byte, []byte) { // 反序列化数据 var sd SensorData // 这里简化处理实际应用应使用高效的序列化库如 [msgpack](https://github.com/vmihailenco/msgpack) 或 Protobuf // 假设 data 是 JSON 格式 // json.Unmarshal(data, sd) // 为了演示我们模拟解析假设数据就是温度值(float32)的字节表示 if len(data) 4 { return 0x00, nil // 返回 Tag 0 表示丢弃 } // 简单将字节转为 float32 (仅作示例生产环境需严谨) temp : float32(data[0]) float32(data[1])/100.0 // 模拟一个温度值 // 核心过滤逻辑超过100度或低于-20度的数据视为异常丢弃 if temp 100.0 || temp -20.0 { fmt.Printf([边缘过滤] 丢弃异常温度: %.2f°C\n, temp) return 0x00, nil // Tag 0 是系统预留的“空”或“丢弃”标签 } fmt.Printf([边缘过滤] 有效温度: %.2f°C\n, temp) // 将处理后的数据这里我们原样转发也可加工后转发发往下一个环节 // 我们使用一个新的 Tag比如 0x02表示“已清洗的有效数据” // 注意这里直接转发原始数据实际应用中可能会封装新的结构 return 0x02, data }这个handler函数是 SFN 的核心。它接收原始数据[]byte处理后返回两个值第一个是byte类型代表输出数据的标签第二个是[]byte类型代表输出数据本身。返回(0x00, nil)是一种约定俗成的“丢弃数据”的方式。实操心得在真正的生产环境中序列化协议的选择至关重要。JSON 虽然方便调试但序列化/反序列化开销大且报文体积大。YoMo 官方推荐并使用 MessagePack 作为默认的编解码器它在性能和体积上取得了很好的平衡。对于极致性能场景可以考虑 Protobuf 或 FlatBuffers。务必在项目初期统一序列化方案。3.3 编写数据源Source与数据输出Sink仅有 SFN 还不够我们需要有数据产生和最终消费的地方。YoMo 架构中数据源叫Source 最终的数据消费者叫Sink。我们来写一个简单的Source模拟传感器发送数据// 文件mock_source.go package main import ( fmt log math/rand time github.com/yomorun/yomo ) func main() { // 创建一个 Source命名为 temperature-source source : yomo.NewSource(temperature-source, yomo.WithZipperAddr(localhost:9000), ) defer source.Close() // 连接到 Zipper err : source.Connect() if err ! nil { log.Fatalf([source] connect error: %v, err) } ticker : time.NewTicker(500 * time.Millisecond) // 每500毫秒发送一次 defer ticker.Stop() for range ticker.C { // 模拟温度数据大部分正常偶尔产生异常值 var temp float32 if rand.Intn(10) 1 { // 10%的概率产生异常值 temp rand.Float32()*150 50 // 50~200度的异常值 } else { temp rand.Float32()*30 10 // 10~40度的正常值 } // 将温度值转换为字节流这里简化处理 // 实际应使用统一的序列化方法如 msgpack data : []byte{byte(temp), byte((temp - float32(int(temp))) * 100)} fmt.Printf([数据源] 发送温度: %.2f°C\n, temp) // 以 Tag 0x01 发送数据 err source.Write(0x01, data) if err ! nil { log.Printf([source] write error: %v, err) } } }再写一个简单的Sink 来接收经过边缘过滤后的有效数据Tag 0x02// 文件cloud_sink.go package main import ( context fmt log github.com/yomorun/yomo ) func main() { // 创建一个 Sink命名为 cloud-logger sink : yomo.NewSink(cloud-logger, yomo.WithZipperAddr(localhost:9000), yomo.WithObserveDataTag(0x02), // 只接收 Tag 为 0x02 的数据 ) defer sink.Close() // 设置处理器 sink.SetHandler(func(ctx context.Context, data []byte) { // 这里模拟云端处理打印、存入数据库、触发告警等 // 同样需要反序列化 data // var sd SensorData // msgpack.Unmarshal(data, sd) fmt.Printf([云端接收] 收到有效传感器数据原始字节: %v\n, data) // 模拟写入数据库 // db.Insert(sd) }) err : sink.Connect() if err ! nil { log.Fatalf([sink] connect error: %v, err) } fmt.Println(云端 Sink 已启动等待接收数据...) select {} }3.4 使用 Zipper 进行编排与运行现在我们有三个组件Source、SFN和Sink。它们如何协同工作这就需要Zipper。Zipper 是 YoMo 的协调器负责服务发现、数据路由和负载均衡。我们需要一个配置文件来告诉 Zipper 我们的拓扑结构。创建一个zipper.yaml文件name: TemperatureProcessingPipeline host: 0.0.0.0 port: 9000 # 定义工作流 flows: - name: temperature-flow # 数据从 source 发出经过 sfn 处理最终到达 sink # 这个顺序不是严格的执行顺序而是声明了数据的可能路径 # Zipper 会根据 SFN 声明的 ObserveDataTag 和其返回的 Tag 自动路由运行步骤启动 Zipper在终端1运行yomo serve -c ./zipper.yaml。你会看到 Zipper 在 9000 端口启动。启动边缘 SFN在终端2进入edge-filter目录运行go run app.go。启动云端 Sink在终端3运行go run cloud_sink.go。启动数据源在终端4运行go run mock_source.go。观察各个终端的日志你会看到数据源每秒发送数据边缘 SFN 过滤掉异常值并将有效数据打上0x02标签云端 Sink 则只接收到这些有效数据。整个流程中数据通过 QUIC 协议在组件间流动延迟极低。4. 深入核心性能调优与生产级考量让一个 Demo 跑起来只是第一步。要将 YoMo 用于生产环境我们必须关注性能、可靠性和可观测性。4.1 序列化与编解码器优化如前所述handler函数中的[]byte反序列化是性能热点。YoMo 内置了对encoding/gob和github.com/vmihailenco/msgpack的支持。强烈建议使用 MessagePack。首先为你的数据结构实现msgpack.Marshaler和msgpack.Unmarshaler接口或者使用代码生成工具。然后在 SFN 中import github.com/vmihailenco/msgpack/v5 func handler(ctx context.Context, data []byte) (byte, []byte) { var sd SensorData if err : msgpack.Unmarshal(data, sd); err ! nil { log.Printf(解码失败: %v, err) return 0x00, nil } // ... 处理逻辑 ... // 编码返回数据 outData, err : msgpack.Marshal(sd) if err ! nil { return 0x00, nil } return 0x02, outData }对于追求极致性能的场景可以调研github.com/golang/protobuf或github.com/google/flatbuffers。但要注意这可能会增加开发的复杂性和框架的集成成本。4.2 背压Backpressure处理流处理系统中如果下游处理速度跟不上上游生产速度就会产生背压。YoMo 基于 QUIC 协议其流控机制能在传输层提供一定的背压管理。但对于业务层我们仍需注意。在Source的Write方法和 SFN 的handler中这些操作本质上是同步的。如果handler处理太慢会导致上游数据积压。有几种策略异步处理在handler中只做最轻量的过滤和路由将耗时的操作如调用外部 API、复杂计算投递到内存队列或 Go Channel 中由其他 Goroutine 异步处理。但要注意这破坏了数据的顺序性。批量处理修改数据模型让上游Source以微批次Micro-batch的方式发送数据。SFN 的handler一次处理一批数据提升吞吐量但会牺牲一些延迟。动态缩放这是更高级的模式。监控 SFN 的处理延迟或队列长度通过 YoMo 的元数据或外部协调器如 Kubernetes HPA动态增加或减少 SFN 的实例数量。YoMo SFN 是无状态的非常适合水平扩展。4.3 可观测性日志、指标与追踪生产系统没有监控就是“裸奔”。YoMo 集成了 OpenTelemetry可以方便地对接 Jaeger、Zipkin 等分布式追踪系统。在创建 SFN 或 Source 时通过WithTracing选项启用sfn : yomo.NewStreamFunction( edge-filter, yomo.WithZipperAddr(localhost:9000), yomo.WithObserveDataTag(0x01), yomo.WithTracing(jaeger, http://jaeger-collector:14268/api/traces), // 示例 )这会在数据流经的每个环节Source - SFN - ... - Sink自动注入追踪上下文你可以在 Jaeger UI 上看到一个完整请求链路的延迟分解图对于定位性能瓶颈至关重要。此外你需要暴露业务和系统的指标Metrics。可以使用prometheus/client_golang库在 SFN 中自定义指标比如yomo_sfn_processed_total处理数据总量。yomo_sfn_processing_duration_seconds处理耗时直方图。yomo_sfn_error_total处理错误计数。将这些指标通过/metrics端点暴露由 Prometheus 采集再在 Grafana 中绘制仪表盘。4.4 部署与运维Kubernetes 实践YoMo 组件是标准的 Go 二进制文件容器化部署非常简单。为每个 SFN、Source、Sink 编写独立的 Dockerfile。关键在于 Zipper 的部署和高可用。在生产环境中Zipper 应该以 StatefulSet 的方式部署在 Kubernetes 中并配置持久化存储来保存服务注册信息。虽然单个 Zipper 可以管理很多节点但为了消除单点故障需要研究 YoMo 未来对 Zipper 集群的支持或者采用一种主动-被动Active-Passive的故障转移模式例如使用一个共享的存储如 etcd 或 Redis来同步状态前面用 Service 做负载均衡和故障切换。对于 SFN 的部署由于它们是无状态的直接使用 Deployment 即可。利用 Kubernetes 的 Service 和 YoMo 的服务发现SFN 可以动态地加入或离开数据处理流水线。5. 实战避坑常见问题与排查指南在实际使用 YoMo 的过程中我踩过不少坑。这里总结一份常见问题速查表希望能帮你节省时间。问题现象可能原因排查步骤与解决方案SFN 启动后连接 Zipper 失败1. Zipper 未启动或地址端口错误。2. 网络防火墙/策略阻止了 UDP 端口QUIC 使用 UDP。3. Zipper 版本与 SFN 依赖的 yomo 库版本不兼容。1.netstat -tulnp | grep 9000检查 Zipper 端口。2. 使用telnet测试 TCP 端口连通性Zipper 的 QUIC 可能基于某个 TCP 端口做发现具体看日志但主要需确认 UDP 端口是否开放。3. 检查go.mod中github.com/yomorun/yomo的版本尽量保持所有组件版本一致。数据能从 Source 发出但 Sink 收不到1. SFN 的handler返回的 Tag 与 Sink 监听的ObserveDataTag不匹配。2. SFN 的handler在处理中发生 panic 或错误导致数据被丢弃返回了0x00。3. 数据序列化格式不一致Sink 无法解析。1. 在 SFN 中打印handler返回的 Tag 值确认是 Sink 监听的 Tag。2. 在 SFN 的handler开头加defer func() { if r : recover(); r ! nil { log.Printf(panic: %v, r) } }()捕获 panic。仔细检查业务逻辑确保所有路径都有明确的返回值。3. 在 Source、SFN、Sink 中使用完全相同的序列化/反序列化代码块或抽象成公共库。处理延迟忽高忽低不稳定1.handler函数中有阻塞操作如同步网络 I/O、文件 I/O。2. Go 垃圾回收GC导致的 “Stop the World” 停顿。3. 宿主机资源CPU、内存不足或被其他进程抢占。1. 使用pprof进行性能剖析 (import _ net/http/pprof)定位耗时最长的函数。将阻塞操作异步化。2. 设置GODEBUGgctrace1环境变量观察 GC 日志。考虑优化代码减少内存分配如使用sync.Pool复用对象。3. 使用docker stats或kubectl top监控容器资源使用情况为容器设置合理的资源请求和限制。在 Kubernetes 中Pod 间通信失败1. Kubernetes Service 名称或 DNS 解析问题。2. Pod 的 SecurityContext 或网络策略NetworkPolicy限制了 UDP 流量。3. Zipper 的 Service 类型或端口定义错误。1. 在 Pod 内使用nslookup yomo-zipper测试 DNS。使用 ClusterIP 而非 localhost。2. 检查 NetworkPolicy确保允许 Pod 之间在 Zipper 端口如 9000上的 UDP 通信。简化测试时可暂时禁用网络策略。3. 确保 Zipper Service 的spec.ports中正确声明了端口和协议可能需要为 QUIC 特殊处理。Zipper 重启后SFN 无法自动重连或状态丢失1. SFN 没有实现重连逻辑。2. Zipper 是无状态的服务注册信息未持久化。1. YoMo 客户端 SDK 通常内置了重连机制检查日志确认。可在代码中增加一个健康检查循环监测连接状态并尝试重连。2. 目前社区版 Zipper 可能将状态保存在内存中。生产环境需要关注高可用方案或等待支持持久化存储的版本。可以考虑在 Zipper 前使用负载均衡器部署多个 Zipper 实例如果支持。一个关键的调试技巧充分利用 YoMo 的日志。在启动组件时设置环境变量YOMO_LOG_LEVELdebug可以打印出非常详细的网络通信、数据路由和生命周期日志这对于理解数据流向和定位问题至关重要。6. 超越基础高级模式与生态整合当你熟悉了 YoMo 的基础用法后可以探索一些更高级的模式让它融入更广阔的云原生生态。模式一作为 Sidecar 进行数据预处理在 Kubernetes 的 Pod 中你的主容器是一个业务应用它产生日志或指标数据。你可以部署一个 YoMo SFN 作为 Sidecar 容器订阅主容器暴露的数据例如通过 Unix Socket 或共享内存进行实时过滤、聚合、格式化然后通过 YoMo 流高效地发送到远端的监控分析平台。这样业务应用无需集成复杂的 SDK实现了关注点分离。模式二与 Serverless 函数结合YoMo SFN 的轻量性和快速启动特性让它非常类似于 Serverless 函数。你可以将 SFN 部署在像 OpenFaaS 或 Knative 这样的 FaaS 平台上。由 YoMo Source 产生的事件触发 FaaS 平台拉起对应的 SFN 函数进行处理处理完毕后函数实例可以缩容到零极致地利用资源。模式三流式 AI 推理这是边缘计算非常典型的场景。在边缘设备上部署一个 YoMo SFN它订阅摄像头视频流分解为帧图片数据每一帧图片数据到达后SFN 调用一个本地部署的轻量级 AI 模型如 TensorFlow Lite 或 ONNX Runtime 加载的模型进行实时推理如物体检测然后将推理结果如边界框坐标实时发送到云端。YoMo 的低延迟保证了从“看到”到“分析出结果”的响应时间极短。生态整合示例将处理后的数据写入 Kafka 或数据库YoMo Sink 并不一定是终点。你可以在 Sink 的handler中将数据轻松写入任何你需要的系统import ( github.com/segmentio/kafka-go gorm.io/gorm ) func handler(ctx context.Context, data []byte) { var sd SensorData msgpack.Unmarshal(data, sd) // 写入 Kafka kafkaWriter.WriteMessages(ctx, kafka.Message{ Value: data, }) // 同时写入 PostgreSQL db.WithContext(ctx).Create(sd) // 或者发送到 Prometheus Pushgateway // 或者调用一个 Webhook }通过这种方式YoMo 专注于它最擅长的“实时流传输与边缘处理”而将持久化、批量分析等任务交给更专业的后端系统各司其职构建一个健壮的混合数据处理架构。从我个人的实践来看YoMo 最大的价值在于它提供了一种“思维模式”的转变让我们习惯于将计算逻辑拆分成细粒度的流函数并思考每个函数最适合部署在何处——是离数据源最近的边缘还是拥有强大算力的云端。这种架构上的灵活性结合其开箱即用的超低延迟能力在处理实时数据洪流的现代应用中无疑是一把锋利的瑞士军刀。

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

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

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…