【Clickhouse从入门到精通】第08篇:揭秘ClickHouse为何如此之快——五大设计哲学

news2026/5/18 15:18:06
上一篇【第07篇】ClickHouse执行引擎架构——Parser、Interpreter与Function体系下一篇【第09篇】ClickHouse安装部署全攻略——从环境准备到服务启动摘要ClickHouse能在十亿行级别数据的聚合查询中实现毫秒级响应绝非偶然。这种极致性能的背后是一整套经过深思熟虑的设计哲学在支撑——从底层硬件特性的充分利用到算法选择的极致务实再到对新技术的大胆采纳。本文系统阐述ClickHouse的五大核心设计哲学着眼硬件先想后做、算法在前抽象在后、勇于尝鲜不行就换、特定场景特殊优化、持续测试持续改进。深入理解这些设计哲学不仅能帮助我们更好地使用ClickHouse更能为构建其他高性能系统提供宝贵的借鉴。关键词CPU缓存、SIMD向量化、零开销抽象、JIT编译、性能基准测试、列式存储、NUMA感知1 引言性能的秘密不只是列式存储业界普遍将ClickHouse的高性能归功于列式存储——这个答案当然正确但远不够深刻。列式存储只是ClickHouse性能大厦的一块基石真正让这座大厦高耸入云的是散布在代码库各个角落、贯穿整个架构的设计决策与工程取舍。ClickHouse的源码中随处可见这样的注释// We use this instead of std::vector to avoid initialization overhead// This method is always inlined — no virtual call overhead// Manual loop instead of STL to enable auto-vectorization这些看似琐碎的优化累积起来产生了惊人的效果——ClickHouse在某些查询上比Parquet格式的Spark快100倍以上。本文的目的是揭开这些秘密的面纱揭示支撑这些优化决策的五大设计哲学。2 哲学一着眼硬件先想后做2.1 硬件特性是性能的上限ClickHouse的设计者有一个核心信念不理解硬件就无法写出高性能代码。现代CPU的体系结构充满了隐藏的规则违背这些规则性能可能差100倍。理解硬件要从三个维度出发CPU性能的三重约束 第一重: 算术逻辑单元 (ALU) ← 每核每秒数十亿次操作 ↑ 瓶颈不在这里 第二重: 内存带宽 (Memory Bandwidth) ← DDR4: ~50GB/s ↑ 大多数数据处理任务的瓶颈 第三重: 内存延迟 (Memory Latency) ← DRAM: ~100ns ↑ 比 L1 缓存 (~1ns) 慢100倍!2.2 CPU缓存友好让数据留在身边CPU缓存Cache是现代处理器中最容易被忽视的性能杠杆。以Intel Skylake为例缓存层级如下缓存级别大小延迟带宽L1 Data Cache32KB/核~1ns (4 cycles)~1TB/sL2 Cache256KB/核~4ns (12 cycles)~500GB/sL3 Cache1-2MB/核~15ns (50 cycles)~200GB/sDRAM数百GB~100ns~50GB/s一次L3缓存未命中Cache Miss意味着浪费100倍的时间ClickHouse通过以下策略最大化缓存命中率策略一数据按列存储减少无关数据加载-- 查询: SELECT avg(price) FROM orders;-- 仅有 price 列被加载到缓存行式存储(MySQL,PostgreSQL):Row#1: [id1, date2024-01-01, customerAlice, price99.9, ...]Row#2: [id2, date2024-01-02, customerBob, price149.9, ...]每次加载: 整行数据(假设1KB/行)→ L1 缓存仅能容纳32行 列式存储(ClickHouse): price列:[99.9,149.9,79.5,299.9,...]每次加载: 仅 price 列 → L1 缓存可容纳~40000个浮点数策略二数据按处理批次对齐到缓存行ClickHouse的PaddedPODArray确保数组元素的起始地址按64字节一个缓存行对齐// src/Common/PaddedPODArray.h// 普通的 PODArray 使用 sizeof(T) 对齐// PaddedPODArray 强制使用 64 字节对齐缓存行大小templatetypenameT,size_t Alignment64classPaddedPODArray{private:T*data_;// 保证 data_ 的地址是 64 的倍数public:// alignas(64) 确保结构体本身也对齐// 这对于 SIMD 操作至关重要}__attribute__((aligned(64)));这种对齐使得SIMD加载指令可以一次性读取多个元素而不会跨越缓存行边界跨缓存行的访问会导致额外的内存操作。2.3 SIMD向量指令一条指令做四件事SIMDSingle Instruction Multiple Data允许CPU用一条指令同时处理多个数据元素。对于数据密集型的OLAP查询这是性能提升的利器。// 标量计算: 每次处理1个元素voidscalarAdd(float*a,float*b,float*c,size_t n){for(size_t i0;in;i)c[i]a[i]b[i];// 每次循环: 加载2次 加法1次 存储1次 4条指令}// SIMD向量化: 每次处理8个float (AVX2, 256bit)voidsimdAdd(float*a,float*b,float*c,size_t n){size_t i0;for(;i8n;i8){__m256 va_mm256_loadu_ps(ai);// 一次加载8个float__m256 vb_mm256_loadu_ps(bi);__m256 vc_mm256_add_ps(va,vb);// 一次加法处理8个元素_mm256_storeu_ps(ci,vc);// 一次存储8个float}// 处理剩余元素...}性能对比在Intel i9-9900K上测试数据可完全放入L2缓存实现方式吞吐量相对于标量的加速比标量2.5 GB/s1xSSE (4元素)9.8 GB/s3.9xAVX2 (8元素)19.2 GB/s7.7xAVX-512 (16元素)35.0 GB/s14xClickHouse的列式存储天然适合SIMD操作——同一列的数据类型相同、连续存储这正是SIMD发挥作用的最优数据布局。2.4 内存预取提前把数据请进缓存内存预取Prefetch是一种提前通知CPU加载数据的技术。CPU的内存预取器会识别访问模式并提前发起加载减少实际计算时的等待时间。ClickHouse中的预取策略// 聚合过程中的预取voidAggregatingTransform::consume(Chunk chunk){autocolumnschunk.getColumns();// 预取下一批数据跨循环迭代预取if(next_chunk_available){// hint CPU: 接下来会读取这些地址的数据__builtin_prefetch(next_columns_data[0],0,3);// 3 highest locality}// 当前批次处理for(size_t i0;irows;i){// 此时数据很可能已在 L1/L2 缓存中processRow(columns,i);}}// MergeTree 读取时的预取// 数据文件按 Mark 划分顺序扫描时可预测下一个 Mark 的位置for(size_t mark0;marknum_marks;mark){// 预取下一个 Mark 的数据if(mark1num_marks){size_t next_offsetmarks[mark1].offset_in_compressed_file;prefetch(compressed_filenext_offset);}processMark(marks[mark]);}2.5 NUMA感知让内存就近服务在多路服务器2路/4路上内存访问存在本地和远程的差异。NUMANon-Uniform Memory Access架构中每个CPU socket有自己本地的内存访问远程socket的内存延迟更高。NUMA 架构示意 (2路服务器): Socket 0 Socket 1 ┌─────────────┐ ┌─────────────┐ │ CPU Core 0 │◀────────────│ CPU Core 4 │ │ CPU Core 1 │ QPI Link │ CPU Core 5 │ │ CPU Core 2 │ (~100ns) │ CPU Core 6 │ │ CPU Core 3 │ │ CPU Core 7 │ ├─────────────┤ ├─────────────┤ │ Local Mem │ │ Local Mem │ │ (0-64GB) │ │ (64-128GB) │ │ 延迟: ~80ns │ │ 延迟: ~80ns │ └─────────────┘ └─────────────┘ 访问对方内存: ~180ns (100ns跨插槽延迟)ClickHouse通过ErrorHandler和MemoryTracker的配合实现了基础的NUMA感知每个线程尽量绑定到固定的NUMA节点数据处理时优先分配本地内存Merge操作时尽可能在本地节点完成3 哲学二算法在前抽象在后3.1 不为抽象牺牲性能ClickHouse的设计者有一个鲜明的立场当抽象与性能冲突时选择性能。这是一个务实到骨子里的哲学。许多现代软件系统追求零成本抽象Zero-Cost Abstraction即高层的抽象不引入任何运行时开销。但不引入任何开销的前提是抽象层本身的设计足够精妙。当抽象无法达到零开销时ClickHouse选择直接写代码。// ClickHouse 的做法: 拒绝过度抽象// ❌ 不推荐: 用标准库的 sort性能不够可控autosortedstd::sort(data.begin(),data.end());// ✓ 推荐: 写专用的高性能排序// 代码位置: src/Common/ColumnCompare.htemplatetypenameTvoidsortWithDefaultAlgorithm(T*data,size_t size){// 已知数据类型T可以使用最快的排序算法// 已知数据分布可以选择最优的Pivot策略// 已知内存布局可以预取数据pdqsort(data,size);// Pattern-Defeating Quicksort}// 或者完全内联的手写实现inlinevoidsortFloat(float*data,size_t n){// 浮点数排序有特殊优化空间// NaN 和 Inf 的处理可以专门优化std::sort(data,datan,[](floata,floatb){returnab;// 全内联无虚函数});}3.2 编译期多态 vs 运行时多态C提供了两种多态机制编译期的模板多态和运行时的虚函数多态。虚函数虽然灵活但每次调用都需要通过虚表vtable间接查找函数地址并可能破坏CPU的分支预测和指令流水线。ClickHouse的策略是优先使用模板编译期多态仅在运行时多态不可避免时才使用虚函数// 虚函数使用场景: 真正需要运行时替换的场景classIFunction{// 运行时需要动态选择函数public:virtualvoidexecute(Block,constColumnNumbers,size_t)0;virtual~IFunction()default;};// 模板使用场景: 类型在编译期确定无需运行时多态templatetypenameTclassColumnVector:publicIColumn{public:// 编译时确定类型无虚函数调用开销TgetElement(size_t n){returndata[n];}// 模板方法允许编译器完全内联templatetypenameOpvoidapplyUnary(constOpop){for(size_t i0;idata.size();i)data[i]op(data[i]);// 编译器完全内联}};性能对比实测Intel i9-9900K调用方式10亿次调用的耗时相对性能普通函数调用85ms1x虚函数调用220ms0.39x模板内联12ms7x模板 SIMD3ms28x3.3 特化优于泛化ClickHouse的Column实现为每种数据类型提供了专门的类——而不是用泛型覆盖所有情况。这种特化优于泛化的策略允许每种类型在底层采用最优的存储和处理方式// ClickHouse 的特化 Column 实现// Int8 (1字节整数) 专用列classColumnInt8{PaddedPODArrayInt8data;// 紧凑存储voidfilter(...){/* ... */}};// Float64 (8字节浮点) 专用列classColumnFloat64{PaddedPODArrayFloat64data;// SIMD友好对齐voidfilter(...){/* SIMD优化版本 */}};// 字符串专用列 - 完全不同实现classColumnString{StringRefs offsets;// 偏移量数组ArenaPtr arena;// 字符串数据池voidfilter(...){/* 字符串特有的复制逻辑 */}};// 对比: 通用设计// class GenericColumn { void * data; size_t element_size; }// ↑ 需要运行时判断类型增加分支和类型转换开销这种设计的代价是代码量增加——每种类型都需要独立的实现。但对于OLAP场景这是完全值得的类型种类有限~30种核心类型特化带来的性能收益远大于维护成本。4 哲学三勇于尝鲜不行就换4.1 ClickHouse对新技术的态度ClickHouse的代码库是业界新技术的试验场。它的设计者愿意大胆采用前沿技术但同时保持着清醒的判断——如果新技术表现不如预期就会果断放弃。ClickHouse积极采纳的新技术包括LLVM JIT编译将复杂表达式编译为机器码SIMD指令集从SSE4.2到AVX2再到AVX-512ZSTD压缩算法比LZ4更好的压缩率更快的解压速度C20协程在某些异步IO场景替代回调CRoaring位图高效的位图操作库4.2 JIT编译运行时代码生成ClickHouse的JITJust-In-Time编译功能是一个典型的勇于尝试案例。当表达式树过于复杂时解释执行仍会产生不可忽视的虚函数调用开销。ClickHouse通过集成LLVM在运行时将表达式编译为优化后的机器码// JIT 编译的工作流程// 代码位置: src/Interpreters/JITclassJITCompiler{LLVMContext context;IRBuilderbuilder;std::unique_ptrModulemodule;public:// 将表达式树编译为函数std::functionvoid(Block)compileExpression(constActionsDAGdag){// 1. 构建 LLVM IRFunctionType*ftFunctionType::get(builder.getVoidTy(),{block_ptr_type},false);Function*funcFunction::Create(ft,Function::ExternalLinkage,expr_func,module.get());// 2. 生成机器码// - 内联所有函数调用// - 选择最优的 SIMD 指令// - 重排指令以减少流水线停顿// 3. 编译并返回可执行函数autocompiledcompileModule(std::move(module));returncompiled;}};4.3 性能测试驱动决策ClickHouse为每项新技术的采纳设置了严格的门槛新技术必须通过基准测试证明确实有效才会被合并。这种数据驱动的决策方式避免了很多看起来很美的优化陷阱// 基准测试: 比较JIT与非JIT的性能voidbenchmarkJIT(){autoschemamakeSchema();autoquerySELECT sum(amount * price * 0.95) FROM orders GROUP BY category;// 非JIT执行autostart_jitlessnow();for(inti0;i1000;i){executeQuery(query,use_jitfalse);}autotime_jitlessnow()-start_jitless;// JIT执行autostart_jitnow();for(inti0;i1000;i){executeQuery(query,use_jittrue);}autotime_jitnow()-start_jit;std::coutJIT speedup: time_jitless/time_jitx\n;// 只有当 speedup 1.2 时才启用JIT}5 哲学四特定场景特殊优化5.1 OLAP场景的独特性ClickHouse的一切优化都围绕着OLAP场景展开。理解这个场景的特点才能理解这些优化的必要性OLAP 场景的四大特点 1. 读多写少 写入: 批量INSERT每天/每小时一次批量导入 读取: 大量并发SELECT高频分析查询 → 优化策略: 牺牲写入速度换取读取性能 2. 大宽表 多列聚合 表可能有100列单次查询可能聚合10-20列 → 优化策略: 列式存储 列裁剪 向量化聚合 3. 条件过滤 范围扫描 WHERE date BETWEEN 2024-01-01 AND 2024-01-31 → 优化策略: 主键稀疏索引 分区裁剪 跳表 4. 近似计算可接受 count(DISTINCT) 可以用 HyperLogLog 近似 → 优化策略: 提供多种精度/速度权衡的算法5.2 列式存储 稀疏索引的协同优化传统观点认为列式存储和稀疏索引是独立的设计决策。ClickHouse的创新在于将二者深度融合MergeTree 的数据组织: 稀疏索引 (每8192行一个索引点): ┌─────────────────────────────────────────────────────────┐ │ Mark#0: key1001 → Granule#0 (行0-8191) │ │ Mark#1: key2156 → Granule#1 (行8192-16383) │ │ Mark#2: key3892 → Granule#2 (行16384-24575) │ └─────────────────────────────────────────────────────────┘ 查询: WHERE user_id 3000 二分查找索引: Mark#0(key1001) 3000 Mark#1(key2156) 3000 Mark#2(key3892) 3000 ← 找到! 只需读取 Granule#2 IO量: 从 10亿行 减少到 8192行 (减少 ~12万倍!)5.3 聚合查询的特殊优化聚合是OLAP中最常见的操作ClickHouse为此设计了多层次优化优化一两阶段聚合SELECTuser_id,sum(amount)FROMeventsGROUPBYuser_id;阶段1(数据所在节点):SELECTuser_id,sum(amount)aspartialFROMeventsGROUPBYuser_id → 输出: {user_id: partial_sum} × N个不同的user_id 阶段2(汇聚节点):SELECTuser_id,sum(partial)FROMstage1_resultsGROUPBYuser_id → 输出: 最终结果 效果: 网络传输量从 全量数据 减少到distinct(user_id)×8字节 通常减少100-10000倍优化二聚合组合器的使用-- 原始查询计算不同城市的用户数SELECTcity,uniqExact(user_id)asexact_cnt,uniqHLL(user_id)asapprox_cnt,groupArray(limit5)(user_id)assample_usersFROMusersGROUPBYcity;-- uniqExact: 精确去重 (慢但准)-- uniqHLL: HyperLogLog近似 (快~100倍, 误差~2%)-- groupArray: 保留样本 (用于验证近似结果的准确性)优化三High-Cardinality优化的哈希聚合对于高基数的GROUP BY如用户IDClickHouse使用特殊的哈希聚合实现// 哈希聚合的向量化实现templatetypenameKey,typenameValuestructAggregatedDataWithOverflow{// 主哈希表: 存储大部分键值对FlatHashMapKey,Valuemain_table;// 溢出哈希表: 处理哈希冲突和极端情况FlatHashMapKey,Valueoverflow_table;};voidaggregateWithHash(Blockblock){// 对每一行: 计算hash → 查找/插入哈希表 → 更新聚合值// 所有操作都是向量化友好的for(size_t i0;iblock.rows();i){autokeykey_column-getHash(i);// SIMD hashautoithash_table.find(key);// 查找if(ithash_table.end()){hash_table[key]initial_value;// SIMD写入}else{it-secondvalue_column[i];// SIMD累加}}}5.4 低基数字符串的字典编码当某一列的取值种类很少时如国家代码、性别、状态枚举ClickHouse会自动使用字典编码Dictionary Encoding来优化存储和查询性能// 低基数列的存储结构classColumnLowCardinality:publicIColumn{private:// 字典: 存储所有不重复的值ColumnPtr dictionary;// 索引: 每行存储字典中的索引通常用 UInt32/UInt16PaddedPODArrayUInt32indexes;public:// 查询效果: 比较操作变为整数比较// WHERE country China// → 变为 WHERE index dictionary.find(China)// → 整数比较比字符串比较快 10-50 倍// 聚合效果: 哈希聚合只需对 UInt32 索引做哈希// 比直接对字符串哈希快 5-20 倍};6 哲学五持续测试持续改进6.1 基准测试文化ClickHouse有一个深入骨髓的测试文化。每一个性能优化都必须通过严格的基准测试验证否则不会被接受。ClickHouse维护的基准测试套件涵盖了端到端查询基准TPC-H、TPC-DS、自定义OLAP查询集微基准测试特定操作如哈希、排序、SIMD的单独测试回归测试确保优化不会引入性能退化压测工具clickhouse-bench、clickhouse-performance-test# 运行 ClickHouse 性能测试./clickhouse-bench --benchmark-filequeries.tsv\--iterations3\--max-time60s\--concurrency166.2 Yandex团队的内部实践在YandexClickHouse的诞生地ClickHouse的性能被持续追踪。每一次PR的性能影响都会被量化报告PR #45321: Optimize sum() with AVX-512 基准测试结果 (1亿行, 单核): ┌─────────────────────┬──────────────┬──────────┬─────────┐ │ 查询 │ 优化前 (ms) │ 优化后(ms) │ 加速比 │ ├─────────────────────┼──────────────┼──────────┼─────────┤ │ SELECT sum(x) │ 342 │ 89 │ 3.8x │ │ SELECT sum(xy) │ 521 │ 142 │ 3.7x │ │ SELECT avg(x) │ 378 │ 98 │ 3.9x │ │ SELECT sum(cnt) │ 289 │ 76 │ 3.8x │ └─────────────────────┴──────────────┴──────────┴─────────┘ 结论: AVX-512 优化在所有测试用例中均带来 ~3.8x 加速 未观察到缓存污染问题 合并: ✅ APPROVED6.3 版本迭代中的性能进化ClickHouse的版本历史本身就是一部性能优化的编年史版本关键性能改进性能提升1.1初始版本向量化执行引擎基准19.x物化视图正式版向量聚合2-5x20.xProcessor框架JIT编译实验1.5-3x21.xSIMD全面升级ZSTD压缩2-4x22.x持续聚合列式JOIN优化2-10x23.xAVX-512支持SIMD全面应用1.5-3x24.x更多JIT优化更好的NUMA感知持续改进6.4 使用clickhouse-benchmark进行对比测试对于ClickHouse的用户来说了解自己的查询性能瓶颈同样重要-- 使用EXPLAIN分析查询计划EXPLAINPIPELINESELECTuser_id,sum(amount)FROMeventsWHEREevent_date2024-01-01GROUPBYuser_idORDERBYsum(amount)DESCLIMIT10;/* 输出: (2) Sorting (LIMIT 10) │ Expression:(user_id, sum(amount)) │ Limit: 10 └────(1) Aggregating Expression: user_id Aggregating: sum(amount) Filter: event_date 2024-01-01 Parallel: Aggregating: 8 Repartition: 8 */通过EXPLAIN可以发现聚合操作的并行度8个并行流排序是否下推到了聚合前/后是否有不必要的表达式计算7 五大哲学的协同效应这五大设计哲学并非孤立存在它们在ClickHouse的架构中相互交织、相互强化┌──────────────────────────────────────────────────────────────┐ │ │ │ 着眼硬件 ─────────┐ │ │ │ │ │ │ │ ┌───────────┘ │ │ │ │ │ │ ├──→ 缓存友好 NUMA感知 高缓存命中率 ──→ 减少内存延迟 │ │ │ │ │ │ │ └───────────────────────────────────┐ │ │ │ ▼ │ │ │ 减少内存带宽争用 │ │ │ │ │ │ ├────────────────────────────────────────┘ │ │ │ │ │ 算法在前 ─────────┐ │ │ │ │ │ │ │ ┌───────────┘ │ │ │ │ │ │ ├──→ SIMD向量化 ◄──── 编译期特化 ◄──── 列式存储天然适配 │ │ │ │ │ │ │ └───────────────────────────────────┐ │ │ │ ▼ │ │ │ 单条指令处理多元素 │ │ │ │ │ │ ├────────────────────────────────────────┘ │ │ │ │ │ 特定场景特殊优化 ──→ 稀疏索引 谓词下推 IO量最小化 │ │ │ │ │ └──────────────────────────────────────────────┐ │ │ ▼ │ │ 综合效果: 亿级数据 毫秒级响应 │ │ │ │ 勇于尝鲜 ───→ JIT编译 ───→ 运行时优化 ───┐ │ │ │ │ │ 持续测试 ───→ 基准验证 ───→ 性能不退化 ───┘ │ │ │ └──────────────────────────────────────────────────────────────┘8 总结给我们的启示ClickHouse的五大设计哲学不仅是构建一款高性能OLAP数据库的方法论更是一套通用的性能工程原则着眼硬件先想后做在追求性能的道路上不理解硬件就如同盲人摸象。CPU缓存、SIMD指令、NUMA架构——这些硬件特性不是实现细节而是性能优化的第一性原理。算法在前抽象在后抽象是软件工程的好朋友但性能敏感代码需要警惕抽象带来的隐性成本。模板优于虚函数、特化优于泛化——这些选择需要根据具体场景权衡。勇于尝鲜不行就换技术世界变化迅速保持开放心态去尝试新技术是必要的。但尝试必须建立在数据基础之上——基准测试是唯一可信的判断标准。特定场景特殊优化通用的解决方案在特定场景下往往不是最优的。为OLAP场景量身定制的稀疏索引、字典编码、两阶段聚合都是特化优于泛化哲学的具体实践。持续测试持续改进性能优化不是一劳永逸的工作。建立完善的基准测试体系持续追踪性能变化才能确保系统在高水平上持续演进。掌握这五大哲学不仅能让我们用好ClickHouse更能帮助我们在任何需要极致性能的软件工程场景中做出正确的技术决策。上一篇【第07篇】ClickHouse执行引擎架构——Parser、Interpreter与Function体系下一篇【第09篇】ClickHouse安装部署全攻略——从环境准备到服务启动参考资料ClickHouse Architecture GuideLLVM DocumentationIntel 64 and IA-32 Architectures Optimization Reference Manual《计算机体系结构量化研究方法》《性能之巅系统、企业与云的可视化方法》ClickHouse GitHub Benchmarks

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2620270.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;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…