各位Cder好,我是长期混迹在金融系统开发前线的一名后端工程师。最近在帮业务线排查一个网络IO问题时,我发现了一个非常有意思的现象:每逢法定长假,我们接入的A股实时行情服务就会大量爆出超时日志,甚至引发上游服务的雪崩。经过深入的源码级排查,我意识到这不仅仅是简单的网络问题,而是业务场景与网络协议之间的碰撞。今天就来和大家硬核分享一下。

实时金融数据流的严酷要求

在我们这套架构里,我们需要通过WebSocket建立长连接,以极低的延迟接收股票的实时Tick信息。这对于需要进行实时计算的服务来说是刚需。但大家都知道,A股的运行时间是由各种法定节假日和调休决定的。这就意味着,我们的长连接在某些特定的日子里,会面临比平日里更早结束或者更晚开始的数据流阻断。

撕开网络底层的痛点表象

当我们用技术视角去透视这个问题时,节假日前后的异常其实可以归结为以下几个技术痛点:

  1. 连接的“假活”状态:A股节前提前休市后,服务端不再下发业务数据包。由于缺乏业务层的交互,如果客户端没有实现完善的应用层心跳(Ping/Pong),TCP连接很容易被沿途的路由器NAT表老化剔除,导致连接名存实亡。
  2. 重连风暴(Thundering Herd):节后开市的瞬间,如果大量断开的客户端同时发起重连请求,极易压垮行情源的网关,造成大面积的503错误。
  3. 数据反序列化地雷:由于休市期间数据管道可能会被用来做测试或重置,节后收到的首个JSON payload结构体可能发生变化,导致程序内抛出空指针或解析异常。

优秀的API是如何做产品隔离的?

要解决这些痛点,除了客户端要做防御外,服务端API的设计也至关重要。我查阅了多款行情API的官方文档,发现高标准的接口服务在休市状态机的处理上有一套成熟的逻辑。例如之前接入的AllTick API,在其服务端就实现了优雅的降级策略。在节后重启数据流时,它不会一上来就猛灌实时数据,而是先推送一个经过特殊标记的静态历史快照,用于验证连接质量并同步客户端状态,之后才开始稳定分发流式Tick。

来看看底层是怎么建立这套监听机制的:

import websocket
import json

def on_message(ws, message):
    data = json.loads(message)
    print("收到tick数据:", data)

ws = websocket.WebSocketApp(
    "wss://apis.alltick.co/stock/subscribe",
    on_message=on_message
)
ws.run_forever()

工程应用中的最终解决方案

作为工程师,我们绝不能把系统的稳定性寄托在外部接口的完美无缺上。针对节假日造成的断流,我在中间件层做了如下重构:
第一步:基于时间的黑白名单拦截。通过接入开源的交易日历库,精确计算当前是否处于开盘时间。在非交易时段,主动断开WebSocket连接,释放系统句柄资源。
第二步:实现带有退避的重连状态机。利用指数回退(Exponential Backoff)算法处理节后开盘的重连,有效规避惊群效应。
第三步:强类型的数据校验与缓冲。对所有通过WebSocket推过来的文本进行严格的JSON Schema校验。对于节假日异常期可能出现的缺失字段,利用本地的历史Redis缓存进行字段补齐。
搞定这些,你就再也不用在假期结束前一晚,提心吊胆地盯着监控大屏了。

Ubuntu 26.04 LTS (Resolute Raccoon) 正式版发布 - 现代化的企业与开源 Linux

Ubuntu 26.04 LTS (Resolute Raccoon) GA release Apr 2026

请访问原文链接:https://sysin.org/blog/ubuntu-2604/ 查看最新版。原创作品,转载请保留出处。

作者主页:sysin.org


Ubuntu 桌面

Ubuntu 26.04 LTS 正式版发布

Ubuntu 26.04 LTS Apps

2026-04-23,Ubuntu 26.04 LTS 正式版按计划如期发布。

Ubuntu 26.04 LTS 搭载 Linux 内核 7.0 和 GNOME 50 桌面环境,都是两个优雅的整数版本。

以下是笔者对 Ubuntu 26.04 LTS(Resolute Raccoon)发布摘要总结,对比 Ubuntu 24.04 LTS (Noble Numbat) 的更新内容:

桌面环境(Desktop)

  • 应用更新:Firefox 更新至 149/150,LibreOffice 24.2 → 25.8,Thunderbird 更新至 140 “Eclipse”,GIMP 2.10 → 3.0。
  • GNOME 50:从 46 升级至 50。支持登录后自动启动应用、优化分数缩放以减少模糊、默认等宽字体大小与 UI 字体匹配、默认安装 Sysprof 性能分析工具。
  • 默认应用替换: 文档查看器由 Evince 替换为 Papers(基于 GTK4 和 Rust)。图像查看器由 EOG 替换为 Loupe(Rust + Glycin)。终端由 GNOME Terminal 替换为 Ptyxis。视频播放器由 Totem 替换为 Showtime。音视频缩略图生成器由 Totem 缩略图器替换为 gst-thumbnailers(Rust GStreamer + Glycin)。
  • 搜索与索引:Tracker Miners 重命名为 LocalSearch(3.8.2 → 3.11),索引特定文件需勾选安装第三方软件或手动安装提取器。
  • 显示会话:Ubuntu 桌面会话仅运行在 Wayland 后端(GNOME Shell 不再支持 X.org),X11 应用可通过 XWayland 运行,其他桌面(KDE on X11, Xfce, MATE, i3 等)仍可使用 X.org。Nvidia 显卡现已完全支持 Wayland。
  • 软件管理:默认不再包含“Software & Updates”应用(可手动安装);App Center 改进(支持安装进度、自更新、Snap 消息、管理页直接卸载、触屏滚动、第三方 Deb 安装);新增 Security Center(支持家目录权限提示实验功能),附带 prompting-clientsnap。
  • 电源与性能:Power Profiles Manager 改进 (sysin),支持新硬件(尤其 AMD)、多优化驱动、电池感知(仅电池时自动提高优化级别);新增 NTSYNC 驱动,提升 Wine/Proton 上 Windows 游戏性能。
  • 安装与镜像:新增通用 ARM64 桌面 ISO(支持 VM、ACPI+EFI、骁龙 WoA 设备,含骁龙 X Elite 初始硬件支持);改进 BitLocker 保护下的 Windows 双启动体验(支持在旁安装、加密安装等高级选项)。
  • 格式与编解码:原生支持 JPEG XL;默认通过 VA-API 为 AMD 和 Intel 用户提供硬件加速视频编解码;安装时可选第三方软件包集更新(含蓝牙 AAC 编解码器)。
  • 更新与无障碍:系统更新不再弹窗抢焦点,改为通知+系统托盘图标;安装程序修复了大量屏幕阅读器无障碍问题。
  • 遥测:Ubuntu Insights 将取代 Ubuntu Report,提供对非个人识别系统指标的控制,且为选入制(之前同意不会沿用)。

服务器与常见组件

  • OpenSSH:9.6p1 → 10.2p1;弃用 SHA1 SSHFP DNS 记录警告、移除弱 DSA 签名算法支持、新增 PerSourcePenalties、默认支持 mlkem768x25519-sha256 后量子密钥交换、新增 invalid-user 匹配选项、sshd.service 别名为 ssh.service、新增 openssh-client-gssapi 和 openssh-server-gssapi 包、不再生成主机 DSA 密钥、服务器自 1:9.6p1-3ubuntu17 起不再读取 ~/.pam_environment。
  • 时间同步:Chrony 取代 systemd-timesyncd 作为默认时间守护进程(新安装),支持 NTS(认证加密 NTP),配置片段位于 /etc/chrony/sources.d/ubuntu-ntp-pools.sources
  • ClamAV:更新至 1.4.3,新增 OneNote 附件扫描、UDF 分区提取、HTML CSS 内嵌图像提取、alz/lha(lzh) 归档提取、图像模糊哈希开关、Office 文档 VBA 提取改进、--cache-size 自定义清理文件缓存、systemd.timer 用于 freshclam、大文件限制处理改进、私有 Freshclam 镜像客户端证书认证、病毒数据库最小年龄等。
  • Django:4.2 → 5.2 LTS。
  • PHP:更新至 8.5,包含属性钩子、非对称可见性、更新 DOM API、新 URI 扩展、管道运算符、Clone With、#[\NoDiscard] 属性、常量表达式中的闭包和一等可调用对象、持久 cURL 共享句柄、array_first() 和 array_last() 等。
  • Dovecot:更新至 2.4.2(配置格式有重大变更)。
  • Postfix:默认不再以 chroot 安装,且仅有有限的 chroot 支持。
  • RabbitMQ:无法直接升级 (sysin),需手动步骤(因特性标志)。
  • Samba:更新至 4.23 版本,默认启用 SMB3 Unix 扩展、禁用 NetBIOS,并包含大量 AD/DC 相关改进、功能移除及包结构变化,升级前需注意 AD DC 组件与 i386 支持情况。。
  • Squid:6 → 7.2;新增 tls_key_log、key-extras、doh_query、cache_peer tls-client-cert-switch;移除 client_delay_access、ftp_epsv、cache_peer no-netdb-exchange、client_persistent_connections、server_persistent_connections。
  • SSSD:2.12 版本,现以 sssd 用户(而非 root)运行,需确保其可访问密钥等。
  • strace:支持彩色输出(--color、STRACE_COLORS、NO_COLOR)。
  • HAProxy:更新至 3.2 LTS;有破坏性变更(如 Runtime API 多命令检测、dynamic server 拒绝 enabled 关键字、非标准 URI 更严格解析、tune.ssl.ocsp-update 重命名为 tune.ocsp-update)。
  • DocumentDB:新增,0.108-0 版本(基于 PostgreSQL 的 MongoDB 兼容文档数据库)。
  • MySQL:8.0 → 8.4 LTS(8.4.8),移除 32 位 Server 支持(仍提供 armhf/i386 的客户端和客户端库)。
  • MySQL Shell:8.0 → 8.4。
  • PostgreSQL:更新至 18(新 I/O 子系统、虚拟生成列、uuidv7()、OAuth 2.0 认证等)。
  • Valkey:更新至 9.0.3(原子槽迁移、哈希字段过期等)。
  • 容器栈:containerd 和 runc 采用定期最新或稳定更新策略。
  • 高可用与集群:kpartx-boot 包停用(功能并入 kpartx);dmraid 包移除(建议用 mdadm 替代);Pacemaker 更新至 3。

开发工具链

  • GCC 14 → 15.2,binutils 2.42 → 2.45,glibc 2.39 → 2.42。
  • Python 3.12 → 3.13.9(3.14 也可用)。
  • LLVM 18 → 21。
  • Rust 1.75 → 1.93(1.91、1.92 也可用)。
  • Golang 1.22 → 1.25。
  • Zig 新增,默认 0.14.1。
  • OpenJDK 21 → 25(LTS 8/11/17/21 仍可用,含 26、27 preview),其中 OpenJDK 25 在 AMD64/ARM64/s390x/PPC64EL 上 TCK 认证。
  • Spring® snaps:Gradle 和 Maven 插件可用于构建 Java 应用 ROCK 镜像。
  • GraalVM snap:支持 JDK 21/24/25。
  • .NET 8 → 10(并扩展至 IBM Power 平台),且有新版 .NET Snap。
  • PowerShell snap:扩展至 arm64、s390x、ppc64el 架构。

企业相关

  • authd(云认证)更新:EntraID 提供器修复与改进、新增 Google 提供器、支持 EntraID 设备注册、新增 authctl 命令行工具、UID/GID 处理等修复。
  • ADSys:Active Directory Group Policy 客户端支持最新 Polkit,改进证书注册。

安全

  • AppArmor:新增多个应用沙盒配置文件(可能需报 bug 调整)。
  • TPM 全盘加密:支持密码短语管理与恢复密钥再生、更好固件更新集成。
  • OpenSSL:支持 QUIC、后量子密码算法(ML-KEM、ML-DSA、SLH-DSA)、更广 EVP 覆盖及性能改进。
  • cargo-auditable:Launchpad 上构建的 Rust 包可选启用,二进制内嵌入依赖元数据供漏洞排查。

硬件支持

  • NVIDIA Dynamic Boost:在支持的 N 卡笔记本上默认启用(仅通电且 GPU 负载足够时生效,电池不生效)。
  • Intel 显卡:支持 Core™ Ultra Xe2 集成 Arc™、Arc™ B580/B570 Battlemage 独立 GPU;Blender 等光线追踪性能提升;Battlemage 上 AVC/JPEG/HEVC/AV1 硬件加速编码;Intel® Compute Runtime 新 CCS 优化;调试支持;oneAPI Level Zero Ray Tracing 提升 AI/ML(Embree on SYCL)。
  • Nvidia 挂起恢复:专有驱动中启用 suspend-resume 以防唤醒时损坏和冻结。
  • ARM64 桌面平台:linux-generic 内核提供更广 UEFI 启动兼容 (sysin)。
  • Raspberry Pi:新启动分区布局(测试新启动资源再提交,要求固件较新);Pi 桌面镜像改为基于 desktop-minimal 种子(默认应用更少,列出移除清单并可手动清理);swap 由 cloud-init 处理;RISC-V 仅支持 RVA23S64 ISA(无硬件时仅 QEMU -cpu rva23s64)。
  • IBM Z:最低要求 z15(不支持 z14/LinuxONE II 及更旧),z15 及更新性能提升。

通用/底层变化

  • sudo-rs:成为默认 sudo 提供器;原 sudo 重命名为 sudo.ws;sudo-ldap 包移除(建议用 PAM 做 LDAP 认证)。
  • rust-coreutils:操作系统核心工具(如 base64 等)默认由该包提供(性能提升),同时仍提供经典 GNU coreutils 并可切换。
  • Linux 内核:6.8 → 7.0;新增 sched_ext(eBPF 调度策略)、linux-lowlatency 包退休(改用 linux-generic + lowlatency-kernel 调 GRUB)。
  • systemd 255 → 259:26.04 是最后支持 System V 服务脚本兼容的版本;默认使用上游 tmp.mount 单元(/tmp 现为 tmpfs)。
  • Netplan 1.0 → 1.2:自定义 systemd-networkd-wait-online 逻辑、SR-IOV embedded-switch-mode 改进、解析器跳过损坏配置、ProtonVPN/Azure Linux 修复、wpa-psk-sha256 WiFi、NetworkManager 后端 routing-policy、非标准 OVS 设置支持。
  • APT 2.7 → 3.1:新依赖求解器、TLS/哈希从 GnuTLS/gcrypt 切换到 OpenSSL、apt(8) 增加自动分页器、apt-key 移除(直接用 gpgv)。
  • Dracut:取代 initramfs-tools 作为默认 initramfs 基础设施(仍支持 initramfs-tools 并可切换)。

Ubuntu Desktop 简介

安全、现代,被数百万人使用的操作系统

全球数百万 PC 和笔记本电脑正在使用的第一开源操作系统。

专业开发者的首选

每次 Ubuntu 发布都会带来最新的应用程序、库和工具链。Ubuntu 是主要 IDE、游戏开发工具和 AI/ML 软件的首要平台。

满足你日常使用的所有需求

Ubuntu 提供网页浏览、通讯、游戏与内容创作的必备应用,包括 Firefox、Chrome、Discord、Steam 和 OBS Studio,满足你日常计算的所有需求。

为隐私与安全而设计

通过定期更新和内置安全功能,Ubuntu 优先保护用户隐私与系统完整性,是注重数据安全用户的可靠之选。

深度集成企业工具

Ubuntu 无缝集成企业环境。通过 Ubuntu Pro 订阅,你可以获得运行 Ubuntu 于高安全环境所需的所有工具:安全修补、设备管理等。任何人都可以免费在最多 5 台设备上使用 Ubuntu Pro,企业用户可免费试用 30 天

完全开源

Ubuntu 始终免费供下载、使用与分享。我们相信开源的力量;如果没有全球志愿开发者社区,就不会有 Ubuntu。

Ubuntu Server 简介

借助 Ubuntu Server 实现横向扩展

Ubuntu Server 为企业数据中心(无论是公有云还是私有云)提供经济性与技术性的可扩展能力。无论你是要部署 OpenStack 云、Kubernetes 集群,还是一个拥有 50,000 个节点的渲染农场,Ubuntu Server 都能提供业界领先的高性价比横向扩展性能。

性能与多功能性

Ubuntu Server 获得领先硬件厂商(OEM)认证,提供精简的初始部署,并包含集成的部署与应用建模工具,因此你可以最大化利用基础设施资源——无论你在部署 NoSQL 数据库、Web 集群,还是云环境 (sysin)。

可靠的发布周期

Ubuntu Server 的长期支持(LTS)版本默认为 Ubuntu Main 软件仓库中约 2,500 个软件包提供五年的标准安全更新。每六个月发布一次的中期版本带来新功能,而硬件支持更新则为所有受支持的 LTS 版本提供最新机器的兼容支持。

最广泛使用且值得信赖的平台

根据 OpenLogic 2025 开源生态支持报告,Ubuntu 是私有云实施的基础,也是全球使用最多的 Linux 发行版(连续第三年位居第一)。

下载地址

Ubuntu 26.04 LTS (Resolute Raccoon) GA, 2026-04-23

  • Ubuntu 26.04 LTS (Resolute Raccoon) 64-bit PC (AMD64 x86_64) desktop image
  • Ubuntu 26.04 LTS (Resolute Raccoon) 64-bit PC (ARMv8 AArch64) desktop image
  • Ubuntu 26.04 LTS (Resolute Raccoon) 64-bit PC (AMD64 x86_64) server install image
  • Ubuntu 26.04 LTS (Resolute Raccoon) 64-bit ARM (ARMv8 AArch64) server install image
  • 请访问:https://sysin.org/blog/ubuntu-2604/

虚拟机模板下载:


更多:Linux 产品链接汇总

各位老哥们好,我是一个毕业工作 2 年的新人,最近领导在给我安排工作的时候我之前的工作喜欢和工作方式好像和他期待的不太一样。想发出来让大家分析下是我太学生思维了吗?


事件一 机器人验证

最近公司买了个机器人,他安排我去研究下,然后跑一个案例,能让他动起来。当时的原话是“你去跑一下网上这个案例,然后了解下他是怎么驱动起来的”

然后我就正常的跑官方案例,中间遇到很多环境,沟通的问题。重点是我对他的了解 可能只在表面,就是他是个什么,有哪些重要技术实现,然后基础的操作逻辑是什么。

但是事后领导让我分享的时候,会问的非常非常细致,比如这个技术 ROS 现在市场上使用情况怎么样,有没有其他控制方式,机器人我们如果自己独立二开应该是什么流程。

我总结一下是,我收到的消息是干 A 然后我根据字面意思理解为要做的任务,加一些必要的基础了解作为任务去做。
如果完全懂是 100 分,我感觉根据我的理解和他给我干的天数我做这个任务是 30 分。

但是他的要求和提问的内容我觉得算是 80 分。

事件二 硬件加速卡

最近让我调用一个 CGRA 的基础技术卡,
然后我就去看了下但是我只看了具体型号的卡,他的核心创新是什么,里面很多专有名词,我只理解个大概没有很深入的理解。

后面他问的时候就问的非常深入和广,比如这个 CGRA 技术实现原理,和 gpu ,ASIC 对比有什么优缺点,现在市场上还有谁在用。等等。


由此我有一个疑问,他交给我的任务可能是一句具体的话“跑下这个案例”“调研下 xxx 加速卡” 我理解的是字面意思+一些基础的必要知识信息。

但是他后续给我的资源(天数比较少)和要求给我的感觉是他需要一个很懂,或者是至少是 70 分的理解水平,不只是任务本身,他的生态,原理,对比起等.....

所有我想问下大多数工作都是这样的吗?是我太学生思维了还是一般情况下都会明确的告诉你你要干到是什么程度....

期望各位工作久了的前辈解惑下

看到很多 V 友发帖说 claude 账号被封问题,我目前是使用 GooglePlay 订阅的 20 美元的 Pro 套餐,已经稳定订阅一年左右了。
目前感觉额度不够用,想升级到 5X 的 MAX(对应官网是 100 美元的)。
请问下,之前出现封号的都是 MAX 套餐的吗?是 100 美元还是 200 美元的封号概率大些,还是说只要升级到任意 MAX 套餐都会有大概率被封。
目前我使用的是台湾住宅 IP(购买 IP 时人家是这样宣传的)

除了做 demo ,任何一个需要稳定性的系统都不应该使用 vibe coding 实现。全黑盒,完全不可控。
之前的一家公司,PM 开始自己 vibe coding ,推到上线后结果完全不可维护,到最后还是研发来擦屁股。产品爽了,最后烂摊子研发全接走?

https://developers.openai.com/api/docs/pricing?latest-pricing=standard

Model Input Credits Output Credits
GPT-5.3-Codex 43.75 350
GPT-5.4 62.50 375
GPT-5.5 125 750

天塌了啊,最新 openai 的模型越来越贵,穷人要用不起了啊

看 gpt5.5 的 token 价格翻倍了感觉不妙,结果一看 codex 消耗果然相比 5.4 也翻倍了

本来 codex 的 credit 计算规则改了后就明显消耗量加快了,结果现在 5.5 用量还翻倍了

然后 codex 中 5.5 默认的推理强度还是 extra high 。。。。。

当作和 opus 一样的高级模型好了。。。。

感觉很复杂,现在工作难度、工作强度相比之前大幅下降,但是工作内容的边界借助 AI 大幅拓展了,工作中的成就感其实是上升的,看到各种新模型的能力,也会觉得很欣喜

另一方面也确实会有一点被全面替代,无力抵抗的焦虑

好在目前这些感受还不影响我

简单试了下天气卡片,中文英文都试了,太简陋了:
图片.png

中文:

创建一个包含 CSS 和 JavaScript 的单一 HTML 文件,用于生成动画天气卡片。卡片应该通过不同的动画直观地表示以下天气状况:

风:(例如,移动的云朵、摇摆的树木或风线)

雨:(例如,下落的雨滴、形成的水坑)

阳光:(例如,闪耀的光线、明亮的背景)

雪:(例如,下落的雪花、积累的雪)

所有天气卡片应并排显示,卡片应该有深色背景。

在这个单一文件中提供所有 HTML 、CSS 和 JavaScript 代码。JavaScript 应该包含一种切换不同天气状况的方式(例如,一个函数或一组按钮)以展示每种天气的动画效果。

英文:

Create a single HTML file containing CSS and JavaScript to generate an animated weather card. The card should visually represent the following weather conditions with distinct animations: Wind: (e.g., moving clouds, swaying trees, or wind lines) Rain: (e.g., falling raindrops, puddles forming) Sun: (e.g., shining rays, bright background) Snow: (e.g., falling snowflakes, snow accumulating) Show all the weather card side by side The card should have a dark background. Provide all the HTML, CSS, and JavaScript code within this single file. The JavaScript should include a way to switch between the different weather conditions (e.g., a function or a set of buttons) to demonstrate the animations for each.

现在很多社会现象我觉得不好,但是往往它却很流行很潮流。下面列几个
1 无论男女,裤子前面的绳子,都快拖到地上了,这不是夸张,当然多数没那么长,但是我看起来总有违和感。我也有这样的裤子,每次我都塞到裤子,外面看不到。我依稀记得,在我小时候,村子里的傻子会把裤腰带这么松松垮垮的挂在那里。
2 有的男的跑步,穿紧身裤,胯下之物就那么突兀显现着。虽然女的的漏 b 的没那么违和,但是男的这样我真的不忍直视。

平时有不少,真的行之为文的时候,又想不起来了。 那就这些吧。

各位老哥们好,我是一个毕业工作 2 年的新人,最近领导在给我安排工作的时候我之前的工作喜欢和工作方式好像和他期待的不太一样。想发出来让大家分析下是我太学生思维了吗?


事件一 机器人验证

最近公司买了个机器人,他安排我去研究下,然后跑一个案例,能让他动起来。当时的原话是“你去跑一下网上这个案例,然后了解下他是怎么驱动起来的”

然后我就正常的跑官方案例,中间遇到很多环境,沟通的问题。重点是我对他的了解 可能只在表面,就是他是个什么,有哪些重要技术实现,然后基础的操作逻辑是什么。

但是事后领导让我分享的时候,会问的非常非常细致,比如这个技术 ROS 现在市场上使用情况怎么样,有没有其他控制方式,机器人我们如果自己独立二开应该是什么流程。

我总结一下是,我收到的消息是干 A 然后我根据字面意思理解为要做的任务,加一些必要的基础了解作为任务去做。
如果完全懂是 100 分,我感觉根据我的理解和他给我干的天数我做这个任务是 30 分。

但是他的要求和提问的内容我觉得算是 80 分。

事件二 硬件加速卡

最近让我调用一个 CGRA 的基础技术卡,
然后我就去看了下但是我只看了具体型号的卡,他的核心创新是什么,里面很多专有名词,我只理解个大概没有很深入的理解。

后面他问的时候就问的非常深入和广,比如这个 CGRA 技术实现原理,和 gpu ,ASIC 对比有什么优缺点,现在市场上还有谁在用。等等。


由此我有一个疑问,他交给我的任务可能是一句具体的话“跑下这个案例”“调研下 xxx 加速卡” 我理解的是字面意思+一些基础的必要知识信息。

但是他后续给我的资源(天数比较少)和要求给我的感觉是他需要一个很懂,或者是至少是 70 分的理解水平,不只是任务本身,他的生态,原理,对比起等.....

所有我想问下大多数工作都是这样的吗?是我太学生思维了还是一般情况下都会明确的告诉你你要干到是什么程度....

期望各位工作久了的前辈解惑下

除了做 demo ,任何一个需要稳定性的系统都不应该使用 vibe coding 实现。全黑盒,完全不可控。
之前的一家公司,PM 开始自己 vibe coding ,推到上线后结果完全不可维护,到最后还是研发来擦屁股。产品爽了,最后烂摊子研发全接走?

https://developers.openai.com/api/docs/pricing?latest-pricing=standard

Model Input Credits Output Credits
GPT-5.3-Codex 43.75 350
GPT-5.4 62.50 375
GPT-5.5 125 750

天塌了啊,最新 openai 的模型越来越贵,穷人要用不起了啊

看 gpt5.5 的 token 价格翻倍了感觉不妙,结果一看 codex 消耗果然相比 5.4 也翻倍了

本来 codex 的 credit 计算规则改了后就明显消耗量加快了,结果现在 5.5 用量还翻倍了

然后 codex 中 5.5 默认的推理强度还是 extra high 。。。。。

当作和 opus 一样的高级模型好了。。。。

各位Cder好,我是长期混迹在金融系统开发前线的一名后端工程师。最近在帮业务线排查一个网络IO问题时,我发现了一个非常有意思的现象:每逢法定长假,我们接入的A股实时行情服务就会大量爆出超时日志,甚至引发上游服务的雪崩。经过深入的源码级排查,我意识到这不仅仅是简单的网络问题,而是业务场景与网络协议之间的碰撞。今天就来和大家硬核分享一下。

实时金融数据流的严酷要求

在我们这套架构里,我们需要通过WebSocket建立长连接,以极低的延迟接收股票的实时Tick信息。这对于需要进行实时计算的服务来说是刚需。但大家都知道,A股的运行时间是由各种法定节假日和调休决定的。这就意味着,我们的长连接在某些特定的日子里,会面临比平日里更早结束或者更晚开始的数据流阻断。

撕开网络底层的痛点表象

当我们用技术视角去透视这个问题时,节假日前后的异常其实可以归结为以下几个技术痛点:

  1. 连接的“假活”状态:A股节前提前休市后,服务端不再下发业务数据包。由于缺乏业务层的交互,如果客户端没有实现完善的应用层心跳(Ping/Pong),TCP连接很容易被沿途的路由器NAT表老化剔除,导致连接名存实亡。
  2. 重连风暴(Thundering Herd):节后开市的瞬间,如果大量断开的客户端同时发起重连请求,极易压垮行情源的网关,造成大面积的503错误。
  3. 数据反序列化地雷:由于休市期间数据管道可能会被用来做测试或重置,节后收到的首个JSON payload结构体可能发生变化,导致程序内抛出空指针或解析异常。

优秀的API是如何做产品隔离的?

要解决这些痛点,除了客户端要做防御外,服务端API的设计也至关重要。我查阅了多款行情API的官方文档,发现高标准的接口服务在休市状态机的处理上有一套成熟的逻辑。例如之前接入的AllTick API,在其服务端就实现了优雅的降级策略。在节后重启数据流时,它不会一上来就猛灌实时数据,而是先推送一个经过特殊标记的静态历史快照,用于验证连接质量并同步客户端状态,之后才开始稳定分发流式Tick。

来看看底层是怎么建立这套监听机制的:

import websocket
import json

def on_message(ws, message):
    data = json.loads(message)
    print("收到tick数据:", data)

ws = websocket.WebSocketApp(
    "wss://apis.alltick.co/stock/subscribe",
    on_message=on_message
)
ws.run_forever()

工程应用中的最终解决方案

作为工程师,我们绝不能把系统的稳定性寄托在外部接口的完美无缺上。针对节假日造成的断流,我在中间件层做了如下重构:
第一步:基于时间的黑白名单拦截。通过接入开源的交易日历库,精确计算当前是否处于开盘时间。在非交易时段,主动断开WebSocket连接,释放系统句柄资源。
第二步:实现带有退避的重连状态机。利用指数回退(Exponential Backoff)算法处理节后开盘的重连,有效规避惊群效应。
第三步:强类型的数据校验与缓冲。对所有通过WebSocket推过来的文本进行严格的JSON Schema校验。对于节假日异常期可能出现的缺失字段,利用本地的历史Redis缓存进行字段补齐。
搞定这些,你就再也不用在假期结束前一晚,提心吊胆地盯着监控大屏了。

各位老哥们好,我是一个毕业工作 2 年的新人,最近领导在给我安排工作的时候我之前的工作喜欢和工作方式好像和他期待的不太一样。想发出来让大家分析下是我太学生思维了吗?


事件一 机器人验证

最近公司买了个机器人,他安排我去研究下,然后跑一个案例,能让他动起来。当时的原话是“你去跑一下网上这个案例,然后了解下他是怎么驱动起来的”

然后我就正常的跑官方案例,中间遇到很多环境,沟通的问题。重点是我对他的了解 可能只在表面,就是他是个什么,有哪些重要技术实现,然后基础的操作逻辑是什么。

但是事后领导让我分享的时候,会问的非常非常细致,比如这个技术 ROS 现在市场上使用情况怎么样,有没有其他控制方式,机器人我们如果自己独立二开应该是什么流程。

我总结一下是,我收到的消息是干 A 然后我根据字面意思理解为要做的任务,加一些必要的基础了解作为任务去做。
如果完全懂是 100 分,我感觉根据我的理解和他给我干的天数我做这个任务是 30 分。

但是他的要求和提问的内容我觉得算是 80 分。

事件二 硬件加速卡

最近让我调用一个 CGRA 的基础技术卡,
然后我就去看了下但是我只看了具体型号的卡,他的核心创新是什么,里面很多专有名词,我只理解个大概没有很深入的理解。

后面他问的时候就问的非常深入和广,比如这个 CGRA 技术实现原理,和 gpu ,ASIC 对比有什么优缺点,现在市场上还有谁在用。等等。


由此我有一个疑问,他交给我的任务可能是一句具体的话“跑下这个案例”“调研下 xxx 加速卡” 我理解的是字面意思+一些基础的必要知识信息。

但是他后续给我的资源(天数比较少)和要求给我的感觉是他需要一个很懂,或者是至少是 70 分的理解水平,不只是任务本身,他的生态,原理,对比起等.....

所有我想问下大多数工作都是这样的吗?是我太学生思维了还是一般情况下都会明确的告诉你你要干到是什么程度....

期望各位工作久了的前辈解惑下

目前版本更新到 v0.2.13 了(基本是周一到周五每天都会更新)和 WorkBuddy 越来越像了。

  1. 新版中和 WB 一样,增加了【专家】替换掉了原来的【灵感】

image

  1. 连接应用管理增加了很多

image

  1. 对话信息流比以前方便很多,如:文件直接显示图标,点击即可打开;侧边栏打开可以看到任务背景、文件、专家等关键信息

image

  1. 增加了【文件】标签,找相关文件方便了

image

  1. 增加了一些高级功能设置

image

下面再说说不好的地方

6.和 WB 一样,计量单位从【token】变成了【积分】,原来每天 4000 万 token,现在是 800 积分。主页面也不显示用量了,但是免费的大模型倒是可以自选了,费率不同。

image

image

7.存在【抱歉,这个问题我暂时无法解答,让我们换个话题吧~】,之前都是正常的,个人也没觉得这是敏感的内容。

image

总结:总体来说还是进步明显,帮我做了很多工作中低质量又不得不做的内容,完成的相当好,稳定性也提高了很多,和 WorkBuddy 还是有一些侧重上的差异,下次分享另一个的感受。

背景

最近写项目发现了一个有意思的报错。我发现它让人摸不到头脑,甚至每次写到新增登录方式必然会报一次错。

报错截图

可以看到是由于懒加载,导致的无法处理代理对象。
image.png

问题代码复现

验证过滤器拿认证用的方法代码:

   @Override
    @Transactional
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        if (username.length() == 28) {
            return this.loadByWechatOpenid(username);
        } else {
            // 学生登录
            Optional<User> userOfStudent = this.loadBySno(username);
            if (userOfStudent.isPresent()) {
                return userOfStudent.get();
            }

            // 正常登录方式
            User user = this.userRepository.findByPhone(username).orElseThrow(() -> new UsernameNotFoundException("e"));
            user.getAuthorities();
            return user;
        }
    }

     /**
     * 学号登录
     * */
    private Optional<User> loadBySno(String sno) {
        Optional<Student> studentOptional = this.studentRepository.findBySnoAndDeletedFalse(sno);
        if (studentOptional.isPresent()) {
            Student student = studentOptional.get();
            if (student.getUser() == null) {
                User user = this.saveByStudent(student.getName(), student.getSno());
                student.setUser(user);
                this.studentRepository.save(student);
                return Optional.of(user);
            }
            return Optional.of(student.getUser());
        }
        return Optional.empty();
    }

报错方法代码:

@Entity
@Data
public class User {
 
    ...

    // 默认是懒加载
    @ApiModelProperty("角色")
    @ManyToMany
    @JsonView(RolesJsonView.class)
    private Set<Role> roles = new HashSet<>();

    ...

    @JsonView(AuthoritiesJsonView.class)
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        if (null == this.authorities) {
            Set<String> authorities = new HashSet<>();
            // 这行报错
            if (null != this.getRoles() && !this.getRoles().isEmpty()) {
                authorities = RoleServiceImpl.getGrantedAuthorities(this.getRoles());
            }
            this.authorities = authorities.stream().map(authority -> (GrantedAuthority) () -> authority)
                    .collect(Collectors.toSet());
        }
        return this.authorities;
    }
}

解决方案

这里先告诉一下解决方案,先在方法上添加@Transactional,在从数据库拿到user时,在方法结束前调用user.getAuthorities()。其实这里调用user.getRoles()是一样可以的。

 private Optional<User> loadBySno(String sno) {
        Optional<Student> studentOptional = this.studentRepository.findBySnoAndDeletedFalse(sno);
        if (studentOptional.isPresent()) {
            Student student = studentOptional.get();
            if (student.getUser() == null) {
                User user = this.saveByStudent(student.getName(), student.getSno());
                student.setUser(user);
                this.studentRepository.save(student);
                // 在返回user的时候调用一下,getAuthorities()方法即可
                if (user != null) {
                    user.getAuthorities();
                }
                return Optional.of(user);
            }
            if (student.getUser() != null) {
                student.getUser().getAuthorities();
            }
            return Optional.of(student.getUser());
        }
        return Optional.empty();
    }

探究原因

什么是懒加载?实际上就是用了代理模式的方法,减小程序的处理压力。
用一个简单的例子来说:现在有clazz,student和teacher3个实体,他们3个各自有20个属性。在我们日常开发中,对于一个实体并不会把它所有的属性都使用上,相反,而是使用几个属性。那这对服务器来说不久加载了一堆没用的信息吗,我内存就那么大。Spring Boot说:有了我用代理模式不就好了吗。我把@Transactional删除后,它就报错了,实际上这个schedules的类型是List<Schedule>他这里变成PersistentBag类型。它里面没有数据,就报错了。
image.png

另一个问题

理解了什么是懒加载,以及如何解决上面的问题之后,下面介绍另一个看起来毫无关联但实际上也与懒加载有关系的问题。可以看到下面的报错也很神奇:状态码是200,却是报错了。
image.png
一头雾水的时候,先去看控制台->网络。发现了一个有趣的问题,数据太长了,数据可能被截断了,浏览器觉得不是json数据。实际上是实体对象互相嵌套导致的,schedule中有course,course中有courseItem,courseItem中有schedule...然后就导致了这个问题。
image.png

解决方案

在courseItem中的schedule属性加上jsonView。这样可以控制controller返回数据时返回实体的数据,这里不细讲。

@Setter
@Getter
@Entity
public class CourseItem extends BaseEntity{
    ...

    @ManyToOne(fetch = FetchType.LAZY)
    @JsonView(ScheduleJsonView.class)    // 加上这行
    @ApiModelProperty("课程计划")
    private Schedule schedule;

    public interface ScheduleJsonView {}
    ...
}

@RestController
@RequestMapping("schedule")
public class ScheduleController {
   ...
   @GetMapping("getAllByCurrentTermAndCurrentUser")
    @JsonView(GetAllByCurrentTermAndCurrentUserJsonView.class)
    public List<Schedule> getAllByCurrentTermAndCurrentUser() {
        Term term = this.termService.getCurrentTerm();
        if (term == null) {
            return List.of();
        }
        return this.scheduleService.getAllByCurrentTermAndCurrentUser(term);
    }

    private interface GetAllByCurrentTermAndCurrentUserJsonView extends
            Schedule.CourseJsonView,
            Schedule.ClazzJsonView,
            Schedule.Teacher2JsonView,
            Schedule.Teacher1JsonView,
            Course.CourseItemJsonView,    
            GetSchedulesInCurrentTermJsonView {
    }

    ...
}

有趣的思考

两个报错看起来感觉都没什么关联,为什么放到一起。想想我们刚刚讲的懒加载,对于一个实体,加上了@OneToMany等的属性,他是不能拿到值的,我们得在一个加了@Transactional的方法结束前get一下才能显示。上面的代码很明显,就从数据库中拿了数据,按道理不会显示这些关联实体属性(如courseItem)。

遗漏报错信息

其实在最开始关于懒加载的报错最后有一个no session的信息。这个session和HTTP session是一个东西吗?显然不是的。用一个生动的例子讲一下这个session是什么,有什么作用,会做什么。

懒加载问题继续探讨

把 User(用户)想象成一份档案,而 User 拥有的 roles(角色/权限)是贴在这份档案上的标签。

延迟加载(Lazy Loading
Hibernate 为了省事,在从数据库取出 User 档案时,故意没有立刻把标签(roles)也取出来,而是贴了一张写着“需要时再去拿”的便利贴。这张便利贴就是一个代理对象。

Session(会话)是负责取资料的人
在 Hibernate 里,真正能从数据库里帮你把数据拿出来的那个“办事员”,就是 session。他只在“数据库操作期间”上班。

懒加载问题发生的瞬间
在业务代码(认证逻辑)里:
先从数据库通过 session 拿到了 User 档案,此时标签还没取,只有便利贴。
数据库操作很快结束了,Spring 自动把 session 关闭了,办事员下班走了。
接着,Spring Security 要检查这个用户的权限,就调用了 user.getAuthorities(),实际上就是想看看便利贴上对应的标签到底写的是什么。

这时候,程序试图通过便利贴去找办事员(session)去数据库里真正取标签,但办事员已经下班(session 已关闭),没办法取了。于是它就报错:

LazyInitializationException: could not initialize proxy - no session
(延迟加载初始化失败 —— 因为没找到会话)

简单说就是:要用的数据在需要被真正读取的时候,负责取数据的“连接”已经断开了。

请求实体过长导致的问题

那么在返回请求的时候开启了session?是的。
Spring Boot 默认配置 spring.jpa.open-in-view=true ,它的作用就是:把 Hibernate 的 session 从你查询数据库一直活到 HTTP 响应写完为止。

时间线是这样的:

请求到达:DispatcherServlet(Spring MVC 核心)开始处理这个请求,OSIV 拦截器立刻为当前线程绑定一个 Hibernate session。

进入控制器方法:你通过 professorRepository.findById(id) 去查教授。这条 SQL 只查了教授表,学生列表并没有被查出来。返回的 Professor 对象里,students 其实是一个“代理对象”(便利贴),正等着有人来真正读取它。

方法返回:控制器返回 Professor 对象。Spring MVC 发现你要输出 JSON(因为 @RestController),于是开始对这个对象进行序列化,为的是生成字符串发给前端。

序列化过程触发了读取:Spring 用 Jackson 把 Professor 转成字符串时,会通过 getter 方法读它的每一个属性。当读到 getStudents() 时,触发了代理对象。Hibernate 发现这个代理需要初始化,于是去数据库执行 SQL 把学生列表查出来。

session 还活着,查询成功:此时 OSIV 绑定的那个 session 还没有关闭,所以 Hibernate 能够顺利执行 SQL,返回完整的学生列表。于是 Jackson 拿到了完整的集合,最终生成的 JSON 里就包含了教授和他的学生。

响应写完后:HTTP 响应完全返回给前端,Spring MVC 工作结束,OSIV 拦截器关闭 session。

对于session的思考

session那么好用为什么要关掉,一直开着不好吗?

每个 Session 背后都占着一个“物理数据库连接”

数据库连接数非常有限。比如你的数据库配置了最大 50 个并发连接。
如果一个请求处理了 1 秒钟,Session 开了 1 秒,那么 50 个请求同时进来刚好用满。
如果你一直不关 Session,它就一直占着这个连接。请求处理完了,用户慢悠悠看前端页面(持续几分钟),连接就一直被扣着。用不了多久,连接池就会被耗尽,新的请求再也拿不到数据库连接,整个系统瘫痪。
数据库连接是非常宝贵的资源,必须“快借快还”。

内存会爆掉

session 是一个“一级缓存”,它会一直跟踪你加载过的所有对象,并给它们拍快照(用于脏检查)。
一个请求你查了 10 个教授,它记着 10 个对象。
如果不关闭,随着时间累积,这个 session 缓存里的对象会越来越多,历史查过的东西全堆在里面,而且因为被 Session 引用着,GC 也不能回收。
最终就是内存泄漏(OOM)。

数据一致性问题(很严重)

session 有“重复读”的保证:同一个 session 里查同一个 ID 两次,第二次直接给你缓存里的旧对象,根本看不到数据库的最新变化。
如果 session 一直开着,用户张三在 10:00 查了一个教授的薪水是 1 万。
10:05 管理员在其他系统里把薪资改成了 2 万并提交了。
10:10 张三再次在这个一直开着的 Session 里查这个教授,看到的还是 1 万,因为 session 还拿着旧缓存。
一个长期存在的 session,相当于一直活在“事务快照”里,完全无法跟数据库同步。

所以,session 必须设计成“即用即关”的短生命周期。它的职责就是服务好“一次业务操作”或“一次 HTTP 请求”。做完事赶紧关,释放连接、释放内存、下次查询拿到新数据。

总结

  1. 对于在Spring Boot的实体中的有@OnToMany等注解的属性,会默认开启懒加载,你不访问这个属性它就不加载出来。
  2. 由于我们使用的是Spring Boot过滤器链实现的登录功能,我们需要显示的开启session或者用上文的方法。
  3. Spring Boot会启用默认配置 spring.jpa.open-in-view=true, 把 Hibernate 的 session 从你查询数据库一直活到 HTTP 响应写完为止。
  4. 用一个JPA中的话说Hibernate中的session就是Entitymanager。

    参考

    Hibernate ORM 用户指南:https://docs.hibernate.org/orm/5.4/userguide/html_single/#pc-...
    JPA配置:https://docs.spring.io/spring-boot/appendix/application-prope...

一场面试 11 连问,背八股很容易当场露馅

刚开始做 Go 微服务那会儿,我以为面试就两类题:写算法背八股
后来才发现,很多面试官真正喜欢的,是这种“连环追问”:

你会用就行?那你说说为什么这么用;你说它快?那你说说快在哪;你说系统稳定?那你说说极端情况下会发生什么

下面这篇面经不讲经历,只给你面试题 + 示例回答(并附带常见追问)。

如果你能把这些回答“讲顺”,大概率能过掉后端/微服务方向的核心拷问。

🪤 1)context 怎么用的?

面试官:context 你项目里怎么用?

很多人的“标准答案”是:context 就是用来传参的,或者加个超时。

但面试官真正想听的是:你是否理解它的边界传播链路

示例回答(面试版)

  • context 主要解决 3 件事:取消(cancel)超时/截止时间(deadline)跨边界的请求级元数据(value)
  • 我会把 ctx 作为函数的第一个参数,沿调用链往下传到所有可能阻塞的地方:DB/Redis/HTTP/gRPC/MQ publish 等。
  • 在入口(HTTP/gRPC handler)会拿到一个“请求根 ctx”,然后在内部需要更强约束的地方派生子 ctx:WithTimeout/WithCancel
  • WithValue 只放请求范围必须跨 API 边界的元数据(比如 traceId、userId),不把业务参数塞进去,更不会把 ctx 存到 struct 里长期持有。
func (s *Service) CreateOrder(ctx context.Context, req *CreateOrderReq) error {
    ctx, cancel := context.WithTimeout(ctx, 2*time.Second)
    defer cancel()

    // 1) 传给 DB / RPC / Redis
    if err := s.repo.InsertOrder(ctx, req); err != nil {
        return err
    }

    // 2) 自己的 goroutine 也要“跟着 ctx 退出”
    go func() {
        select {
        case <-ctx.Done():
            return
        case <-time.After(200 * time.Millisecond):
            _ = s.metrics.Report(req.OrderID) // 示例:真正实现里也应传 ctx
        }
    }()

    return nil
}

常见追问(别踩坑)

  • context 里为什么不建议传业务参数?”——因为可读性差、无类型约束、容易滥用;更重要的是会让 ctx 的语义从“控制与元信息”变成“万能背包”。
  • “如果下游不支持 ctx 怎么办?”——包一层适配,或者保证取消时能主动关闭连接/停止消费,至少让 goroutine 能退出。

⚡ 2)为什么选 ES?ES 为什么快?

面试官:你们为什么用 Elasticsearch?它为什么快?

如果你只说“全文检索、分词”,基本等于没答。

示例回答(面试版)

  • 选 ES 是因为我们需要:全文检索 + 相关性排序 + 聚合分析 + 横向扩展,而这些在 MySQL 上靠 LIKE '%xx%' 或冗余字段很难做,且代价很高。
  • ES 快主要来自 Lucene 的索引结构与查询执行方式:

    • 倒排索引:从“词 -> 文档列表”,检索是集合运算,不是全表扫。
    • 段(segment)+ 不可变:写入先 refresh 成段,查询直接命中段文件,读路径更稳定。
    • 列式存储(doc values)与缓存:聚合/排序更高效;filter 走缓存、bitmap 等结构,速度明显。
    • 分片并行:一个 query 可以在多个 shard 上并行执行,再汇总结果。
  • 我们会把 ES 的角色定位成“检索与分析引擎”,主数据仍以 DB 为准,ES 通过增量同步/异步消费来更新,接受一定的最终一致

常见追问(面试官爱追)

  • “ES 写入也很快吗?”——写入是吞吐型,refresh/merge 有成本;高写入要控制 refresh interval、合理分片、避免频繁更新同一文档导致段合并压力。
  • “为什么不用 PG 的全文检索?”——可以用,但在相关性、生态、横向扩展、聚合性能上各有取舍;我们偏向 ES 的成熟度与运维经验(按你项目实际说)。

🔌 3)模块之间的通信怎么做的?

面试官:你们服务/模块之间怎么通信?

示例回答(面试版)

  • 同步链路用 gRPC:IDL 清晰、性能好、统一错误码与超时控制,配合拦截器做 logging/trace/metrics。
  • 异步链路用 MQ 事件通知:把“必须立即返回”的路径做短,把“最终一致即可”的动作下沉到异步(比如发券、写日志、触发索引更新)。
  • 关键点是把工程问题讲清楚:超时/重试/幂等/顺序性/重复消费/可观测性
同步(gRPC)适合:
  + 强依赖、必须拿到结果(比如查库存、查配置)
异步(MQ)适合:
  + 最终一致、允许延迟(比如通知、异步落库、索引更新)

常见追问

  • “既然用 MQ,怎么保证不丢?”——生产端 confirm、持久化;消费端手动 ack;失败重试 + 死信;业务幂等兜底。

🐇 4)为什么选 RabbitMQ?

面试官:你们为什么是 RabbitMQ,不是 Kafka?

示例回答(面试版)(按你项目取舍讲):

  • 我们更看重低延迟、灵活路由、可靠投递、易运维

    • Exchange(direct/topic/fanout)路由能力强,适合业务事件分发。
    • 支持 ack、重回队列、死信队列、延迟队列(常见实现)等,做“业务兜底”很方便。
    • 对“任务队列/事件通知”这种模式很顺手。
  • Kafka 更偏“高吞吐日志流”,我们这类“业务事件 + 路由 + 消费确认”场景更贴 RabbitMQ 的模型。

常见追问

  • “RabbitMQ 性能不如 Kafka 你怎么看?”——是的,吞吐上 Kafka 更强,但选型要看指标:我们更在意路由与投递语义;并且我们当前量级 RabbitMQ 足够,后续量级变化再做架构演进。

🆚 5)RabbitMQ 和 Kafka 的主要区别?

这题建议你直接给“对比维度”,面试官听得最舒服。

示例回答(面试版)

维度RabbitMQKafka
模型队列/交换机路由分区日志(log)
消费以投递/确认为核心以 offset/重放为核心
历史消息通常消费即删除(按队列语义)按保留策略长期保存,可重放
吞吐中高(偏低延迟业务)很高(大吞吐流式)
顺序性单队列可保证分区内有序
典型场景业务事件、任务队列、复杂路由埋点日志、流式计算、CDC、事件总线

补一句更像“项目经验”的话:

我们用 RabbitMQ 做“业务事件通知”,用 Kafka(如果有)做“日志/埋点/CDC 流”,这样职责更清晰。

🌳 6)B+ 树的本质是什么?

面试官:B+ 树你怎么理解?“本质”是什么?

示例回答(面试版)

  • B+ 树的本质是:为磁盘/页存储设计的多路平衡搜索树,目标是用更大的扇出(fan-out)降低树高,从而减少 I/O 次数。
  • 它把数据(或主键)集中在叶子节点,内部节点只存索引键;叶子节点通过链表相连,因此:

    • 等值查询:从根到叶,I/O 次数可控;
    • 范围查询:定位到起点叶子后顺序扫,顺序 I/O 更友好。
  • 这也是为什么像 InnoDB 这类存储引擎会基于 B+ 树做索引:既能查得快,又能把范围与排序做得更自然。

常见追问

  • “B 树和 B+ 树差在哪?”——B 树数据可在内部节点;B+ 树数据都在叶子,范围扫描更稳。

📮 7)channel 了解多少?

面试官:Go 的 channel 你了解多少?有缓冲/无缓冲差别?

示例回答(面试版)

  • chan 是 Go 的并发通信原语,本质是“同步/队列化的通信通道”,用来在 goroutine 之间安全传递数据。
  • 无缓冲 channel:发送与接收必须同时准备好,天然同步(更像 rendezvous)。
  • 有缓冲 channel:缓冲没满时发送不阻塞;缓冲为空时接收阻塞;常用于削峰或做 worker pool。
  • 关闭语义:

    • 关闭后仍可接收(收到零值 + ok=false),但再发送会 panic;
    • 通常由发送方关闭,接收方不要随便 close(除非你能保证只有你在发送)。
select {
case v := <-ch:
    _ = v
case <-ctx.Done():
    return ctx.Err()
}

常见追问(高频坑)

  • nil channel:收发都会永久阻塞,常用于在 select 里动态开关分支。
  • “怎么避免 goroutine 因 channel 卡住?”——配合 context、超时、或明确关闭通道;不要让 for { <-ch } 在没有退出条件的情况下跑。

⚙️ 8)GMP 模型:如果阻塞了会怎么样?

面试官:讲讲 GMP,如果 goroutine 阻塞了会怎样?

示例回答(面试版)

  • G = goroutine,M = OS thread,P = 调度器的逻辑处理器(持有本地队列与运行时资源)。
  • 正常情况下:P 把可运行的 G 放到本地队列,绑定到某个 M 上执行。
  • 阻塞分两类(这是加分点):

    • 网络 I/O:Go 有 netpoll,通常会把 G 挂起(park),让 M 继续拿 P 跑别的 G,不会“卡死整个线程”。
    • 系统调用/长时间阻塞:M 可能被内核阻塞,运行时会把 P 从这个 M 上“摘”下来,交给别的 M 继续跑,必要时会创建新的 M 顶上。
  • 如果阻塞点没有退出条件(比如一直等 channel/锁、ctx 不取消),就可能出现协程泄漏:G 一直挂着,资源慢慢被吃光。

常见追问

  • “Go 不是有抢占吗?”——是的,新版本支持异步抢占,但它解决的是“长时间计算不让出 CPU”的问题;对“等待某个永远不会发生的事件”无能为力,所以还是要设计退出机制。

🧩 9)为什么要有 P?

面试官:有了 G 和 M,为什么还要 P?

示例回答(面试版)

  • P 的作用是把调度从“全局抢锁”变成“本地队列优先”,降低竞争:每个 P 有自己的 run queue,大多数调度都在本地发生。
  • P 也承担了运行时的一些资源绑定(比如某些缓存/状态),并通过 GOMAXPROCS 控制并行度:最多同时有多少个 P 在跑,也就最多同时跑多少个 goroutine(严格说是同时执行的 G 的数量上限)。
  • 没有 P 的话,所有 M 都去抢全局队列锁,调度开销会显著上升,尤其在高并发下。

🕳️ 10)什么情况下会协程泄漏?

面试官:协程泄漏你遇到过吗?一般怎么发生?

示例回答(面试版)

  • channel 永久阻塞:发送方没人接、接收方没人发;或者 for range ch 等不到 close。
  • 忘记取消/超时:内部起 goroutine 做重试/轮询,但 ctx 用了 context.Background() 或者忘了 cancel()
  • ticker/timer 没停time.NewTicker 没有 Stop(),goroutine 一直被唤醒做无意义工作。
  • 资源未关闭导致阻塞:网络连接、文件句柄不关,读写 goroutine 卡在 I/O 上。
  • fan-out 没收敛:每个请求开 N 个 goroutine,缺少并发上限/缺少 errgroup 统一回收。
g, ctx := errgroup.WithContext(ctx)
g.Go(func() error { return s.callA(ctx) })
g.Go(func() error { return s.callB(ctx) })
return g.Wait()

面试官喜欢听到的“工程化收尾”:

我会给所有后台 goroutine 一个明确的退出条件(ctx / close channel / done),并且在压测和线上用 pprof 看 goroutine 数是否稳定。

🐳 11)讲一下 Docker 和 K8s

面试官:Docker 和 K8s 你怎么理解?区别是什么?

示例回答(面试版)

  • Docker 解决的是“怎么把应用和依赖打包并一致运行”:镜像(image)是交付物,容器(container)是运行态。
  • K8s 解决的是“一堆容器怎么在集群里自动化运维”:调度、扩缩容、滚动升级、自愈、服务发现、配置管理。
  • 常用对象我能讲清楚:

    • Deployment:无状态应用的发布与滚动升级
    • Service:稳定访问入口(负载均衡/服务发现)
    • Ingress:HTTP 路由入口(配合 Ingress Controller)
    • ConfigMap/Secret:配置与密钥
    • HPA:按指标自动扩缩容
    • StatefulSet:有状态服务(按需)

一句话总结(很好用):

Docker 更像“把程序装进标准集装箱”,K8s 更像“港口调度系统”,负责把集装箱放到合适的船上、坏了自动换、忙了自动加船。

✅ 总结:面试官其实在考什么?

当这些题连着问的时候,面试官通常不是要你背概念,而是看你有没有三种能力:

  • 能否把“会用”讲成“为什么这么用”(context、channel)
  • 能否把“选型”讲成“约束 + 取舍”(ES、RabbitMQ vs Kafka)
  • 能否把“并发”讲成“极端情况 + 退出机制”(GMP、协程泄漏)
你不需要把每个点都讲到论文级别,但你需要在关键处“说出底层原因”,并且能落到工程实践的兜底方案上。

END

写在最后:

最近私信问我面试题的小伙伴实在太多了,一个个回有点回不过来。

我大家公认最容易挂的 AI/Go/Java 面试坑点 整理成了一份 PDF 文档。里面不光有题,还有解题思路和避坑指南。

想要的同学,直接加我微信wangzhongyang1993,或者关注并私信我 【面试】,我统一发给大家。