乐闻世界logo
搜索文章和话题

服务端面试题手册

MQTT 的发布/订阅模式是如何工作的?

MQTT 的发布/订阅模式是一种消息传递架构,它解耦了消息的生产者和消费者,实现了灵活的一对多通信。核心概念1. 主题(Topic)定义:主题是消息的路由地址,采用层级结构格式:使用斜杠(/)分隔的字符串,如 home/livingroom/temperature特点:层级清晰,便于组织和管理支持通配符订阅大小写敏感长度限制:最多 65535 字节2. 发布者(Publisher)角色:消息的生产者功能:向特定主题发送消息特点:不需要知道订阅者的存在可以同时向多个主题发布消息发布后立即返回,不等待订阅者响应3. 订阅者(Subscriber)角色:消息的消费者功能:订阅感兴趣的主题,接收相关消息特点:可以订阅多个主题可以使用通配符订阅一类主题只接收订阅后发布的消息4. Broker(代理服务器)角色:消息的中转站和路由器功能:接收发布者发送的消息根据订阅关系将消息分发给订阅者管理客户端连接和会话处理消息的 QoS 保证工作流程连接建立:客户端(发布者/订阅者)连接到 Broker订阅主题:订阅者向 Broker 发送订阅请求发布消息:发布者向特定主题发送消息消息路由:Broker 接收消息,查找订阅该主题的客户端消息分发:Broker 将消息转发给所有订阅者消息接收:订阅者接收并处理消息通配符订阅单级通配符(+)匹配单个层级示例:home/+/temperature 匹配 home/livingroom/temperature,但不匹配 home/livingroom/kitchen/temperature多级通配符(#)匹配多个层级,必须放在主题末尾示例:home/# 匹配 home/ 下的所有主题优势解耦性:发布者和订阅者完全解耦,互不依赖灵活性:支持一对多、多对一、多对多的通信模式可扩展性:易于添加新的发布者和订阅者异步性:发布者不需要等待订阅者响应高效性:Broker 负责消息路由,减少网络开销与点对点模式的对比| 特性 | 发布/订阅模式 | 点对点模式 ||-----|-------------|-----------|| 耦合度 | 低 | 高 || 消息接收者 | 多个 | 一个 || 消息持久化 | 可选 | 通常需要 || 复杂度 | 中等 | 简单 || 适用场景 | 广播、通知 | 直接通信 |MQTT 的发布/订阅模式使其成为物联网、实时通信和消息推送等场景的理想选择。
阅读 0·2月21日 15:45

MQTT 的保留消息(Retained Messages)是什么?如何使用?

MQTT 的保留消息(Retained Messages)是一种特殊的消息机制,允许 Broker 保存最新消息,供新订阅者接收。保留消息的概念定义保留消息是 Broker 持久化存储的消息,当有新的客户端订阅该主题时,Broker 会立即将保留消息发送给该客户端。作用状态同步:新订阅者可以立即获取最新状态初始化数据:为新连接的客户端提供初始数据状态恢复:帮助客户端快速恢复到最新状态减少请求:避免客户端主动请求最新状态保留消息的工作原理设置保留消息发布消息时设置 Retain 标志:PUBLISH 报文参数:- Topic: 主题名称- Payload: 消息内容- QoS: QoS 级别- Retain: true(设置为保留消息)保留消息的存储存储位置:Broker 内存或持久化存储存储数量:每个主题只保留一条最新消息存储覆盖:新发布的保留消息会覆盖之前的保留消息保留消息的发送当客户端订阅主题时:客户端发送 SUBSCRIBE 报文Broker 检查该主题是否有保留消息如果有,立即发送保留消息给客户端然后发送后续的新消息保留消息的特性1. 每个主题一条规则:每个主题只保留一条最新的保留消息覆盖机制:新发布的保留消息会替换之前的清除机制:发布空消息(Payload 为空)可以清除保留消息2. QoS 级别继承性:保留消息的 QoS 级别由发布时决定订阅限制:订阅者接收的 QoS 级别受限于订阅时的 QoS 设置QoS 规则:实际 QoS = min(发布 QoS, 订阅 QoS)3. 持久化内存存储:默认存储在内存中持久化存储:可配置持久化到磁盘Broker 重启:持久化的保留消息在 Broker 重启后仍然存在4. 消息顺序发送顺序:保留消息在普通消息之前发送订阅时机:只在订阅时发送一次后续消息:不重复发送保留消息使用场景1. 设备状态同步场景:温度传感器保留主题:sensor/123/temperature保留消息:{"value": 25.5, "unit": "C", "timestamp": 1234567890}新订阅者订阅 sensor/123/temperature立即收到最新温度值2. 配置信息发布场景:设备配置保留主题:config/device/123保留消息:{"mode": "auto", "interval": 60}新设备上线订阅配置主题立即获取最新配置3. 系统状态广播场景:系统状态保留主题:system/status保留消息:{"status": "running", "version": "1.0.0"}新客户端订阅系统状态立即获取当前系统状态4. 开关状态场景:智能开关保留主题:switch/123/state保留消息:{"state": "on"}新订阅者立即获取开关状态代码示例Python (paho-mqtt)import paho.mqtt.client as mqttimport jsonimport timedef on_connect(client, userdata, flags, rc): print(f"Connected with result code {rc}") # 订阅主题 client.subscribe("sensor/+/temperature")def on_message(client, userdata, msg): print(f"Received: {msg.topic} - {msg.payload.decode()}") print(f"Retained: {msg.retain}")# 发布保留消息client = mqtt.Client()client.connect("broker.example.com", 1883, 60)# 发布保留消息(retain=True)message = {"value": 25.5, "unit": "C", "timestamp": int(time.time())}client.publish("sensor/123/temperature", json.dumps(message), retain=True)# 清除保留消息(发布空消息)# client.publish("sensor/123/temperature", "", retain=True)client.disconnect()# 订阅者subscriber = mqtt.Client()subscriber.on_connect = on_connectsubscriber.on_message = on_messagesubscriber.connect("broker.example.com", 1883, 60)subscriber.loop_forever()JavaScript (MQTT.js)const mqtt = require('mqtt');// 发布保留消息const publisher = mqtt.connect('mqtt://broker.example.com');publisher.on('connect', () => { console.log('Publisher connected'); // 发布保留消息(retain: true) const message = JSON.stringify({ value: 25.5, unit: 'C', timestamp: Date.now() }); publisher.publish('sensor/123/temperature', message, { retain: true }); // 清除保留消息(发布空消息) // publisher.publish('sensor/123/temperature', '', { retain: true }); publisher.end();});// 订阅者const subscriber = mqtt.connect('mqtt://broker.example.com');subscriber.on('connect', () => { console.log('Subscriber connected'); subscriber.subscribe('sensor/+/temperature');});subscriber.on('message', (topic, message) => { console.log(`Received: ${topic} - ${message.toString()}`); console.log(`Retained: ${message.retain}`);});最佳实践1. 保留消息设计状态信息:保留消息应该表示当前状态简洁明了:消息内容简洁,易于解析包含时间戳:便于判断消息的新旧程度版本控制:可以包含版本信息2. 主题命名推荐格式:- sensor/{device_id}/temperature- config/{device_id}- status/{system_id}避免使用:- 通配符主题(不能发布到通配符主题)- 过于复杂的主题结构3. 消息大小限制大小:保留消息不宜过大建议大小:通常小于 1KBBroker 限制:注意 Broker 对消息大小的限制4. QoS 选择一般状态:QoS 0重要状态:QoS 1关键状态:QoS 25. 清除机制主动清除:发布空消息清除保留消息定期清理:定期检查和清理过期的保留消息生命周期管理:为保留消息设置合理的生命周期注意事项内存占用:保留消息会占用 Broker 内存,大量保留消息可能影响性能持久化配置:如果需要保留消息在 Broker 重启后仍然存在,需要配置持久化消息更新:频繁更新保留消息会增加 Broker 负担订阅时机:保留消息只在订阅时发送,不会重复发送QoS 限制:订阅者接收的 QoS 级别受限于订阅时的 QoS 设置空消息清除:发布空消息(Payload 为空)可以清除保留消息保留消息 vs 遗嘱消息| 特性 | 保留消息 | 遗嘱消息 ||-----|---------|---------|| 触发时机 | 订阅时 | 异常断开时 || 消息来源 | 发布者设置 | 客户端设置 || 存储位置 | Broker | Broker || 发送对象 | 新订阅者 | 订阅该主题的客户端 || 消息数量 | 每主题一条 | 每客户端一条 || 清除方式 | 发布空消息 | 正常断开或重新连接 |保留消息的局限性每主题一条:每个主题只能保留一条消息,无法保存历史消息内存占用:大量保留消息会占用较多内存实时性:保留消息可能不是最新的(取决于发布频率)无历史记录:无法获取历史状态变化依赖 Broker:完全依赖 Broker 的可靠性MQTT 保留消息是物联网应用中非常重要的机制,合理使用可以有效实现状态同步和初始化,提高用户体验和系统可靠性。
阅读 0·2月21日 15:44

Ollama 与其他 LLM 部署方案(如 vLLM、LM Studio)相比有什么优缺点?

Ollama 与其他 LLM 部署方案相比,各有优劣:1. Ollama vs. vLLM:Ollama 优势:安装简单,一行命令即可部署跨平台支持(Linux/macOS/Windows)内置模型管理和 API 服务适合个人开发和小型应用vLLM 优势:更高的推理性能和吞吐量支持 PagedAttention 技术更适合大规模生产环境支持更多模型格式2. Ollama vs. LM Studio:Ollama 优势:命令行和 API 友好更适合服务器部署开源且免费更好的自动化集成LM Studio 优势:图形化界面,用户体验好内置模型市场适合桌面用户可视化配置选项3. Ollama vs. OpenAI API:Ollama 优势:完全本地运行,数据隐私保护无 API 调用费用可自定义模型无网络依赖OpenAI API 优势:模型性能更强(GPT-4 等)无需本地硬件持续更新和优化更好的多语言支持4. Ollama vs. LocalAI:Ollama 优势:更轻量级更简单的配置更好的性能优化活跃的社区支持LocalAI 优势:OpenAI API 兼容性更好支持更多模型类型更灵活的配置选项支持多模型并行5. Ollama vs. Text Generation WebUI:Ollama 优势:更适合 API 集成更简单的部署更好的性能命令行友好Text Generation WebUI 优势:功能丰富的 Web 界面支持更多高级功能可视化参数调整更好的交互体验选择建议:个人开发/学习:Ollama 或 LM Studio生产环境 API 服务:Ollama 或 vLLM需要 OpenAI 兼容性:LocalAI桌面用户:LM Studio需要最高性能:vLLM需要图形界面:LM Studio 或 Text Generation WebUI
阅读 0·2月21日 15:43

Gin 框架的性能优化技巧和最佳实践有哪些?

Gin 框架的性能优化技巧和最佳实践如下:1. 路由优化1.1 路由分组// 合理使用路由组,减少重复前缀api := r.Group("/api/v1"){ users := api.Group("/users") { users.GET("", getUsers) users.GET("/:id", getUser) users.POST("", createUser) }}1.2 路由顺序将高频路由放在前面静态路由优先于动态路由避免路由冲突1.3 减少路由嵌套避免过深的路由层级合理规划路由结构2. 中间件优化2.1 中间件选择// 只在需要的路由上添加中间件r.GET("/public/data", getData) // 不需要认证r.GET("/private/data", authMiddleware(), getPrivateData) // 需要认证2.2 中间件逻辑优化保持中间件逻辑轻量避免在中间件中进行阻塞操作使用缓存减少重复计算2.3 中间件顺序将性能影响小的中间件放在前面将可能中断请求的中间件放在前面3. 数据绑定优化3.1 使用明确的绑定方法// 推荐:使用明确的绑定方法c.ShouldBindJSON(&obj)// 不推荐:使用通用绑定方法c.ShouldBind(&obj)3.2 避免过度验证只验证必要的字段使用合理的验证规则4. 数据库优化4.1 连接池配置db.SetMaxOpenConns(100)db.SetMaxIdleConns(10)db.SetConnMaxLifetime(time.Hour)4.2 查询优化使用索引避免 N+1 查询合理使用缓存5. 响应优化5.1 启用压缩import "github.com/gin-contrib/gzip"r.Use(gzip.Gzip(gzip.DefaultCompression))5.2 流式响应// 对于大数据量,使用流式响应c.Stream(func(w io.Writer) bool { // 写入数据 w.Write(data) return true // 继续写入})5.3 合理设置缓存头c.Header("Cache-Control", "public, max-age=3600")6. 并发优化6.1 使用 goroutine 池// 使用 worker pool 处理并发任务type WorkerPool struct { tasks chan func()}func (p *WorkerPool) Submit(task func()) { p.tasks <- task}6.2 避免阻塞操作将阻塞操作放到 goroutine 中使用 context 控制超时7. 内存优化7.1 对象复用// 使用 sync.Pool 复用对象var bufferPool = sync.Pool{ New: func() interface{} { return new(bytes.Buffer) },}7.2 避免内存泄漏及时释放资源避免在 Context 中存储大量数据使用 defer 确保资源释放8. 日志优化8.1 异步日志// 使用异步日志记录logger := log.New(os.Stdout, "", log.LstdFlags)go func() { for entry := range logChannel { logger.Println(entry) }}()8.2 合理的日志级别生产环境使用 INFO 或 WARN 级别开发环境使用 DEBUG 级别9. 监控和性能分析9.1 使用 pprofimport _ "net/http/pprof"go func() { log.Println(http.ListenAndServe("localhost:6060", nil))}()9.2 添加性能指标// 使用 Prometheus 等工具收集指标import "github.com/prometheus/client_golang/prometheus"var requestDuration = prometheus.NewHistogramVec( prometheus.HistogramOpts{ Name: "http_request_duration_seconds", Help: "HTTP request duration in seconds", }, []string{"method", "path"},)10. 最佳实践总结合理使用路由组和中间件启用 gzip 压缩配置数据库连接池使用缓存减少重复计算避免阻塞操作使用对象池减少内存分配异步日志记录添加性能监控定期进行性能测试使用 pprof 分析性能瓶颈通过以上优化技巧,可以显著提升 Gin 应用的性能和稳定性。
阅读 0·2月21日 15:43

Prometheus 的 Recording Rules 和 Alerting Rules 有什么区别?

Prometheus Recording Rules 和 Alerting Rules 的区别和使用:Recording Rules(记录规则):预先计算并存储常用的查询结果提高查询性能,减少计算开销不会触发告警配置示例:groups: - name: api_recording_rules interval: 30s rules: - record: job:http_requests:rate5m expr: sum by (job) (rate(http_requests_total[5m])) - record: job:request_errors:rate5m expr: sum by (job) (rate(http_requests_total{status=~"5.."}[5m]))使用场景:频繁查询的复杂表达式需要聚合多个指标的计算提高仪表盘加载速度减少实时查询压力Alerting Rules(告警规则):监控指标并触发告警支持告警分组、抑制、静默发送通知到 Alertmanager配置示例:groups: - name: api_alerting_rules rules: - alert: HighErrorRate expr: job:request_errors:rate5m / job:http_requests:rate5m > 0.05 for: 5m labels: severity: critical annotations: summary: "High error rate on {{ $labels.job }}" description: "Error rate is {{ $value | humanizePercentage }}"关键区别:| 特性 | Recording Rules | Alerting Rules ||------|----------------|----------------|| 目的 | 预计算查询结果 | 触发告警通知 || 存储 | 生成新的时间序列 | 不存储新序列 || 性能 | 提高查询性能 | 可能增加评估开销 || 使用 | 仪表盘、查询 | 监控、告警 |最佳实践:Recording Rules:使用有意义的命名规范合理设置评估间隔定期审查和清理无用规则使用 by 子句进行分组Alerting Rules:合理设置 for 参数避免误报使用分级告警(info、warning、critical)添加清晰的描述信息使用标签便于分组和路由规则管理:使用版本控制管理规则文件使用 promtool 检查规则语法测试规则后再部署监控规则评估性能验证规则:promtool check rules /path/to/rules.yml
阅读 0·2月21日 15:41

在生产环境中使用 Prometheus 有哪些最佳实践?

Prometheus 在生产环境中的最佳实践:架构设计:高可用部署:部署多个 Prometheus 实例使用 Thanos 或 Cortex 实现长期存储配置负载均衡分散查询压力资源规划:resources: requests: memory: "4Gi" cpu: "2" limits: memory: "8Gi" cpu: "4"数据保留策略:storage: tsdb: retention.time: 15d retention.size: 50GB监控指标设计:命名规范:使用下划线分隔包含应用名称使用标准单位(bytes、seconds)示例:http_requests_total、memory_usage_bytes标签设计:使用有意义的标签避免高基数标签保持标签一致性示例:job="api", instance="10.0.0.1:9090"指标类型选择:Counter:累计值(请求数、错误数)Gauge:瞬时值(内存、CPU)Histogram:分布统计(延迟、响应大小)Summary:客户端分位数告警策略:分级告警:- alert: CriticalError expr: error_rate > 0.1 labels: severity: critical- alert: WarningError expr: error_rate > 0.05 labels: severity: warning告警抑制:inhibit_rules: - source_match: severity: 'critical' target_match: severity: 'warning' equal: ['alertname', 'instance']告警路由:route: group_by: ['alertname', 'cluster'] group_wait: 10s group_interval: 10s repeat_interval: 12h receiver: 'default' routes: - match: severity: critical receiver: 'pagerduty'安全配置:认证和授权:basic_auth: username: admin password: ${PROMETHEUS_PASSWORD}TLS 加密:tls_config: cert_file: /etc/prometheus/certs/server.crt key_file: /etc/prometheus/certs/server.key client_ca_file: /etc/prometheus/certs/ca.crt网络安全:使用防火墙限制访问配置 Kubernetes NetworkPolicy使用 VPN 或私有网络运维管理:配置管理:使用版本控制(Git)使用 Helm 或 Operator 部署实施变更审核流程备份策略:# 定期备份配置和数据promtool tsdb snapshot /var/lib/prometheus/ /backup/监控 Prometheus 自身:# 健康状态up{job="prometheus"}# 性能指标prometheus_tsdb_head_samples_appended_totalprometheus_query_duration_seconds_sum# 存储指标prometheus_tsdb_storage_blocks_bytes性能优化:采集优化:合理设置采集间隔使用 Recording Rules过滤不需要的指标查询优化:使用预计算规则限制查询时间范围使用标签过滤存储优化:配置数据压缩定期清理旧数据使用外部存储文档和培训:文档化:监控架构文档告警规则说明故障处理流程运维手册培训:团队培训计划值班轮换制度应急演练持续改进:定期审查:审查告警规则优化查询性能清理无用指标性能监控:监控资源使用分析查询性能优化存储策略安全审计:定期安全检查更新依赖版本审查访问权限
阅读 0·2月21日 15:40