gitweixin
  • 首页
  • 小程序代码
    • 资讯读书
    • 工具类
    • O2O
    • 地图定位
    • 社交
    • 行业软件
    • 电商类
    • 互联网类
    • 企业类
    • UI控件
  • 大数据开发
    • Hadoop
    • Spark
    • Hbase
    • Elasticsearch
    • Kafka
    • Flink
    • 数据仓库
    • 数据挖掘
    • flume
    • Kafka
    • Hive
    • shardingsphere
    • solr
  • 开发博客
    • Android
    • php
    • python
    • 运维
    • 技术架构
    • 数据库
  • 程序员网赚
  • bug清单
  • 量化投资
  • 在线查询工具
    • 去行号
    • 在线时间戳转换工具
    • 免费图片批量修改尺寸在线工具
    • SVG转JPG在线工具

如何在Chrome中设置启动时自动打开多个默认网页

精品微信小程序开发门户,代码全部亲测可用

  • 首页   /  
  • 作者: east
前端 7月 27,2025

如何在Chrome中设置启动时自动打开多个默认网页

我喜欢在同时用多个国内的大模型网站,每次启动chrome浏览器,一个个启动觉得麻烦。今天发现其实可以设置chrome启动时默认自动启动。

在Google Chrome中设置启动时自动打开多个默认网页,可通过以下步骤实现:


​​一、进入启动时设置​​

  1. ​​打开Chrome浏览器​​,点击右上角的 ​​三个垂直点​​(菜单按钮),选择 ​​“设置”​​ 。
  2. 在左侧菜单栏中找到 ​​“起始页面”​​ 选项并点击进入。

​​二、添加多个默认网页​​

  1. ​​选择启动行为​​
    在“启动时”页面中,选择 ​​“打开特定网页或一组网页”​ 。
  2. ​​添加网页​​
    • 点击 ​​“添加新网页”​​ 或 ​​“设置网页”​​ 按钮(不同版本名称可能略有差异)。
    • 在弹出窗口中输入第一个网页的完整网址(如 https://www.google.com),点击 ​​“添加”​​ 或 ​​“确定”​​ 。
    • 重复上述步骤,添加其他需要默认打开的网页 。
  1. ​​使用当前标签页​​(可选)
    如果希望将当前打开的标签页设为默认网页,可点击 ​​“使用当前网页”​​ 按钮 。

​​三、保存并验证​​

  • 完成添加后,关闭设置页面,​​Chrome会自动保存配置​​。
  • 重启浏览器,检查是否成功打开所有设置的网页 5。
作者 east
未分类 7月 7,2025

spark内存溢出怎样区分是软件还是代码原因

在 Spark 内存溢出(OutOfMemoryError) 的排查中,首先要区分是软件层配置不当还是代码逻辑导致内存占用异常。下面提供一个系统性的排查思路,帮助你判断是软件问题还是代码问题:


一、初步排查方向

维度判断问题来源
内存是否普遍不够软件配置问题
某任务、某节点频繁 OOM代码逻辑问题
所有任务都报相似 OOM软件问题可能更大
Task 在运行中内存缓慢增长代码中数据缓存或累积导致
提升 executor 内存后仍然溢出代码逻辑问题可能更大

二、具体排查步骤

查看 OOM 日志信息

  • 报错关键词:java.lang.OutOfMemoryError
  • 看看是:
    • GC overhead limit exceeded(垃圾回收过于频繁,内存紧张)
    • Java heap space(堆内存不足)
    • Direct buffer memory(off-heap内存问题)

这些信息能帮助我们快速定位是哪一块内存出了问题。


判断是否是 软件资源配置不足

表现:

  • executor 内存(如 --executor-memory 2g)太小
  • executor 数量太多,总内存超机器物理内存
  • shuffle spill 频繁但磁盘也不够用
  • 没有配置 spark.memory.fraction 或设置不合理(默认 0.6)

排查方式:

  • 适当提高 executor memory 和 driver memory 看是否解决问题;
  • 检查 spark.sql.shuffle.partitions 设置是否过大;
  • 观察是否所有节点都在 OOM;
  • 查看 GC 日志:是否频繁 full GC,停顿时间过长。

如果内存调高之后就不报错,说明是配置问题。


判断是否是 代码导致内存异常

典型表现:

  • 某些 task 内存快速膨胀,例如:
    • groupByKey() 或 reduceByKey() 输入太大;
    • 使用 collect() 导致 driver 内存不足;
    • 使用 rdd.cache() 缓存了大量数据;
    • Dataset 操作中存在 mapPartitions 内部收集过多数据;
    • 算子嵌套太深,堆栈过长导致栈溢出;
    • 广播变量(broadcast)太大;
    • join 前未分区或数据倾斜严重,单分区数据过大。

排查方式:

  • 查看具体是哪些 stage/task 报错(Spark UI -> Executors 或 Stages);
  • 查看是否只有少数 executor OOM;
  • 结合源码或业务逻辑,排查数据倾斜、缓存、collect 等问题;
  • 是否使用了 checkpoint?是否放在了合适位置?

三、建议工具与方法

Spark UI 重点页面

  • Stages 页面:查看哪个 stage 出现问题,是否数据倾斜;
  • Executors 页面:某个 executor 使用内存明显偏高;
  • SQL 页面:看哪个 SQL 任务导致内存暴涨;
  • Storage 页面:查看缓存的数据占用情况。

GC 日志分析

  • 如果是 JVM 内存泄漏,建议打开 GC 日志分析:--conf "spark.executor.extraJavaOptions=-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:gc.log"

总结:如何判断

问题特征更可能是…
所有 executor 都 OOM,提升内存后恢复软件配置不合理
单个 executor OOM,内存增长异常快代码问题
使用 collect/cache/join/groupByKey 导致爆炸代码问题
executor memory 明显低于数据体量软件问题
分区不合理导致单个 task 内存爆炸代码问题
作者 east
Spark 7月 7,2025

Spark Shuffle的优化

Spark Shuffle 是连接不同 Stage 的关键环节,也是 Spark 作业中最容易产生性能瓶颈的地方之一。它涉及大量磁盘 I/O、网络传输和内存使用。优化 Shuffle 对提升作业性能和稳定性至关重要。以下是一些关键的 Spark Shuffle 优化策略:

核心目标: 减少 Shuffle 数据量、降低 I/O 开销、提升网络传输效率、优化内存使用、处理数据倾斜。

主要优化策略:

  1. 减少 Shuffle 数据量 (根本之道):
    • Map-Side 预聚合/Combining: 在 Shuffle 写之前,尽可能在 Mapper 端对数据进行聚合(combineByKey, reduceByKey, aggregateByKey)。这能显著减少需要传输的键值对数量。优先使用 reduceByKey/aggregateByKey 而不是 groupByKey。
    • 选择更高效的算子: reduceByKey 优于 groupByKey + reduce;treeReduce/treeAggregate 在聚合深度大时优于 reduce/aggregate(减少网络轮次)。
    • 过滤数据: 尽早使用 filter 过滤掉不需要参与 Shuffle 的数据。
    • 列裁剪: 只选择 Shuffle 后真正需要的列(尤其是在使用 DataFrame/Dataset API 时)。避免传输整个对象。
    • 避免不必要的 distinct: distinct 会触发 Shuffle。考虑是否可以用其他方式(如 Map 端去重)或在更小的数据集上使用。
    • 广播小表: 如果 Join 操作中一个表很小,使用 broadcast 将其分发到所有 Executor,避免大表 Shuffle。spark.sql.autoBroadcastJoinThreshold 控制自动广播的阈值。
  2. 优化 Shuffle 写:
    • 调整 spark.shuffle.file.buffer: 增加 Shuffle 写过程中每个分区文件的内存缓冲区大小(默认 32K)。增大此值(如 64K, 128K)可以减少磁盘 I/O 次数,但会增加内存压力。需权衡。
    • 调整 spark.shuffle.spill.diskWriteBufferSize: 增大溢出到磁盘时使用的缓冲区大小(默认 1024K),同样减少写磁盘次数。
    • 启用 spark.shuffle.unsafe.file.output.buffer: 对于使用 Tungsten 的 Shuffle,设置这个直接内存缓冲区大小(默认 32K),作用类似 spark.shuffle.file.buffer。
    • 优化 spark.shuffle.spill: 确保 spark.shuffle.memoryFraction 或 spark.memory.fraction 设置合理,为 Shuffle 分配足够内存,减少溢出次数。监控 GC 和溢出情况。
    • 选择高效的 Shuffle 实现:
      • Sort Shuffle (sort): Spark 1.2+ 的默认方式。对每个分区排序并合并小文件。通常最稳定高效。
      • Tungsten-Sort (tungsten-sort): 基于 Project Tungsten,使用堆外内存和更高效的编码。在 Spark 1.4+ 可用,有时性能更好(尤其处理原始类型时)。通常当 spark.shuffle.manager=sort 且满足条件(序列化器支持重定位、非聚合 Shuffle 等)时会自动使用。
    • 文件合并 (spark.shuffle.consolidateFiles): (在较新 Spark 版本中已被优化或默认行为替代) 在老版本中启用此选项可以让多个 Reduce Task 共享同一个 Mapper 输出的合并文件,减少小文件数量。新版本 Sort Shuffle 本身已优化文件数量。
  3. 优化 Shuffle 读:
    • 调整 spark.reducer.maxSizeInFlight: 控制每次 Reduce Task 从远程 Executor 拉取数据的最大大小(默认 48M)。增大此值(如 96M)可以提高吞吐量,但会增加内存使用。需监控网络和内存。
    • 调整 spark.shuffle.io.maxRetries 和 spark.shuffle.io.retryWait: 网络不稳定时,增加重试次数和等待时间以避免 Fetch Failed 错误。但过度重试会拖慢作业。
    • 调整 spark.shuffle.io.numConnectionsPerPeer: 如果集群节点很多且网络是瓶颈,适当增加此值(默认 1)可以提升并发连接数。
    • 启用 spark.shuffle.compress: (默认开启) 压缩 Shuffle 数据(写和读)。使用高效的压缩算法:
      • spark.io.compression.codec: 推荐 lz4(速度快)或 zstd(压缩率高,速度也不错)。snappy 是默认值,也是不错的选择。避免使用低效的 lzf。
    • 调整 spark.shuffle.service.enabled: 启用 External Shuffle Service。这允许 Executor 在退出后(如动态资源分配下)Shuffle 文件仍能被访问,提高稳定性。通常在生产环境推荐启用。
  4. 调整分区数量:
    • 关键参数 spark.sql.shuffle.partitions (SQL/DataFrame/Dataset): 控制 Shuffle 后(如 Join, Aggregation)的分区数(默认 200)。这是最重要的优化点之一。
      • 分区过少: 每个分区数据量过大 -> 可能导致 OOM、GC 时间长、Task 执行慢、无法充分利用集群资源。
      • 分区过多: 每个分区数据量过小 -> Task 调度开销增大、产生大量小文件、网络请求次数增多(影响 Shuffle 读)。
      • 如何调整: 根据集群总核心数和数据量估算。经验值通常是集群总核心数的 2-3 倍。例如,集群有 100 个 Executor,每个 4 核,总核心数 400,可设置为 800 – 1200。需要根据实际作业数据量和执行情况(查看 Spark UI 中的 Shuffle Read Size/Records)反复调整测试。 数据量极大时可设置更高。
    • RDD API: repartition/coalesce: 在 RDD 操作中显式控制分区数。
  5. 处理数据倾斜:
    • 识别倾斜: 通过 Spark UI 查看各 Stage 中 Task 的执行时间分布。执行时间显著长于其他 Task 的通常处理了倾斜的分区。查看 Shuffle Read Size 差异。
    • 缓解策略:
      • 过滤倾斜 Key: 如果极少数倾斜 Key 可以单独处理或过滤掉。
      • 加盐打散: 给倾斜的 Key 添加随机前缀(扩容),在局部聚合后去掉前缀再全局聚合。
      • 提高并行度: 增加 spark.sql.shuffle.partitions,让倾斜 Key 分散到更多分区(对于单个 Key 数据量特别大的情况效果有限)。
      • 使用 skew join 优化 (Spark 3.0+ AQE): 自适应查询执行 (AQE) 能自动检测倾斜 Join 并将倾斜的分区分裂成更小的子分区进行处理。强烈推荐启用 AQE (spark.sql.adaptive.enabled=true)。
      • 特定算子: reduceByKey 比 groupByKey 更能容忍一定程度的倾斜(因为 Map 端合并了)。对于 Join 倾斜,考虑广播小表或使用 SortMergeJoin/ShuffleHashJoin 的替代方案。
  6. 利用自适应查询执行:
    • 启用 AQE (spark.sql.adaptive.enabled=true): Spark 3.0+ 的核心优化特性。
      • 动态合并 Shuffle 分区: 根据 Shuffle 后实际数据大小,自动将过小的分区合并,避免大量小 Task 的开销。
      • 动态调整 Join 策略: 在运行时根据统计信息将 SortMergeJoin 切换为 BroadcastJoin(如果发现小表符合广播条件)。
      • 动态优化倾斜 Join: 自动检测并处理 Shuffle Join 中的数据倾斜问题。
    • 相关参数: spark.sql.adaptive.coalescePartitions.enabled, spark.sql.adaptive.coalescePartitions.minPartitionNum, spark.sql.adaptive.advisoryPartitionSizeInBytes, spark.sql.adaptive.skewJoin.enabled, spark.sql.adaptive.skewJoin.skewedPartitionFactor, spark.sql.adaptive.skewJoin.skewedPartitionThresholdInBytes 等。强烈建议在生产环境中启用并适当配置 AQE。
  7. 硬件与集群配置:
    • 使用 SSD: 将 Shuffle 溢出目录 (spark.local.dir) 配置到 SSD 磁盘上能极大提升 Shuffle 写/读的 I/O 性能。这是非常有效的优化。
    • 充足内存: 确保 Executor 有足够内存(spark.executor.memory),特别是当 spark.memory.fraction 分配给 Storage 和 Execution(包含 Shuffle)时。减少溢出到磁盘的次数。
    • 高速网络: 万兆甚至更高带宽、低延迟的网络能显著加速 Shuffle 数据传输。
    • 合理 CPU 核数: 避免单个 Executor 分配过多 CPU 核(如 > 5),因为多个 Task 竞争磁盘/网络 I/O 可能成为瓶颈。通常每个 Executor 配置 3-5 核是一个较好的平衡点。

优化流程建议:

  1. 监控与诊断: 使用 Spark Web UI 仔细分析作业运行情况。重点关注:
    • Shuffle Read/Write 的总数据量和在各 Stage/Task 上的分布。
    • Task 的执行时间分布(识别倾斜)。
    • GC 时间。
    • 是否有溢出到磁盘 (Spill (Memory), Spill (Disk))。
    • Shuffle Write Time / Shuffle Read Time。
    • 日志中的 WARN/ERROR 信息(如 FetchFailed, OOM)。
  2. 定位瓶颈: 根据监控信息判断是数据量太大、I/O 慢、网络慢、内存不足还是数据倾斜。
  3. 应用策略: 针对性地选择上述优化策略进行调整。优先考虑减少数据量和调整分区数。
  4. 迭代测试: 修改配置或代码后,在小规模数据或测试集群上运行测试,观察效果。每次最好只修改一个主要配置,以便定位效果。
  5. 利用 AQE: 确保在 Spark 3.x 环境中启用并配置好 AQE,它能自动处理很多棘手的优化问题(小分区合并、倾斜 Join)。

Spark Shuffle 优化原则

类别优化建议
算子选择使用 reduceByKey 代替 groupByKey,选择合适的 Join
分区策略控制合理的并发度、分区数,避免极端数据倾斜
参数调优内存、缓冲区、网络传输参数细致设置
数据倾斜通过打散、随机 key、局部聚合等方式规避热点 key
AQE开启 Spark SQL 的自适应执行,自动处理 Join/倾斜问题
文件合并启用 consolidateFiles 降低磁盘负担
作者 east
嵌入式 7月 3,2025

MQTT完全解析和实践

第1章:MQTT的江湖地位——轻量级通讯的王者

你可能听过HTTP、WebSocket、CoAP……但如果你做的是物联网(IoT),MQTT 这个缩写,几乎避无可避。为啥?因为它轻、它快、它省电、它设计初衷就是为带宽差、电量少、网络不稳的设备服务的。

它的全称是 Message Queuing Telemetry Transport。虽然名字里带个“消息队列”,但和 Kafka 这类“正儿八经”的消息队列还真不是一路人。MQTT 更像是推送消息的邮差,而不是存储消息的邮局。

MQTT的核心机制:Pub/Sub模型

MQTT的核心机制是 发布/订阅(Publish/Subscribe),不是客户端直接连接到另一个客户端,而是由一个“中间人”——Broker(消息中介服务器)进行转发。

打个比方:

  • 发布者 = 在微信群里发言的人。
  • 订阅者 = 设置了关键词提醒的群友。
  • Broker = 微信服务器。

你只管发,Broker会帮你广播。订阅者只关心自己订阅的话题(Topic),不会管群里还有多少人在水群。

为什么物联网设备爱它?

MQTT从设计之初就有几个“讨喜”的特点:

  • 超轻量协议头:最小只有2个字节,远比HTTP动不动就几十上百字节要苗条。
  • 支持断线重连:掉线不怕,Client ID在,Broker会记住你。
  • QoS保证:支持三种消息服务质量(0、1、2),你要多可靠,它就有多可靠。
  • 持久会话:不在线也能留消息,回来还能收。
  • 订阅灵活:支持通配符(+、#),批量订阅根本不是问题。

MQTT vs HTTP:别再让设备“重型通信”了!

特性MQTTHTTP
连接方式长连接(保持)短连接(每次请求都重建)
消息头大小极小(2字节起)较大(几十到上百字节)
传输模式推送(服务器主动发)拉取(客户端主动要)
实时性高中低
能耗低高

用HTTP做物联网通讯,就像拿压路机送外卖——能用,但太浪费。


第2章:Topic不是“话题”,是你通讯的地盘

别被中文“话题”这个词骗了,MQTT里的Topic,是设备之间交流的“频道”。每个客户端只要订阅了相同的Topic,就能收到发布在这个Topic上的消息。

MQTT的Topic是层级结构,用斜杠(/)分隔,例如:

smartfarm/sensor/temperature
home/livingroom/light
factory/line1/robotarm/position

你可以把它想成文件路径,每一级都有它的意义。

通配符的魔力

MQTT支持两种通配符:

  • +:单级通配符,匹配某一级的任意名称。
  • #:多级通配符,匹配后面所有层级。

举个例子:

  • home/+/light 可以匹配 home/livingroom/light 和 home/kitchen/light
  • home/# 可以匹配 home/bedroom/fan/status、home/garden/temperature 等等

但注意哦,Topic是区分大小写的,还不能用空格,也别搞中文进去(虽然UTF-8可以,但兼容性差)。

Topic不是你想用就能用的

有些Broker会做Topic的访问控制。比如:

  • /system/# 是系统专用的Topic,不让你乱动
  • 公司级平台会配置每个设备只能订阅/发布某些Topic

所以设计MQTT Topic结构时,一定要清晰、分层、可扩展。

一个实用建议:用产品线/设备类型/功能做分类,例如:

factory/productA/temp_sensor01/data
factory/productA/temp_sensor01/command

第3章:QoS,决定你消息的“命运等级”

QoS,全称 Quality of Service(服务质量),是MQTT里一个超级关键的参数。决定了消息传递的“可靠度”。你可以根据场景选不同的级别:

QoS 0:至多一次(At most once)

  • 消息最多发送一次,不确认,不重发。
  • 最快,也最省资源,但可能丢消息。
  • 适用场景:温湿度、心跳包、实时状态上报。

QoS 1:至少一次(At least once)

  • 保证消息至少送达一次,可能重复送达。
  • 接收端需做幂等处理(不要重复处理同一条消息)。
  • 适用场景:开关指令、报警信息。

QoS 2:只有一次(Exactly once)

  • 复杂握手流程,确保消息只到达一次。
  • 网络差也能保证不重复、不丢失。
  • 适用场景:金融交易、关键配置变更。

但请记住:QoS不是越高越好。越高开销越大,设备负载也上升。合理权衡最重要。

在某些低功耗设备上,QoS 0 + 断电重发机制可能比QoS 1/2更划算。


第4章:Broker的心脏——选型与部署全指南

MQTT的灵魂是 Broker,选不好Broker,你的系统就像搭在沙子上的房子。主流Broker有几个大头:

Broker语言特点
MosquittoC轻量、开源、易部署,适合嵌入式、单机测试
EMQXErlang高并发、分布式、企业级能力强,支持集群与规则引擎
VerneMQErlang支持百万连接,企业级,社区活跃
HiveMQJava商用为主,配套工具完善,Web可视化强

你可以根据以下维度进行选择:

  • 性能要求:连接数多少、消息频率多高?
  • 部署环境:云部署还是边缘设备?
  • 安全需求:是否需要鉴权、TLS?
  • 扩展性:未来是否要接Kafka、MySQL、InfluxDB等?

下面这张表,直接拍板也没问题:

场景推荐Broker
小型智能家居项目Mosquitto
工厂边缘网关EMQX(部署在边缘计算设备)
城市级监控平台HiveMQ或EMQX集群
开发调试用Mosquitto + MQTT.fx/MQTT Explorer

第5章:连接的那一刻——MQTT客户端的秘密仪式

在物联网世界里,设备和Broker之间的第一次“见面礼”尤为重要。连接流程不仅要迅速稳定,还得包含身份验证、遗言声明和KeepAlive协议。

Connect报文:你的身份证明

每个MQTT客户端连接时都必须发送一个 CONNECT报文。这个报文里藏着很多关键信息:

  • Client ID:你的身份证,Broker用它来识别你。
  • Username & Password(可选):用于鉴权认证。
  • Clean Session:告诉Broker是否保存你的“上次对话记录”。
  • Will Message(遗嘱消息):掉线时Broker要不要帮你发一条“我挂了”的通告?
  • Keep Alive:告诉Broker多久没动静就要来ping我一下。

Client ID务必唯一,不然你和别的设备撞了名字,Broker会直接踢掉其中一个(或者两个全踢)。

遗嘱消息:设备断线的“最后遗言”

Will Message 是MQTT最“人性化”的设计之一。

假设你的设备突然断电或炸机,还没来得及优雅地发送离线通知——Broker就会代为转达一条“遗言”,提前设置好就行。

{
  "topic": "device/monitor01/status",
  "payload": "offline",
  "qos": 1,
  "retain": true
}

用它可以实现故障自动上报、设备状态感知、掉线告警等等,非常实用。

KeepAlive机制:别让你“假死”

Keep Alive 是一个时间间隔(单位秒),告诉Broker:

“如果我这段时间内没说话,你主动 ping 我一下。”

如果客户端没回应,Broker就会认为你掉线,然后把你踢出聊天室。这个机制能有效防止网络“假死”——其实你早没连上了,但系统以为你还活着。

建议设置在60秒左右,过短会增加网络开销,过长可能延迟感知掉线。

第6章:用代码点亮通讯——MQTT客户端实战开发

纸上得来终觉浅,得把代码跑一遍才算数。本章我们不谈理论,直接上手,从最常见的三类客户端出发:Java(Paho)、嵌入式C(ESP8266)、Node.js(JavaScript),逐一踩坑逐一解决。


6.1 Java + Eclipse Paho:稳定老将出马

Paho 是 Eclipse 基金会推出的 MQTT 客户端库,支持 Java、Python、JavaScript 等多语言实现。

✅ 添加依赖(以 Maven 为例):

<dependency>
  <groupId>org.eclipse.paho</groupId>
  <artifactId>org.eclipse.paho.client.mqttv3</artifactId>
  <version>1.2.5</version>
</dependency>

✅ 编写客户端代码:

MqttClient client = new MqttClient("tcp://broker.emqx.io:1883", "demoClientId");
MqttConnectOptions options = new MqttConnectOptions();
options.setCleanSession(true);
options.setUserName("user");
options.setPassword("pass".toCharArray());

client.setCallback(new MqttCallback() {
    public void connectionLost(Throwable cause) {
        System.out.println("连接断了:" + cause.getMessage());
    }
    public void messageArrived(String topic, MqttMessage message) throws Exception {
        System.out.println("收到消息:" + message.toString());
    }
    public void deliveryComplete(IMqttDeliveryToken token) {
        System.out.println("消息投递成功");
    }
});

client.connect(options);
client.subscribe("demo/topic", 1);
client.publish("demo/topic", new MqttMessage("hello mqtt".getBytes()));

⚠️ 小提示:

  • Client ID 请保持唯一,不然连接会被踢掉。
  • 不建议每次发消息都断连重连,连接是宝贵资源!
  • 异步连接版本是 MqttAsyncClient,适合UI线程中避免卡顿。

6.2 ESP8266 + PubSubClient:嵌入式的王道

Arduino 和 ESP8266 圈子里,用得最多的就是 PubSubClient。轻巧、稳定、开源。

✅ 安装库:

通过 Arduino IDE 管理库,搜索 PubSubClient 并安装即可。

✅ 示例代码:

#include <ESP8266WiFi.h>
#include <PubSubClient.h>

const char* ssid = "yourSSID";
const char* password = "yourPASS";
const char* mqtt_server = "broker.emqx.io";

WiFiClient espClient;
PubSubClient client(espClient);

void setup_wifi() {
  delay(10);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500); Serial.print(".");
  }
  Serial.println("WiFi connected");
}

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived ["); Serial.print(topic); Serial.print("] ");
  for (int i = 0; i < length; i++) Serial.print((char)payload[i]);
  Serial.println();
}

void reconnect() {
  while (!client.connected()) {
    if (client.connect("ESP8266Client")) {
      client.subscribe("esp/test");
    } else {
      delay(5000);
    }
  }
}

void setup() {
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
}

void loop() {
  if (!client.connected()) reconnect();
  client.loop();
}

⚠️ 常见问题:

  • 有些免费的公共 Broker 不支持遗嘱机制或 QoS 2,要验证前先查清楚。
  • ESP8266 内存有限,不要滥用 String 对象。

6.3 Node.js + MQTT.js:快速原型的神器

JavaScript 就是快,上手容易,调试方便。MQTT.js 是目前最主流的 Node MQTT 客户端。

✅ 安装依赖:

npm install mqtt

✅ 示例代码:

const mqtt = require('mqtt')
const client  = mqtt.connect('mqtt://broker.emqx.io')

client.on('connect', () => {
  console.log('连接成功')
  client.subscribe('node/topic', (err) => {
    if (!err) {
      client.publish('node/topic', 'Hello MQTT from Node.js')
    }
  })
})

client.on('message', (topic, message) => {
  console.log(`收到消息:${topic} -> ${message.toString()}`)
})

⚠️ 小贴士:

  • 如果用在 Electron 中开发可视化工具,MQTT.js 与 WebSocket Broker 配合非常完美。
  • 遇到 ECONNREFUSED 记得检查防火墙、端口是否开放。

第7章:把门锁好——MQTT安全机制的全副武装

物联网是个“草台班子”?可别这样说,安全性才是成败的关键。只要设备连上了公网,就必须考虑安全问题,不然哪天就被“黑客甲”把你家灯全开了。

这一章我们来认真讨论:MQTT如何防火防盗防偷窥——三层防护:身份认证、传输加密、权限控制。


7.1 用户名 + 密码:基础中的基础

大多数MQTT Broker都支持基于用户名和密码的简单鉴权。

Broker 端配置方式:

  • Mosquitto 使用 mosquitto_passwd 命令生成密码文件:
mosquitto_passwd -c /etc/mosquitto/passwd user1

然后在配置文件里加入:

password_file /etc/mosquitto/passwd
auth_plugin allow_anonymous false
  • EMQX 可以通过 Dashboard 或配置文件添加认证用户。

客户端连接示例(Java):

options.setUserName("user1");
options.setPassword("secret".toCharArray());

✅ 优点:实现简单,快速上手。 ❌ 缺点:密码泄露风险高,尤其是没有加密的传输通道。

所以,用户名密码只是“地基”,加密通道才是地锁。


7.2 TLS加密传输:不能让别人偷听

要让黑客无从下嘴,传输过程必须加密。MQTT天然支持TLS/SSL。

最常见两种方式:

  • 使用自签名证书(便宜,但不被浏览器信任)
  • 使用Let’s Encrypt等CA机构签发的证书(更靠谱)

Mosquitto 示例配置:

listener 8883
cafile /etc/mosquitto/certs/ca.crt
certfile /etc/mosquitto/certs/server.crt
keyfile /etc/mosquitto/certs/server.key
require_certificate false
tls_version tlsv1.2

客户端连接(Node.js):

const fs = require('fs')
const mqtt = require('mqtt')

const options = {
  host: 'broker.example.com',
  port: 8883,
  protocol: 'mqtts',
  ca: fs.readFileSync('./ca.crt'),
  cert: fs.readFileSync('./client.crt'),
  key: fs.readFileSync('./client.key')
};

const client = mqtt.connect(options);

⚠️ 注意:

  • TLS连接比明文连接更慢一点,资源占用也高。
  • 有些老旧设备(尤其是STM32类)TLS支持并不友好,可能需要硬件加速或专门适配。

7.3 ACL权限控制:我能发什么?我能订啥?

光有认证还不够,还得有“授权”。这就是 ACL(Access Control List)的角色。

举个例子:你不希望普通用户能订阅别人的摄像头画面吧?

ACL 可以精细到每个客户端的 订阅与发布权限:

Mosquitto 示例(aclfile):

user user1
publish topic home/user1/#
subscribe topic home/user1/#

user admin
publish topic #
subscribe topic #

EMQX 的 ACL 可以接 MySQL、Redis、JWT 等多种后端,非常灵活。

⚠️ 提醒:权限规则建议配合 Client ID 或用户名,否则容易被伪造身份钻空子。


7.4 防止DoS攻击:限流和最大连接数

物联网平台很容易被低成本刷连接刷消息搞挂。所以生产环境务必做下面几件事:

  • 设置客户端连接最大数、最大消息速率:
max_connections 10000
max_inflight_messages 20
message_size_limit 1MB
  • 对异常客户端(频繁掉线重连)封禁IP或限制连接频率。
  • Broker 支持接入防火墙策略或旁路 WAF (例如部署在Nginx后)。
作者 east
Hive 7月 1,2025

hive sql行转列,列转行sql的实例

在 Hive SQL 中,行转列和列转行是常见的数据转换操作。以下是详细说明和示例:

一、行转列(多行转多列)

场景:将同一分组下的多行数据合并为单行,不同值转为新列(如学生各科成绩横向展示)。

数据示例 (student_scores):

student_idsubjectscore
1Math90
1English85
2Math92

目标(每个学生一行,科目成绩转为列):

student_idMathEnglish
19085
292NULL

SQL 实现:

SELECT
  student_id,
  MAX(CASE WHEN subject = 'Math' THEN score END) AS Math,
  MAX(CASE WHEN subject = 'English' THEN score END) AS English
FROM student_scores
GROUP BY student_id;

关键点:

  1. 使用 CASE WHEN 按条件生成新列
  2. 用聚合函数(如 MAX/MIN/SUM)确保单行输出
  3. 必须配合 GROUP BY 分组字段

二、列转行(多列转多行)

场景:将单行的多列数据拆分为多行(如将横向科目成绩转为纵向记录)。

数据示例 (student_scores_wide):

student_idMathEnglish
19085
292NULL

目标(恢复为行式存储):

student_idsubjectscore
1Math90
1English85
2Math92
2EnglishNULL

SQL 实现:

SELECT student_id, 'Math' AS subject, Math AS score 
FROM student_scores_wide
UNION ALL
SELECT student_id, 'English' AS subject, English AS score 
FROM student_scores_wide;

优化方案(使用 LATERAL VIEW explode(),Hive 特有):

SELECT student_id, subject, score
FROM student_scores_wide
LATERAL VIEW explode(
  map(   -- 构建科目-分数的键值对
    'Math', Math,
    'English', English
  )
) subjects AS subject, score;

关键点:

  1. UNION ALL 适合列数量固定的场景
  2. LATERAL VIEW + explode(map) 动态处理多列
  3. 注意处理 NULL 值(Hive 中 NULL 会正常保留)

三、高级用法:动态行列转换

当列名不固定时(如新增科目),需结合 Hive 动态 SQL 或预处理:

  1. 行转列动态化:
    使用 collect_list + 拼接字符串,再通过 UDF 解析(较复杂,通常需借助外部脚本生成 SQL)。
  2. 列转行动态化:
    通过 Hive 元数据获取列名,动态生成 UNION ALL 语句(示例略,需依赖 Hive 变量或编程接口)。

总结对比

操作核心方法适用场景
行转列CASE WHEN + 聚合函数 + GROUP BY固定列名,聚合统计
列转行UNION ALL 或 LATERAL VIEW explode列数量少或需动态处理

提示:Hive 3.0+ 支持 LATERAL VIEW inline(array_of_structs),但需先构造结构体数组。实际使用时请根据数据规模和复杂度选择合适方案。

作者 east
python 6月 28,2025

解决运行Selenium报错:self.driver = webdriver.Chrome(service=service) TypeError: __init__() got an unexpected keyword argument ‘service’

这个错误说明你在使用 webdriver.Chrome(service=service) 的方式初始化 Selenium 的 Chrome 浏览器驱动时,传入了一个不被支持的参数 service,引发了 TypeError。


💡 错误分析:

报错信息:

TypeError: __init__() got an unexpected keyword argument 'service' 

说明当前的 webdriver.Chrome() 方法 不接受 service 参数。这是由于你当前使用的 Selenium 版本较旧(如 v3.x 或更早),而 service=... 是在 Selenium 4.0+ 中才新增支持的方式。


✅ 解决方案:

✅ 方法一:升级 Selenium 到 4.x 或更高版本(推荐)

如果你能控制环境,推荐直接升级 Selenium,以使用最新的 API 和功能。

升级命令:

pip install --upgrade selenium 

然后就可以继续使用如下代码:

from selenium import webdriver
from selenium.webdriver.chrome.service import Service

service = Service(executable_path='path_to_chromedriver')
driver = webdriver.Chrome(service=service)
pythonCopyEditfrom selenium import webdriver
from selenium.webdriver.chrome.service import Service

service = Service(executable_path='path_to_chromedriver')
driver = webdriver.Chrome(service=service)

✅ 方法二:使用旧版兼容方式(如果不能升级)

如果你的环境限制不能升级 Selenium,则要用旧的写法来初始化 ChromeDriver:

from selenium 
import webdriver
driver = webdriver.Chrome(executable_path='path_to_chromedriver')

注意:这在 Selenium 3.x 中是兼容的写法,executable_path 是直接传给 Chrome() 的。


🔍 如何确认当前 selenium 版本

可以在 Python 中运行以下代码查看当前版本:

import selenium 
print(selenium.__version__)

总结:

方案适用场景初始化方式
升级 Selenium 到 v4+推荐,未来兼容性好webdriver.Chrome(service=Service(...))
保持旧版本有环境限制无法升级webdriver.Chrome(executable_path=...)
作者 east
python 6月 24,2025

python 3.6使用mysql-connector-python报错:SyntaxError: future feature annotations is not defined

python 3.6使用mysql-connector-python报错:

Traceback (most recent call last):

File "E:\newcode\bigdata\pysparkTest\etl\export_doris_schema.py", line 1, in <module>

import mysql.connector

File "D:\ProgramData\Anaconda3\lib\site-packages\mysql\connector\__init__.py", line 32, in <module>

from .connection_cext import CMySQLConnection

File "D:\ProgramData\Anaconda3\lib\site-packages\mysql\connector\connection_cext.py", line 40, in <module>

from .abstracts import MySQLConnectionAbstract

File "D:\ProgramData\Anaconda3\lib\site-packages\mysql\connector\abstracts.py", line 33

from __future__ import annotations

^

SyntaxError: future feature annotations is not defined

Builder

错误分析

这个错误是由于Python版本兼容性问题导致的。错误信息显示:

SyntaxError: future feature annotations is not defined

问题原因:

  1. from future import annotations 是Python 3.7+才支持的特性
  2. 您当前使用的mysql-connector-python版本可能需要Python 3.7或更高版本
  3. 您的Python环境版本可能低于3.7,或者mysql-connector-python版本过新

解决方案

方案1:升级Python版本(推荐)

如果可能的话,升级到Python 3.7或更高版本:

# 检查当前Python版本
python --version

方案2:降级mysql-connector-python版本

卸载当前版本并安装兼容的版本:

pip uninstall mysql-connector-python
pip install mysql-connector-python==8.0.33

方案3:使用替代库(最简单)

使用PyMySQL替代mysql-connector-python,它对Python版本要求更宽松:

下面的是一个使用pymysql导出doris表结构的示例

import pymysql
from pymysql import Error

def export_doris_schema(host, port, user, password, database, output_file):
    try:
        # 连接到 Doris 的 MySQL 接口
        connection = pymysql.connect(
            host=host,
            port=port,
            user=user,
            password=password,
            database=database,
            charset='utf8mb4'
        )

        print(f"✅ 成功连接到 Doris 数据库: {database}")

        cursor = connection.cursor()

        # 获取所有表名
        cursor.execute("SHOW TABLES")
        tables = cursor.fetchall()

        with open(output_file, 'w', encoding='utf-8') as f:
            for table in tables:
                table_name = table[0]
                print(f"📋 正在导出表结构: {table_name}")

                cursor.execute(f"SHOW CREATE TABLE `{table_name}`")
                create_stmt = cursor.fetchone()[1]

                f.write(f"-- 表名:{table_name}\n")
                f.write(create_stmt + ";\n\n")

        print(f"🎉 所有表结构已成功导出到:{output_file}")

    except Error as e:
        print(f"❌ 数据库连接或操作失败: {e}")
    except Exception as e:
        print(f"❌ 发生未知错误: {e}")

    finally:
        if 'connection' in locals():
            cursor.close()
            connection.close()
            print("🔒 数据库连接已关闭")

# 配置参数(替换为你的实际信息)
config = {
    "host": "10.0.42.25",        # Doris FE 地址
    "port": 9030,                     # Doris MySQL 协议端口
    "user": "root",
    "password": "",
    "database": "zgcn",      # 要导出的数据库名
    "output_file": "doris_schema.txt" # 导出文件名
}

# 执行导出
export_doris_schema(**config)
作者 east
doris 6月 17,2025

修复启动Doris BE报错:Please set vm.max_map_count to be 2000000 under root using ‘sysctl -w vm.max_map_count=2000000’.

启动 Doris BE 时出现的系统检查报错提示,明确指向 Linux 系统参数配置问题。报错内容如下:

Please set vm.max_map_count to be 2000000 under root using 'sysctl -w vm.max_map_count=2000000'.

这意味着当前系统的 vm.max_map_count 参数值过小。Doris BE 运行时需要大量内存映射操作(尤其在高并发或列存储文件较多的场景下),该参数至少需设置为 2000000,否则可能因内存映射区域分配失败导致启动异常。

一、错误原因解析

vm.max_map_count 是 Linux 内核参数,用于限制单个进程可创建的内存映射区域数量(如 mmap 调用)。不同系统默认值存在差异:

  • Ubuntu 通常默认值为 65530
  • CentOS 常见默认值为 65536
    这些默认值远无法满足 Doris BE 的运行需求。

二、临时解决方案(快速生效但重启失效)

通过命令行直接修改运行时参数:

sudo sysctl -w vm.max_map_count=2000000

此操作会立即调整内存参数,但系统重启后配置会丢失,适用于急需启动服务的场景。

三、永久性解决方案(推荐方案)

通过修改配置文件实现重启后持续生效,操作步骤如下:
1. 编辑系统配置文件
使用文本编辑器打开 /etc/sysctl.conf:

sudo vim /etc/sysctl.conf

在文件末尾添加参数配置:

vm.max_map_count=2000000

保存并退出编辑器。
2. 应用配置使修改生效
执行命令加载新配置:

sudo sysctl -p

若未提示错误,说明配置已成功应用。

四、验证配置是否生效

可通过两种方式检查参数是否修改成功:
1. 使用 sysctl 命令查询

sysctl vm.max_map_count

正常输出应为:

vm.max_map_count = 2000000

2. 查看系统参数文件

cat /proc/sys/vm/max_map_count

若输出值为 2000000,则表示配置已生效。
完成以上操作后,重新启动 Doris BE 服务即可正常运行。编辑分享


作者 east
Docker 6月 12,2025

docker服务器:connect to host cdh04 port 22: No route to host 分析并解决

🔍 一、排查思路总览

  1. 确认目标主机(cdh04)是否运行正常
  2. 确认目标主机的 Docker 容器是否运行并绑定了 SSH 端口
  3. 确认网络配置是否通
  4. 确认 SSH 服务是否正常监听并运行
  5. 确认防火墙和安全组设置

🧪 二、详细排查步骤

✅ 1. Ping 主机名是否能通(DNS or Hosts 问题)

ping cdh04 
  • 如果提示:ping: unknown host cdh04
    • 说明主机名无法解析,检查 /etc/hosts 或 DNS。
  • 如果提示:Destination Host Unreachable
    • 说明网络层面有问题,继续往下查。

✅ 2. 确认是否为 Docker 容器内部主机

如果你是用 Docker 模拟 CDH 集群,那么 cdh04 可能是某个容器的别名。可通过以下命令确认:

docker ps -a | grep cdh04 

如果找不到:

  • 容器可能没有启动;
  • 容器网络未配置正确;
  • 或者该容器已崩溃。

可用以下命令查看网络:

docker network ls docker network inspect <网络名> 

✅ 3. 检查容器是否监听 22 端口

进入宿主机,检查容器绑定端口:

docker inspect cdh04 | grep -A 5 "PortBindings" 

确认是否有:

"22/tcp": [   {     "HostPort": "2222"   } ] 

表示你需要用 ssh -p 2222 用户名@宿主机IP 才能访问,而不是直接 ssh cdh04。


✅ 4. 检查 SSH 服务是否运行

进入容器:

docker exec -it cdh04 bash 

确认:

ps -ef | grep sshd 

如果没有:

service ssh start 

或者:

/etc/init.d/ssh start 

还可以查看日志:

cat /var/log/auth.log 

✅ 5. 容器网络是否正常(重要)

查看容器网络是否被桥接成功:

docker network inspect bridge 

容器是否有 IP:

docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' cdh04 

从宿主机 ping 容器 IP:

ping <容器IP> 

如果 ping 不通,可以尝试重启容器网络:

systemctl restart docker 

或使用:

docker network rm <网络名>  # 慎用,确认后使用 docker network create ... 

✅ 6. 防火墙与安全设置

查看 iptables(或 firewalld)是否阻拦了:

iptables -L -n | grep 22 

或者:

systemctl status firewalld 

临时关闭测试:

systemctl stop firewalld iptables -F 

💡 三、常见问题与建议

问题原因解决方式
No route to host宿主机到容器路由不通检查容器网络、端口映射
Connection refused容器未运行 SSH 服务或未监听 22 端口启动 ssh 服务,检查监听端口
ping 不通容器Docker 网络异常重建 docker 网络或检查 bridge 网络配置
容器无法被主机名访问/etc/hosts 缺失或 DNS 配置错误添加主机映射或使用容器 IP
作者 east
doris 6月 10,2025

Doris FE配置中的自动恢复选项

Doris FE 的自动恢复功能主要通过 ​​metadata_failure_recovery​​ 配置项实现,用于在元数据异常或集群脑裂时恢复 FE 的元数据一致性。以下是具体配置和使用方法:


​​1. 配置参数说明​​

  • ​​参数位置​​:在 FE 的配置文件 fe.conf 中添加或修改以下参数:properties复制metadata_failure_recovery=true
  • ​​作用​​:
    • ​​启用元数据恢复模式​​:清空本地 BDBJE 的元数据存储,尝试从其他节点恢复最新元数据。
    • ​​适用场景​​:FE 无法正常启动(如元数据损坏、脑裂)、集群失去 Master 节点等。

​​2. 不同场景下的配置方法​​

​​场景 1:单节点 FE 故障​​

  • ​​操作步骤​​:
    1. 在 fe.conf 中添加 metadata_failure_recovery=true。
    2. 重启 FE:sh bin/start_fe.sh --daemon。
    3. 恢复成功后,移除该配置或设置为 false,避免后续自动触发恢复8。

​​场景 2:多节点 FE 故障(需手动选择 Master)​​

  1. ​​定位最新元数据节点​​:
    • 检查所有 FE 的 meta_dir/image 目录,找到 image.xxxx 中数字最大的节点(元数据最新)8。
  2. ​​恢复 Master​​:
    • 在最新元数据节点的 fe.conf 中添加 metadata_failure_recovery=true。
    • 重启 FE,观察日志确认是否成功切换为 Master(日志中出现 transfer from XXXX to MASTER)6。
  3. ​​清理其他节点​​:
    • 删除旧 Master 和其他 Follower:ALTER SYSTEM DROP FOLLOWER "IP:PORT";。
    • 重新添加 Follower:ALTER SYSTEM ADD FOLLOWER "IP:PORT";8。

​​场景 3:Observer 节点恢复​​

  • ​​特殊处理​​:
    • 若 Observer 的元数据最新,需先修改 meta_dir/image/ROLE 文件,将 role=OBSERVER 改为 role=FOLLOWER。
    • 按 Follower 恢复流程操作,避免角色不一致问题。

​​3. 版本差异​​

  • ​​Doris ≥2.0.2​​:支持命令行参数直接启用恢复模式:
  • sh bin/start_fe.sh --metadata_failure_recovery --daemon
  • ​​Doris <2.0.2​​:需在 fe.conf 中添加 metadata_failure_recovery=true。

​​4. 注意事项​​

  1. ​​仅限紧急恢复​​:恢复模式会清空本地元数据,需确保其他节点元数据可用。
  2. ​​恢复后操作​​:
    • 恢复成功后必须移除 metadata_failure_recovery 配置,否则下次重启会再次触发恢复。
    • 检查集群状态:SHOW FRONTENDS; 确认所有节点状态正常。
  3. ​​脑裂风险​​:恢复过程中可能产生脑裂,建议在操作前备份元数据目录(fe/doris-meta)4。

​​5. 预防措施​​

  • ​​高可用部署​​:建议配置 3 个 Follower 或 1 Follower + 1 Observer,避免单点故障7。
  • ​​定期备份​​:通过 BACKUP 命令或 Doris Manager 定期备份元数据。
  • ​​监控告警​​:使用 Doris Manager 或第三方工具监控 FE 状态,及时触发恢复流程4。
作者 east
python 6月 9,2025

详解Python当中的pip常用命令

引言:Python包管理的重要性与pip的地位

Python 包管理:有了 pip,开发效率直接起飞!

在 Python 的世界里,包管理就跟盖房子打地基一样重要。想象一下,你要用 Python 写个爬虫,需要用到 requests、BeautifulSoup4 这些库,或者要做数据分析,pandas、numpy 肯定是少不了的。如果没有一个好用的包管理工具,一个个手动下载、安装、管理依赖,那酸爽,谁用谁知道!

所以,pip 就应运而生了。它就像 Python 的御用管家,专门负责包的安装、卸载、升级等等。有了它,我们就可以把更多精力放在写代码上,而不是跟那些烦人的依赖问题死磕。

pip 其实也挺有历史的,它最早可以追溯到 2008 年,后来慢慢发展壮大,现在已经成了 Python 的标配。毫不夸张地说,pip 就是 Python 生态系统中最重要的工具之一。它简单易用,功能强大,几乎所有的 Python 开发者都在用它。

pip 安装与配置:磨刀不误砍柴工

想要用 pip,首先得把它装好。不同操作系统安装 pip 的方式略有差异,但都大同小异,跟着步骤走,保证没问题!

1. Windows 系统

Windows 系统通常自带 Python,但可能没有 pip。别慌,我们有办法:

* 确认 Python 是否安装: 在命令行输入 python –version,如果能看到 Python 的版本号,说明已经安装了。
* 下载 get-pip.py: 打开浏览器,访问 [https://bootstrap.pypa.io/get-pip.py](https://bootstrap.pypa.io/get-pip.py),把这个文件保存到你的电脑上,比如 D 盘根目录。
* 运行 get-pip.py: 打开命令行,切换到 get-pip.py 所在的目录(cd D:\),然后运行 python get-pip.py。


cd D:\
python get-pip.py

等待安装完成,看到 “Successfully installed pip…” 就说明安装成功了。
* 配置环境变量: 为了方便使用 pip,需要把 Python 的 Scripts 目录添加到环境变量中。找到 Python 的安装目录,里面有个 Scripts 目录,把它的路径复制下来。然后在系统设置里找到环境变量,编辑 Path 变量,把 Scripts 目录的路径添加进去。

比如我的 Python 安装在 C:\Python39,那么 Scripts 目录就是 C:\Python39\Scripts。

注意: 添加完环境变量后,需要重启命令行窗口才能生效。
* 验证安装: 重新打开命令行,输入 pip –version,如果能看到 pip 的版本号,说明安装成功了。

2. macOS 系统

macOS 系统通常也自带 Python,但版本可能比较老。建议安装 Homebrew,然后用 Homebrew 安装 Python:

* 安装 Homebrew: 如果你还没有安装 Homebrew,打开终端,运行以下命令:


/bin/bash -c “$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)”

按照提示操作即可。
* 安装 Python: 安装完 Homebrew 后,运行以下命令安装 Python 3:


brew install python3

* 验证安装: 安装完成后,运行 python3 –version 和 pip3 –version,确认 Python 和 pip 都已成功安装。

3. Linux 系统

Linux 系统安装 pip 的方式有很多种,这里介绍一种比较通用的方法:

* 更新软件包列表: 打开终端,运行以下命令:


sudo apt update

* 安装 pip: 运行以下命令安装 pip:


sudo apt install python3-pip

* 验证安装: 安装完成后,运行 pip3 –version,确认 pip 已成功安装。

配置 pip 镜像源

由于国内访问 PyPI(Python Package Index,官方的 Python 包仓库)速度比较慢,所以建议配置 pip 的镜像源,这样可以大大提高下载速度。

* 临时使用镜像源: 在使用 pip 安装包的时候,可以加上 -i 参数指定镜

pip安装与配置:为Python之旅铺平道路

像源:


pip install 包名 -i 镜像源地址

比如,使用清华大学的镜像源安装 requests 库:


pip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple

* 永久配置镜像源: 为了避免每次都手动指定镜像源,可以永久配置 pip 的镜像源。

* Windows 系统: 在 %APPDATA%\pip 目录下创建一个 pip.ini 文件(如果目录不存在,手动创建),内容如下:

ini
[global]
index-url = https://pypi.tuna.tsinghua.edu.cn/simple
[install]
trusted-host = pypi.tuna.tsinghua.edu.cn

* macOS 和 Linux 系统: 在 ~/.pip 目录下创建一个 pip.conf 文件(如果目录不存在,手动创建),内容如下:

ini
[global]
index-url = https://pypi.tuna.tsinghua.edu.cn/simple
[install]
trusted-host = pypi.tuna.tsinghua.edu.cn

常用镜像源推荐

* 清华大学: https://pypi.tuna.tsinghua.edu.cn/simple
* 阿里云: https://mirrors.aliyun.com/pypi/simple/
* 中国科技大学: https://pypi.mirrors.ustc.edu.cn/simple/
* 豆瓣: https://pypi.doubanio.com/simple/

选择一个你喜欢的镜像源,配置好 pip,就可以愉快地安装各种 Python 包啦!

pip 常用命令详解:玩转你的 Python 依赖

pip 的命令其实不多,但个个都很有用。掌握了这些命令,你就可以轻松管理你的 Python 依赖,再也不用担心包的版本冲突、安装失败等问题了。

1. pip install:安装包

这是 pip 最常用的命令,用于安装指定的 Python 包。

* 语法: pip install 包名

比如,安装 requests 库:


pip install requests

pip 会自动从 PyPI 下载 requests 库,并安装到你的 Python 环境中。
* 安装指定版本的包: 如果你需要安装指定版本的包,可以使用 == 符号指定版本号:


pip install requests==2.25.1

这样就会安装 requests 库的 2.25.1 版本。
* 安装多个包: 你可以一次性安装多个包,只需要把包名用空格隔开:


pip install requests beautifulsoup4 pandas

* 从 requirements 文件安装: 有时候,你的项目有很多依赖,一个个手动安装太麻烦了。你可以把所有依赖写到一个 requirements.txt 文件中,然后用 pip 一次性安装:


pip install -r requirements.txt

requirements.txt 文件的格式很简单,每行一个包名,可以指定版本号,也可以不指定:

requests==2.25.1
beautifulsoup4
pandas>=1.2.0

这种方式非常适合管理项目的依赖,可以保证所有开发者使用相同的依赖版本。

2. pip uninstall:卸载包

用于卸载指定的 Python 包。

* 语法: pip uninstall 包名

比如,卸载 requests 库:


pip uninstall requests

pip 会从你的 Python 环境中移除 requests 库。
* 卸载多个包: 同样可以一次性卸载多个包:


pip uninstall requests beautifulsoup4 pandas

* 自动确认卸载: 卸载包的时候,pip 会提示你确认是否卸载。如果你不想每次都手动确认,可以加上 -y 参数:


pip uninstall requests -y

3. pip update或pip install –upgrade:升级包

用于升级指定的 Python 包到最新版本。

* 语法: pip install –upgrade 包名

比如,升级 requests 库:


pip install –upgrade requests

pip 会检查 requests 库是否有新版本,如果有,就下载并安装最新版本。
* 升级所有包: 如果你想升级所有已安装的包,可以使用 pip list –outdated 命令查看哪些包需要升级,然后使用以下命令升级所有包:


pip install –upgrade $(pip list –outdated | awk ‘{print $1}’ | tail -n +3)

这条命令有点长,解释一下:

* pip list –outdated:列出所有需要升级的包。
* awk ‘{print $1}’:提取第一列,也就是包名。
* tail -n +3:去掉前两行(标题行)。
* $(…):把命令的输出作为参数传递给 pip install –upgrade。

注意: 升级所有包可能会导致一些兼容性问题,建议谨慎使用。

4. pip search:搜索包

用于在 PyPI 上搜索指定的 Python 包。

* 语法: pip search 关键词

比如,搜索包含 “image” 关键词的包:


pip search image

pip 会在 PyPI 上搜索包含 “image” 关键词的包,并显示搜索结果。

注意: pip search 命令在较新版本的 pip 中已经被移除了,可以使用 pip install searchpackages 来安装 searchpackages 插件,然后使用 searchpackages 关键词 命令进行搜索。
或者可以考虑直接在 PyPI 官网([https://pypi.org/](https://pypi.org/))上搜索。

5. pip show:查看包信息

用于查看已安装的 Python 包的详细信息。

* 语法: pip show 包名

比如,查看 requests 库的信息:


pip show requests

pip 会显示 requests 库的版本号、作者、描述、依赖等信息。

6. pip list:列出已安装的包

用于列出所有已安装的 Python 包。

* 语法: pip list

pip 会列出所有已安装的 Python 包,并显示版本号。

* 列出可升级的包: 使用 pip list –outdated 命令可以列出所有需要升级的包。

7. pip freeze:生成 requirements 文件

用于生成 requirements.txt 文件,记录当前 Python 环境中的所有依赖。

* 语法: pip freeze > requirements.txt

这条命令会将当前 Python 环境中的所有依赖及其版本号写入到 requirements.txt 文件中。

这个命令非常有用,可以方便地复制项目的依赖到其他环境。

一些小技巧

* 使用 tab 键自动补全: 在命令行输入 pip 命令的时候,可以使用 tab 键自动补全包名,可以节省很多时间。
* 查看 pip 帮助: 如果你忘记了 pip 命令的用法,可以使用 pip –help 命令查看 pip 的帮助信息。
* 使用 -h 参数查看命令的帮助: 比如,查看 pip install 命令的帮助信息,可以使用 pip install -h 命令。

掌握了这些 pip 常用命令,你就可以轻松管理你的 Python 依赖,让你的 Python 开发更加高效!

pip 进阶技巧:更上一层楼

pip 除了基本的安装、卸载、升级功能,还有一些高级用法,可以帮助你更好地管理 Python 项目的依赖,提升开发效率。

1. 使用虚拟环境

虚拟环境是一个独立的 Python 运行环境,可以隔离不同项目的依赖,避免版本冲突。

* 创建虚拟环境: 使用 venv 模块创建虚拟环境:


python3 -m venv 虚拟环境名称

比如,创

pip进阶技巧:提升你的Python开发效率

建一个名为 “myenv” 的虚拟环境:


python3 -m venv myenv

会在当前目录下创建一个名为 “myenv” 的目录,里面包含了虚拟环境的 Python 解释器、pip 等工具。
* 激活虚拟环境:

* Windows 系统:


myenv\Scripts\activate

* macOS 和 Linux 系统:


source myenv/bin/activate

激活虚拟环境后,命令行前面会显示虚拟环境的名称,表示你已经进入了虚拟环境。
* 在虚拟环境中安装包: 在虚拟环境中安装包,只会安装到当前虚拟环境中,不会影响到全局的 Python 环境。


pip install requests

* 退出虚拟环境:


deactivate

退出虚拟环境后,命令行前面不再显示虚拟环境的名称。

使用虚拟环境可以避免不同项目之间的依赖冲突,保证项目的稳定性。建议每个 Python 项目都使用独立的虚拟环境。

2. 使用 pipenv 或 poetry

pipenv 和 poetry 是更现代的 Python 包管理工具,它们在 pip 的基础上做了很多改进,提供了更强大的功能。

* pipenv: pipenv 是 Kenneth Reitz(requests 库的作者)开发的,它集成了虚拟环境管理和依赖管理,可以自动创建和管理虚拟环境,并使用 Pipfile 文件来记录项目的依赖。

* 安装 pipenv:


pip install pipenv

* 创建虚拟环境: 在项目目录下运行 pipenv shell 命令,会自动创建虚拟环境,并激活。


pipenv shell

* 安装包: 使用 pipenv install 包名 命令安装包,会自动把包添加到 Pipfile 文件中。


pipenv install requests

* 生成 requirements.txt 文件:


pipenv lock -r > requirements.txt

* poetry: poetry 是另一种流行的 Python 包管理工具,它使用 pyproject.toml 文件来管理项目的依赖,并提供了更强大的依赖解析和版本控制功能。

* 安装 poetry:


pip install poetry

* 创建项目:


poetry new 项目名称

* 添加依赖:


poetry add requests

* 安装依赖:


poetry install

pipenv 和 poetry 都是非常优秀的 Python 包管理工具,可以根据自己的喜好选择使用。它们可以帮助你更好地管理项目的依赖,提高开发效率。

3. 自定义 pip 配置

pip 允许你自定义一些配置,可以改变 pip 的行为。

* 配置文件: pip 的配置文件位于:

* Windows 系统: %APPDATA%\pip\pip.ini
* macOS 和 Linux 系统: ~/.pip/pip.conf

* 常用配置项:

* index-url:指定 PyPI 的地址。
* trusted-host:指定可信任的 PyPI 主机。
* timeout:指定超时时间。
* retries:指定重试次数。

比如,设置超时时间为 60 秒,重试次数为 3 次:

ini
[global]
timeout = 60
retries = 3

通过自定义 pip 配置,可以更好地控制 pip 的行为,满足自己的需求。

掌握这些 pip 进阶技巧,你就可以更好地管理 Python 项目的依赖,提高开发效率,成为 Python 开发高手!

作者 east
海豚调度器 5月 30,2025

海豚调度器3.x版本解决创建文件夹时提示未指定当前登录用户的租户”的问题

在 海豚调度器 DolphinScheduler 3.x 中,出现提示:

“未指定当前登录用户的租户”

这是因为 当前登录用户没有绑定租户信息(Tenant),而 DolphinScheduler 在资源操作(如创建文件夹、提交任务等)时必须绑定租户,以便在后台进行资源隔离和权限控制。


一、问题成因分析

海豚调度器的核心概念之一是 租户(Tenant)。每个用户在执行任务时都必须以某个租户身份来进行资源调度。

在 DolphinScheduler 3.x 中:

  • 每个用户需要 绑定一个默认租户。
  • 如果没有绑定租户,进行资源操作(如资源中心上传、目录创建)时就会报错。

二、解决步骤

✅ 步骤1:登录系统,进入租户管理

  1. 使用 admin 用户登录 DolphinScheduler Web UI。
  2. 进入菜单:[安全中心] -> [租户管理]。
  3. 创建一个租户,例如:
    • 租户编码:default_tenant
    • 描述:默认租户

注意:租户编码实际对应 Linux 上执行任务的系统用户,需与服务器用户对应。


✅ 步骤2:为用户分配租户

  1. 进入菜单:[安全中心] -> [用户管理]
  2. 找到你的目标用户,点击 编辑。
  3. 在编辑用户界面,将 租户 设置为刚刚创建的租户 default_tenant。
  4. 保存设置。

✅ 步骤3:重新登录或刷新页面

分配租户之后,用户需要重新登录或刷新浏览器,以使绑定关系生效。


✅ 步骤4:重新尝试资源中心操作

现在再尝试在资源中心创建文件夹、上传资源等操作,应不会再出现“未指定当前登录用户的租户”的提示。

作者 east

1 2 … 93 下一个

关注公众号“大模型全栈程序员”回复“小程序”获取1000个小程序打包源码。回复”chatgpt”获取免注册可用chatgpt。回复“大数据”获取多本大数据电子书

标签

AIGC AI创作 bert chatgpt github GPT-3 gpt3 GTP-3 hive mysql O2O tensorflow UI控件 不含后台 交流 共享经济 出行 图像 地图定位 外卖 多媒体 娱乐 小程序 布局 带后台完整项目 开源项目 搜索 支付 效率 教育 日历 机器学习 深度学习 物流 用户系统 电商 画图 画布(canvas) 社交 签到 联网 读书 资讯 阅读 预订

官方QQ群

小程序开发群:74052405

大数据开发群: 952493060

近期文章

  • 如何在Chrome中设置启动时自动打开多个默认网页
  • spark内存溢出怎样区分是软件还是代码原因
  • MQTT完全解析和实践
  • 解决运行Selenium报错:self.driver = webdriver.Chrome(service=service) TypeError: __init__() got an unexpected keyword argument ‘service’
  • python 3.6使用mysql-connector-python报错:SyntaxError: future feature annotations is not defined
  • 详解Python当中的pip常用命令
  • AUTOSAR如何在多个供应商交付的配置中避免ARXML不兼容?
  • C++thread pool(线程池)设计应关注哪些扩展性问题?
  • 各类MCAL(Microcontroller Abstraction Layer)如何与AUTOSAR工具链解耦?
  • 如何设计AUTOSAR中的“域控制器”以支持未来扩展?

文章归档

  • 2025年7月
  • 2025年6月
  • 2025年5月
  • 2025年4月
  • 2025年3月
  • 2025年2月
  • 2025年1月
  • 2024年12月
  • 2024年11月
  • 2024年10月
  • 2024年9月
  • 2024年8月
  • 2024年7月
  • 2024年6月
  • 2024年5月
  • 2024年4月
  • 2024年3月
  • 2023年11月
  • 2023年10月
  • 2023年9月
  • 2023年8月
  • 2023年7月
  • 2023年6月
  • 2023年5月
  • 2023年4月
  • 2023年3月
  • 2023年1月
  • 2022年11月
  • 2022年10月
  • 2022年9月
  • 2022年8月
  • 2022年7月
  • 2022年6月
  • 2022年5月
  • 2022年4月
  • 2022年3月
  • 2022年2月
  • 2022年1月
  • 2021年12月
  • 2021年11月
  • 2021年9月
  • 2021年8月
  • 2021年7月
  • 2021年6月
  • 2021年5月
  • 2021年4月
  • 2021年3月
  • 2021年2月
  • 2021年1月
  • 2020年12月
  • 2020年11月
  • 2020年10月
  • 2020年9月
  • 2020年8月
  • 2020年7月
  • 2020年6月
  • 2020年5月
  • 2020年4月
  • 2020年3月
  • 2020年2月
  • 2020年1月
  • 2019年7月
  • 2019年6月
  • 2019年5月
  • 2019年4月
  • 2019年3月
  • 2019年2月
  • 2019年1月
  • 2018年12月
  • 2018年7月
  • 2018年6月

分类目录

  • Android (73)
  • bug清单 (79)
  • C++ (34)
  • Fuchsia (15)
  • php (4)
  • python (45)
  • sklearn (1)
  • 云计算 (20)
  • 人工智能 (61)
    • chatgpt (21)
      • 提示词 (6)
    • Keras (1)
    • Tensorflow (3)
    • 大模型 (1)
    • 智能体 (4)
    • 深度学习 (14)
  • 储能 (44)
  • 前端 (5)
  • 大数据开发 (491)
    • CDH (6)
    • datax (4)
    • doris (31)
    • Elasticsearch (15)
    • Flink (78)
    • flume (7)
    • Hadoop (19)
    • Hbase (23)
    • Hive (41)
    • Impala (2)
    • Java (71)
    • Kafka (10)
    • neo4j (5)
    • shardingsphere (6)
    • solr (5)
    • Spark (100)
    • spring (11)
    • 数据仓库 (9)
    • 数据挖掘 (7)
    • 海豚调度器 (10)
    • 运维 (34)
      • Docker (3)
  • 小游戏代码 (1)
  • 小程序代码 (139)
    • O2O (16)
    • UI控件 (5)
    • 互联网类 (23)
    • 企业类 (6)
    • 地图定位 (9)
    • 多媒体 (6)
    • 工具类 (25)
    • 电商类 (22)
    • 社交 (7)
    • 行业软件 (7)
    • 资讯读书 (11)
  • 嵌入式 (71)
    • autosar (63)
    • RTOS (1)
    • 总线 (1)
  • 开发博客 (16)
    • Harmony (9)
  • 技术架构 (6)
  • 数据库 (32)
    • mongodb (1)
    • mysql (13)
    • pgsql (2)
    • redis (1)
    • tdengine (4)
  • 未分类 (7)
  • 程序员网赚 (20)
    • 广告联盟 (3)
    • 私域流量 (5)
    • 自媒体 (5)
  • 量化投资 (4)
  • 面试 (14)

功能

  • 登录
  • 文章RSS
  • 评论RSS
  • WordPress.org

All Rights Reserved by Gitweixin.本站收集网友上传代码, 如有侵犯版权,请发邮件联系yiyuyos@gmail.com删除.