三行代码背后的宇宙:当美军封锁霍尔木兹海峡,你的系统能扛住吗?

news2026/4/15 4:45:05
The chain is only as strong as its weakest link. - Thomas Reid什么是短链接这道题的完整解法短链接URL Shortener把一个很长的网址变成一个简短的链接用户点击短链接系统自动跳转到原始地址。核心操作只有两个操作输入输出encodehttps://www.example.com/very/long/urlhttp://tinyurl.com/aB3decodehttp://tinyurl.com/aB3https://www.example.com/very/long/url完整实现代码import string class Codec: def __init__(self): self.code_to_url {} self.url_to_code {} self.base_url http://tinyurl.com/ self.chars string.ascii_letters string.digits # a-z A-Z 0-9共62个字符 self.counter 0 def encode(self, longUrl: str) - str: Encodes a URL to a shortened URL. if longUrl in self.url_to_code: return self.url_to_code[longUrl] self.counter 1 num self.counter if num 0: code self.chars[0] else: res [] base len(self.chars) while num 0: res.append(self.chars[num % base]) num // base code .join(reversed(res)) self.code_to_url[code] longUrl self.url_to_code[longUrl] code return self.base_url code def decode(self, shortUrl: str) - str: Decodes a shortened URL to its original URL. code shortUrl.replace(self.base_url, ) return self.code_to_url.get(code, )如果不用 counter会怎样counter是整个设计的核心。一旦去掉它你必须找到另一种方式生成唯一短码。常见的两种替代方案都有致命缺陷替代方案一随机生成字符串随机选6个字符如xYz123作为短码可能碰巧和已有的短码重复。缺陷你需要一个while循环反复查库检查是否冲突再重试。系统越满冲突越频繁速度越不可预测。极端情况下退化为 O(N)甚至引发级联故障。替代方案二对 URL 做哈希MD5/SHA对longUrl求哈希取前6个字符作为短码。缺陷哈希同样会碰撞两个不同的 URL 哈希后前6位相同。你仍需要复杂的冲突重试逻辑且还有安全风险哈希反推。系统设计核心结论用自增计数器再做 Base62 转换是工业界最成熟的方案大规模落地时用 Redis、ZooKeeper 或 Twitter Snowflake 实现分布式计数器。它提供两个关键保证方向性Directionality编号单调递增时序天然有序无碰撞Collision Elimination整数序列不会重复从数学上消灭了碰撞的可能encode函数真正做到 O(1) 引子当封锁消息炸开2000万人同时点击同一个链接2026年某日美军宣布对霍尔木兹海峡实施封锁。消息在社交媒体瞬间爆炸。一个记者发出的突发新闻链接被疯狂转发——某平台的阅读量在10分钟内突破了2000万。后台工程师的分享链接服务在那个瞬间承受了无法预测的洪峰流量。有人的服务扛住了。有人的没有。差距不在于服务器多几台。差距在那三行代码里。while num 0: code self.chars[num % len(self.chars)] code num // len(self.chars)如果你也觉得这只是进制转换那么这篇文章就是为你准备的。第一幕孙悟空与如来佛的赌约——普通工程师的认知陷阱先讲一个故事。西游记里孙悟空飞到天涯海角在一根石柱上留下了齐天大圣到此一游然后自信满满回来告诉如来我能跳出你的手掌心。如来淡淡一笑展开手掌——那根石柱就在他的中指旁边。孙悟空的问题不是能力不行。他的问题是他只看到了局部以为那就是全部。在短链系统的设计里99%的工程师都是那个刚写出上面三行代码、兴冲冲告诉面试官我懂Base62的孙悟空。他们确实懂Base62。但他们不知道自己站在谁的手掌心里。让我们来一层层剥开这个手掌心。第二幕代码层——当你以为你写对了其实你写出了一个定时炸弹 逐行解剖这三行代码到底在做什么首先让我用你最熟悉的方式解释这个算法的本质进制转换。还记得小学数学125这个数字是怎么构成的1 × 100 百位2 × 10 十位5 × 1 个位如果我们不用0-9这10个数字而用62个字符a-z, A-Z, 0-9来表示同样的逻辑成立——这就是Base62。代码里的每一步num % len(self.chars)→ 取出当前最低位对应的字符索引self.chars[...]→ 把索引映射成字符code char code→ 拼到字符串最前面← 问题就在这里num // len(self.chars)→ 整除把最低位扔掉处理高位听起来很完美对吗但这里藏着两颗地雷。普通工程师一个都发现不了Principal工程师能找出来并说清楚为什么。 地雷一隐藏的 O(N²) ——你以为在做加法其实在搬家Python里的字符串是不可变对象Immutable Object。这意味着每次执行code char codePython在背后做的事情不是在字符串前面加一个字符——而是开辟一块全新的内存空间把新字符和旧字符串的每一个字符全部复制进去丢弃原来那块内存想象一下你在搬家。你每搬进来一件新家具都要先把所有旧家具搬出去拿到新房子再把新家具搬进去再把所有旧家具搬回来。一件家具时搬1趟。两件时搬2趟。N件时搬了123...N N²/2趟。这就是O(N²)的时间和空间浪费。专业写法只要一行改动性能提升从量变到质变# ❌ 普通写法 — 每次循环都搬一次家 code self.chars[num % base] code # ✅ Principal写法 — 先存起来最后一次性拼接 res [] while num 0: res.append(self.chars[num % base]) # O(1)只追加到列表末尾 num // base code .join(reversed(res)) # 一次性拼接O(N)一个用的是list.append()一个用的是字符串拼接。表面上差不多背后的内存分配行为天差地别。这就是为什么同样会写Base62资深工程师和普通工程师的代码在高并发下性能可以差10倍。 地雷二Counter从0开始——你的系统能在用户注册第一个链接时就崩溃看这段代码while num 0: ...如果num 0会发生什么循环直接跳过。返回的code是空字符串。然后你把这个空字符串存进数据库作为用户注册的第一条短链接。然后用户点击了这个链接……系统崩了。这是个典型的Corner Case。而在真实的工程实践里self.counter从0开始或者计数器被重置是完全可能发生的场景。用MECE原则Mutually Exclusive and Collectively Exhaustive完全穷尽、相互独立来看数值的状态空间是状态num 0num 0num 0原始代码能处理吗✅❌❌正确的写法是在循环之外加一个判断if num 0: code self.chars[0] # 0 对应 a作为第一个合法短码 else: res [] base len(self.chars) while num 0: res.append(self.chars[num % base]) num // base code .join(reversed(res))在Principal面试中能一眼发现这个Corner Case就已经把大多数候选人甩在了身后。第三幕算法层——为什么O(1)是一个哲学结论而不是数学结论这里有一个被绝大多数工程师搞混的概念。有人会问这个while循环明明要执行log₆₂(num)次怎么能说是O(1)这个问题问得好。答案需要从三个维度来理解维度一系统上下文让常数变得不存在在URL短链系统里短码长度通常限定在6-7位。6位Base6262⁶ ≈ 568亿条7位Base6262⁷ ≈ 3.5万亿条哪怕你的系统存储了3.5万亿条短链接while循环最多执行7次。在Big-O分析里O(7) O(1)。当一个操作的上界是个极小常数时我们称之为Bounded Constant Time有界常数时间。维度二最关键的O(1)——你消灭了查重这个不确定性怪兽真正理解这个O(1)要把它和随机生成短码的方法对比。随机生成法的步骤随机生成6个字符去数据库查这个短码已经存在了吗存在回到第1步重新生成不存在好存进去随着数据库里的短链越来越多设总量为N碰撞的概率越来越高重试次数越来越多。在极端情况下这个方法的时间复杂度会退化到O(N)甚至触发系统雪崩。而Counter Base62方法建立的是一个从整数到字符串的双射Bijection每个整数唯一对应一个字符串每个字符串唯一对应一个整数绝对不冲突因为底层的整数自增序列绝对不重复这等于从架构上彻底删除了查重这个操作。消灭了随机性消灭了重试消灭了碰撞。执行路径单向、确定、恒定。这才是真正工程意义上的O(1)。维度三用物理学打个比方诺贝尔物理学奖得主理查德·费曼说过如果你真正理解了一件事你应该能用简单的语言解释它。用自由能原理Free Energy Principle来类比随机生成法 热力学的无序状态熵极高惊奇极多你不知道下次会不会碰撞Counter Base62 引入严格因果关系熵为0系统不确定性降为最低好的算法设计本质上是在降低系统的计算自由能。第四幕为什么要自己写Base62——三个你从没想过的理由很多人会问Python有hex()有base64库为什么不用这个问题是区分初级工程师思维和架构师思维的分水岭。原因一Python原生不支持Base62技术限制方法支持进制字符集大小bin()2进制2个字符oct()8进制8个字符hex()16进制16个字符int(s, base)最大36进制36个字符0-9a-z自研Base6262进制62个字符Python的int(s, base)最大只支持Base36因为它不区分大小写字母。要同时使用大小写字母26261062必须自己实现。原因二信息密度的碾压——Base62 vs Base16假设我们用hex()Base16来存短链6位十六进制16⁶ 16,777,216 ≈1677万条按Bitly的量级几个月就耗尽了6位Base6262⁶ ≈568亿条同样长度多表示3380倍的数据为了达到Base62的容量Base16需要9-10位字符。你的短链会变成bit.ly/a3f8bc09e——这还算短链吗这是信息论的胜利。在相同的字符长度下Base62的信息密度是Base16的log(62)/log(16) ≈ 1.54倍。原因三URL安全性——一个会在生产环境爆炸的隐患Python标准库的base64.b64encode()使用的字符集包含、/、这三个字符在URL中是保留字符Reserved Characters在URL中代表空格/代表路径分隔符在查询字符串中有特殊含义如果你的短链包含这些字符浏览器会把https://example.com/aB/c解析成https://example.com/aB%20%2Fc%3D——不仅破坏了链接还让短链更长了。Base62只使用[a-zA-Z0-9]100% URL Safe无需任何转义。隐藏原因四Principal专属安全混淆的自由度如果用标准进制转换发号顺序是a, b, c, d, e...竞争对手只需要递增访问你的短链就能轻松爬取你系统里所有的URL统计你每天的业务量。这叫IDOR不安全的直接对象引用漏洞。但因为Base62是自己实现的我们只需要在初始化时打乱字符表import random import string chars list(string.ascii_letters string.digits) random.shuffle(chars) # 在系统启动时随机打乱一次永久固化 self.chars .join(chars)仅仅通过打乱这个字母表不引入任何加密开销发号器发出的1, 2, 3就会映射成X3m、Kq7、9Rn这样的随机外观——用极低的CPU成本在数学映射层面实现了安全混淆。第五幕从单机到分布式——那个藏在self.counter里的定时炸弹当你在面试里写出这段代码面试官最希望你主动开口说的是这句话这段代码在单机上完美运行但在真实的分布式系统中self.counter是一个致命的单点瓶颈。为什么想象一下100台Web服务器同时调用self.counter 1。如果这个counter只存在每台机器的内存里那100台机器完全独立自增会同时发出ID1, ID1, ID1...——100个相同的短码映射到100个不同的长链。系统彻底乱了。问题的三个层次层次一并发冲突Race Condition多线程环境下单机的self.counter本身就是线程不安全的。counter 1这个操作在Python里不是原子操作即使有GIL在某些情况下依然会出问题。层次二多节点冲突多台服务器之间没有共享状态各自独立计数ID必然重复。层次三单点宕机如果counter存在内存里服务器宕机重启counter归零。所有新生成的短码与历史短码冲突。 Principal级解决方案预分配号段池架构Token Range Server这是业界标准的分布式发号器设计被美团、微博、滴滴等大厂广泛采用┌─────────────────────────────────────────────────────────┐ │ ZooKeeper / etcd │ │ (全局计数器当前发到了10000) │ └────────────────┬────────────────┬──────────────────────-┘ │ │ ┌────────▼───────┐ ┌─────▼────────┐ │ Web Server 1 │ │ Web Server 2 │ │ 号段: [1, 1000] │ │号段:[1001,2000]│ │ 本地counter: 42 │ │本地counter: 1150│ └────────────────┘ └──────────────┘工作原理Web服务器启动时向ZooKeeper申请一个号段比如1000个IDZooKeeper原子性地将全局计数器推进1000返回[1, 1000]给Server 1Server 1在本地内存中从1自增发号完全不需要网络请求当本地号段耗尽时再去申请下一批[2001, 3000]为什么这个设计是天才之举第一性原理分析把原本需要每次都跨网络的分布式锁操作降维成了纯本地内存O(1)操作即使ZooKeeper短暂宕机Web服务器依靠本地缓存的号段依然能存活相当长时间哪怕服务器宕机丢失的号段最多1000个相比于3.5万亿的总空间九牛一毛关于丢号的哲学很多人会担心服务器宕机没用完的号段丢了怎么办这里有一个非常深刻的工程哲学我们用极少量且极廉价的ID碎片空间换取了系统架构的极度简单、无锁化处理和超高吞吐量。 宁可让ID序列不连续也绝不引入脆弱且沉重的回收机制。这与Twitter Snowflake算法的设计理念完全一致——时间戳空转时浪费序号是刻意为之的设计权衡而非缺陷。第六幕Feistel密码——让短码既无碰撞又无规律等等我们刚才用了号段池解决了冲突问题。但还有一个安全隐患没解决打乱self.chars只是一种弱混淆而不是真正的安全。如果攻击者通过逆向分析找到了你的字符表顺序依然能预测你的短码规律。有没有办法在保持双射绝不冲突的前提下让生成的短码呈现完全随机的分布答案是Feistel密码网络Feistel Cipher Network。Feistel网络的神奇之处在于它是一种可逆的置换Reversible Permutation。无论你输入什么它都能给你一个唯一的输出且这个映射是一一对应的——完美保持双射性质。def feistel_encrypt(n, rounds4, key0xDEADBEEF): 将输入的整数n映射到一个完全不同的整数保证双射 left n 16 right n 0xFFFF for i in range(rounds): new_left right new_right left ^ ((right * key i) % (1 16)) left, right new_left, new_right return (left 16) | right # 使用方式在Base62转换前先对counter做一次Feistel加密 def encode(self, longUrl): self.counter 1 shuffled_num feistel_encrypt(self.counter) # 打散单调性 code self._base62_encode(shuffled_num) # 再转Base62 ...输入1, 2, 3...输出完全随机的整数再经过Base62转换得到的短码看起来毫无规律但每个都保证唯一。这才是真正的工业级安全混淆把双射的数学特性发挥到了极致。第七幕分布式存储——那个叫self.code_to_url的字典终将成为回忆在面试里很多人把短链系统的分布式存储设计答成了用MySQL就好了。Principal级别的候选人会从三个核心问题出发反向推导存储方案问题一读写比是多少URL短链系统是典型的读多写少场景。用户创建链接写一次但每次分享出去可能有成千上万次点击读。读写比通常在100:1以上。问题二数据模型复杂吗核心数据就两张表ShortCode → LongURL用于重定向解析LongURL_Hash → ShortCode用于去重可选几乎没有复杂的JOIN操作完全是Key-Value读取。问题三数据量有多大按Bitly的量级数十亿甚至百亿条记录。结论NoSQLCassandra/DynamoDB是首选特性MySQL/PostgreSQLCassandra/DynamoDB水平扩展需要手动分库分表原生支持读写性能受限于单机线性扩展运维复杂度分库分表极复杂相对简单强一致性✅可调最终一致完整的三级存储架构用户请求 → 布隆过滤器无效请求拦截 → Redis L1本地缓存 → Redis集群缓存 → Cassandra每一层都比上一层慢10-100倍但容量大10-100倍。第八幕布隆过滤器——那个神奇的差不多数据结构当系统规模达到亿级别直接去Redis或Cassandra查这个短码存不存在在高并发下会把存储层打挂。这时候我们需要一个能以极低代价回答这个短码一定不存在的工具。**布隆过滤器Bloom Filter**就是这个工具。它的工作原理用一句话概括布隆过滤器可以100%确定地告诉你这个元素绝对不在集合里。但它告诉你在可能是谎言假阳性。这个有限度的谎言就是布隆过滤器的魔法所在。对于短链系统的防穿透场景攻击者随机生成短链访问 → 布隆过滤器说不存在 → 直接返回404不查数据库 ✅布隆过滤器说存在 → 可能是假阳性 → 去数据库查一次最多增加1次DB读 ✅用极小的内存几百MB存几十亿条记录换取了对绝大多数无效请求的O(1)拦截。分布式环境下的布隆过滤器同步在多台服务器的环境里布隆过滤器的同步是个挑战。三种主流方案方案ARedisBloom集中式强一致把布隆过滤器存在Redis里所有Web服务器共享优点架构简单强一致缺点每次查询都有网络开销约1-2ms高并发下Redis成为热点方案B本地内存BF Kafka广播最终一致极致性能每台机器维护独立的本地BF新增元素时通过Kafka通知所有节点更新本地BF优点查询延迟纳秒级本地内存vs Redis相差10000-50000倍缺点存在Kafka延迟造成的短暂不一致方案C离线定时重建 S3全量拉取适合黑名单类静态数据每天凌晨用大数据任务重建BF存入S3各服务器定时拉取最新版本双Buffer热切换优点架构解耦极其稳定缺点实时性差选型原则黄金圈法则从为什么出发——你引入布隆过滤器是为了保护数据库不被无效请求打挂。如果QPS在10万以内RedisBloom足够了因为Redis完全能扛住。如果QPS在百万级别你需要本地BF Kafka因为百万QPS打向同一个Redis节点会把它打挂。这就是架构设计的第一性原理从你要解决的核心问题出发而不是从你熟悉的技术方案出发。 布隆过滤器的删除难题布隆过滤器有一个致命限制标准实现不支持删除。因为多个不同的元素可能对应相同的Bit位如果把Bit从1改成0会误删其他元素。解决方案定期重建最简单有效每天重跑一次基于数据库活跃记录构建新BF布谷鸟过滤器Cuckoo Filter支持删除且空间效率更高是现代替代品计数布隆过滤器Counting Bloom Filter用小整数代替单比特支持删除但内存占用增加4倍第九幕热点攻击防御——当霍尔木兹封锁新闻链接遭到DDoS回到开篇的场景。霍尔木兹封锁消息爆发某个突发新闻链接被转了2000万次。这不是攻击这是自然流量洪峰但对后端的破坏效果和DDoS没有区别。这种场景叫**热点KeyHot Key**问题同一个短码被集中访问打向Redis集群的同一个分片Shard超过单节点的10万QPS上限。多级防御架构Defense in Depth第一级L1本地微缓存TTL1-2秒# 在每台Web服务器的内存里缓存最近访问的URL from cachetools import TTLCache local_cache TTLCache(maxsize10000, ttl2) # 只存最热的1万条2秒过期 def get_long_url(short_code): # 先查本地内存 if short_code in local_cache: return local_cache[short_code] # 纳秒级返回 # 本地未命中查Redis url redis.get(short_code) if url: local_cache[short_code] url return url # Redis未命中查DB...TTL只有2秒但面对百万QPS100台服务器的本地缓存各自承担每台只承受1万QPS。每台服务器每2秒只向Redis发送1次查询请求。百万QPS被降维成了100次/2秒50次QPS打向Redis。第二级Singleflight请求合并当本地缓存和Redis同时失效缓存雪崩大量并发请求同时冲向数据库import threading singleflight_locks {} lock threading.Lock() def get_with_singleflight(short_code): with lock: if short_code not in singleflight_locks: singleflight_locks[short_code] threading.Event() should_fetch True else: event singleflight_locks[short_code] should_fetch False if should_fetch: try: result fetch_from_db(short_code) # 通知所有等待的请求 singleflight_locks[short_code].result result singleflight_locks[short_code].set() return result finally: del singleflight_locks[short_code] else: event.wait() # 等待第一个请求完成 return event.result # 共享结果无论有多少并发请求打到数据库的永远只有1个。第三级布隆过滤器随机无效请求拦截如果攻击者不是打同一个真实短码而是打随机生成的不存在的短码缓存穿透布隆过滤器在第一道关卡就把它们全部拦截。整体防御流程图用户请求 │ ▼ [L1本地缓存] ──命中──→ 立即返回纳秒级 │未命中 ▼ [布隆过滤器] ──不存在──→ 404无效短码无DB开销 │可能存在 ▼ [Redis集群缓存] ──命中──→ 返回毫秒级 │未命中 ▼ [Singleflight合并] ──仅1个请求穿透──→ 数据库 │ ▼ 结果回填所有层级缓存第十幕RedisBloom的分片——突破单节点10万QPS天花板很多工程师以为上了Redis ClusterQPS就能线性扩展了。这是个危险的误解。Redis Cluster的分片是基于Key的CRC16(key) % 16384。如果你只有一个名叫bf:global_urls的布隆过滤器Key无论集群有多少台机器这个Key永远落在一台固定的物理节点上。那10万QPS的天花板依然是天花板。解决方案客户端预分片Client-side Pre-sharding把一个逻辑上的布隆过滤器物理上拆成N个独立的子Keyimport mmh3 # MurmurHash3散列性优秀 def get_bloom_shard_key(element: str, num_shards: int 1024) - str: 根据元素内容决定它该存在哪个分片 hash_val mmh3.hash(element) shard_id hash_val % num_shards return fbf:urls:{shard_id} # 添加元素 def bf_add(short_code: str): shard_key get_bloom_shard_key(short_code) redis.execute_command(BF.ADD, shard_key, short_code) # 查询元素 def bf_exists(short_code: str) - bool: shard_key get_bloom_shard_key(short_code) return redis.execute_command(BF.EXISTS, shard_key, short_code)关键设计原则分片数要远大于当前物理节点数错误的做法3台机器拆成3个Key。为什么错因为未来扩容到4台时取模变成%4所有路由映射全部作废已经存入BF的元素全部找不到了——相当于系统瞬间失忆。正确的做法哪怕现在只有3台机器也要拆成1024个Key。这1024个Key由Redis Cluster通过Hash Slot均匀分散到所有节点。未来扩容时Redis Cluster在后台自动迁移Slot客户端代码一行不用改。这就是分布式系统设计里的预分片Pre-sharding哲学为未来的自己留好扩容空间。结语差距到底在哪里孙悟空最后从如来掌心逃不掉不是因为他的技术不行。是因为他没有系统性地思考自己所处的世界。同样的道理初级工程师看到这三行代码看到的是进制转换。中级工程师看到它看到的是O(N²)和Corner Case。高级工程师看到它看到的是分布式发号器、双射、Feistel加密、事务一致性。Principal工程师看到它看到的是霍尔木兹封锁新闻流量洪峰下这个系统扛得住吗如果扛不住从哪里开始加固这就是差距。它不在于你知道多少技术名词而在于你能不能从一行代码出发看到整个分布式系统的骨架系统思考你能不能在做每个技术决策时说清楚你的Trade-off是什么架构直觉你能不能识别出那些隐藏的O(N²)、隐藏的Corner Case、隐藏的单点故障底层洞察王阳明说知行合一。知道这些不等于会用这些。下一次你写代码时停一秒想一想如果这段代码要承受一条突发全球大事件新闻链接的流量洪峰它会在哪里断掉

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