Linux 的 rwx 权限是什么意思?为什么文件不能写,却仍然可能被删除?
系统解释 Linux 文件与目录 rwx 的不同含义,说明只读文件删除、目录搜索、属主组判断与 sticky bit、ACL 等限制,提供只读排查思路和最小权限原则。
短链接、秒杀、文件上传等完整系统的需求、模块协作、容量、容错与取舍,不重复单个组件的原理题。
共 23 篇文章
系统解释 Linux 文件与目录 rwx 的不同含义,说明只读文件删除、目录搜索、属主组判断与 sticky bit、ACL 等限制,提供只读排查思路和最小权限原则。
准确区分 Java BIO、NIO、AIO 的阻塞、就绪和完成语义,说明 Selector、FileChannel、异步通道与虚拟线程边界,避免把 NIO 全部说成非阻塞。
系统解释 Feed 推、拉与混合模式,区分内容和候选列表,分析大粉丝写放大、活跃关系、合并排序、游标分页、删除与权限变化的工程取舍。
用完整消息生命周期设计即时通讯,解释请求去重、持久确认、会话顺序、离线补拉和多端游标,区分连接传输、送达与已读,并列出故障验收场景。
提供 TS、Python 合并区间实现,解释左端点排序、包含关系与不变条件,区分闭区间和半开区间,分析最后追加、输入校验及时间空间复杂度。
提供 TypeScript、Python 三数之和实现,解释排序双指针的移动依据、固定数与命中去重,用重复负数算例说明下标与数值区别及完整复杂度。
对比链地址法与开放寻址法,通过冲突和删除算例解释探测路径、墓碑、实际键比较、负载因子与扩容,说明平均复杂度和最坏情况边界。
通过页框访问例子解释 FIFO、LRU 和 Clock,讲清引用位、第二次机会、精确维护成本与 Belady 异常,区分操作系统页置换和应用缓存。
区分 MTU、MSS、TCP 分段和 IP 分片,用 1500/1460 算例说明头部与路径前提,解释 IPv6、路径 MTU 和网卡卸载造成的抓包差异。
客观比较 Redis 与 Memcached 的数据语义、可靠性、容量和分布责任,用完整缓存链解释纯缓存选型、节点故障、回源压力及一致性边界。
解释 MySQL 普通视图与基础表的关系,说明查询定义、执行成本、可更新与可插入条件、WITH CHECK OPTION 和权限边界,避免误当物化缓存。
从 InnoDB 聚簇与二级索引解释自增 ID、UUID 主键取舍,分析长度、随机插入、UUIDv7、BINARY 存储及内部主键和外部标识分离方案。
区分 MySQL 慢 SQL 与长事务,解释锁、读取视图和 undo 清理影响,提供活跃事务只读查询,说明 Sleep 会话、回滚成本及事务范围治理。
解释 Nacos 服务注册、订阅与客户端选择过程,分析实例下线后的缓存、传播、旧连接和在途请求,提供优雅退出与分层排查方法。
从单位消息成本解释 Kafka 高吞吐,分析分区日志、批处理、页缓存、压缩与零拷贝,说明 TLS 条件、分区热点及吞吐、延迟和可靠性的取舍。
解释 RabbitMQ 交换机、绑定和队列职责,对比 Direct、Topic、Fanout 路由规则,说明多个队列与多个消费者的区别及未路由、发布确认的边界。
解释 FastAPI def、async def 路由与同步依赖的执行位置,指出 helper 不会自动进线程池,提供显式卸载示例并分析 Starlette 限制器、连接池与 CPU 工作。
通过订单替代构造入口解释 Python 实例方法、classmethod、staticmethod 的绑定规则,说明子类行为、模块函数选择和 TypeScript static 的实际差异。
解释 Python __new__ 与 __init__ 的职责、顺序和返回值条件,展示对象创建流程,说明不可变类型、返回旧实例及 TypeScript 无同一协议的差异。
解释 BlockingQueue 四类方法及等待策略,对比 ArrayBlockingQueue、LinkedBlockingQueue 的容量、锁与内存成本,分析队列积压、过载和任务持久化边界。
按 Java Thread.State 六种状态解释线程生命周期,重点区分 BLOCKED、WAITING 和 TIMED_WAITING,说明 RUNNABLE、sleep、wait 与死锁判断的常见误区。
解释 Spring @Async 的代理调用与自身调用失效,区分线程池排队、Future 和 void 异常处理,讲清事务、ThreadLocal 与重要任务持久化的边界。
沿着 MapperProxy、映射语句、参数处理、Executor、JDBC 和结果映射解释 MyBatis 原理,说明 namespace、方法重载及 MyBatis-Spring 会话管理边界。
解释 package.json 中 ^、~ 和零主版本范围,区分 SemVer 声明、锁文件与实际安装结果,说明 npm ci、间接依赖和升级兼容验证。
通过提交时间线解释 git reset 和 revert,比较 soft、mixed、hard 对文件的影响,说明已推送提交、共享历史、合并撤销和 reflog 的风险边界。
区分前端运行时错误、资源失败、Promise 拒绝和接口业务失败,提供浏览器监听示例,讲清版本与 Source Map、隐私过滤、去重和上报链路稳定性。
用登录功能区分前端单元、组件、集成与 E2E 测试,说明 mock 边界、测试覆盖职责、真实后端验证和不稳定测试的处理方法。
系统解释 Vue 模板编译到 render 的过程,区分 AST、静态提升、PatchFlag 和块结构,说明这些编译信息怎样帮助运行时更新,以及与响应式、key 的边界。
通过对象引用环和窗口监听器解释 JavaScript 垃圾回收,讲清可达性、标记清除、闭包与内存泄漏,提供堆快照和保留路径的排查思路。
用 TS 与 Python 实现固定参数数量的 curry,解释闭包、分支复用、默认参数、function.length、this 和占位符边界,并区分柯里化与偏函数应用。
解释 Fetch 和 Axios 在 404、500 时的默认错误语义,区分网络、HTTP、JSON 解析和业务失败,提供 TS Fetch 与 Python httpx 示例及取消、重试边界。
解释 Babel 的解析、AST 转换与代码生成,区分语法兼容、辅助函数和 Polyfill,说明 preset-env、core-js 配置及应用与库的不同兼容责任。
沿着模块转换与构建生命周期解释 Webpack Loader 和 Plugin 的区别,说明普通 Loader 顺序、pitch 边界及 Plugin 钩子,纠正常见执行顺序误解。
用字节区间解释 Range 续传,说明 206、Content-Range、416 和 If-Range,处理版本变化与完整响应误追加问题。
解释 HPA 指标目标比例、CPU request 基准与期望副本算法,区分指标缺失、策略限制和 Pod 无法调度。
通过 web 与 db 的容器网络解释 localhost、服务名和端口映射,说明监听地址、服务就绪与重建后连接恢复。
区分 Kafka 幂等生产者、事务和消费位点的保证范围,解释 read_committed,以及为什么 Kafka Exactly-once 不自动保证外部数据库只写一次。
说明 CSP script-src 如何限制脚本执行,比较逐响应 nonce 与按内容计算 hash,解释 Report-Only、第三方脚本和 XSS 防护边界。
区分 WebRTC 媒体与数据连接、WebSocket 通道和信令,解释 ICE 候选、STUN 地址发现与 TURN 中继,并说明直连和服务端转发的取舍。
解释代理链里的 X-Forwarded-For,说明可信代理、从右向左识别边界、源站绕过和伪造风险,以及真实 IP 与用户身份的区别。
解释 MySQL 外键如何保护引用关系,比较 CASCADE、RESTRICT 与 SET NULL,并说明软删除、权限规则和级联副作用的工程边界。
解释 MySQL JSON 标量字段怎样通过生成列或函数索引建立索引,说明类型、长度、排序规则、表达式匹配与数组多值索引的边界。
用长事务、等待 DDL 和后续查询的等待链解释 MySQL MDL,区分元数据锁与行锁,并给出安全排查对象和超时参数边界。
用有值时默认函数仍被执行的例子,解释 Optional orElse 与 orElseGet 的急切和惰性求值,说明 null、map、flatMap 和异常边界。
说明 Spring Boot 常见配置来源的覆盖关系,区分命令行、环境变量、配置文件和 Profile,并给出配置没有生效的排查方法。
比较 HashSet、LinkedHashSet 与 TreeSet 的去重依据、遍历顺序和复杂度,用比较器误删同价对象说明排序与唯一性需要一起设计。
解释 Stream 的惰性流水线与 parallelStream 的拆分、并行和合并,用共享写入与阻塞调用说明并行不一定更快的原因。
用菱形继承解释 Python C3 MRO 与 super 的查找位置,说明为什么 super 不一定调用直接父类,以及协作式初始化和 TypeScript 的边界。
比较 FastAPI BackgroundTasks 与 Celery 的执行位置、任务持久性、失败重试和资源隔离,解释响应已返回不等于任务可靠完成。
比较 asyncio.gather 与 TaskGroup 的异常传播、兄弟任务取消和清理行为,解释 return_exceptions 与 ExceptionGroup,并说明 Promise.all 的取消边界。
通过并发请求解释 AsyncLocalStorage 的 run、getStore 与异步上下文传递,提供 Node.js TypeScript 和 Python contextvars 示例,并说明共享对象与权限边界。
解释 React useOptimistic 的基础状态与临时乐观状态,用提交失败和并发修改说明界面恢复、真实结果提交与服务端副作用的区别。
用一条请求与卸载时间线区分 staleTime、gcTime,解释缓存命中后仍请求的原因,以及失效、轮询和查询 Key 的边界。
区分 Next.js updateTag、revalidateTag 与 router.refresh 的更新对象,说明即时失效、后台更新和客户端刷新,并给出缓存不更新的排查顺序。
区分 Next.js Server Actions 的界面数据修改入口与 Route Handlers 的显式 HTTP 接口,说明调用方式、外部消费者和服务端鉴权边界。
比较 Event Sourcing 与普通操作日志,解释按序演算、快照和事件版本兼容,说明重放为何不能再次发送邮件或执行外部动作。
解释 CQRS 的命令模型与查询模型,说明共享数据库、异步投影和读后写一致性取舍,并区分分库与事件溯源等独立选择。
通过松弛、负权反例与过期堆条目解释 Dijkstra,提供 TS 和 Python 教学实现,说明复杂度、不可达节点与路径恢复方法。
用入度与队列解释 Kahn 拓扑排序,提供 TS 和 Python 实现,分析自环、重复边和被阻塞节点,以及运行器何时可以启动后续任务。
比较 gzip 与 Brotli,解释 Accept-Encoding、Content-Encoding 和 Vary,区分静态预压缩、动态 CPU 开销和流式发送的取舍。
用时序解释 Nagle 与延迟 ACK 的触发条件,提供 TS、Python 的 TCP_NODELAY 设置片段,说明拆写、缓冲与抓包验证边界。
解释 Linux Load Average 计入的可运行和 D 状态任务,说明三条平均值与核数的读法,并给出 CPU、I/O 和容器配额的排查顺序。
比较 MySQL DECIMAL、FLOAT、DOUBLE,提供 TS 整数单位与 Python Decimal 示例,解释精度标度、舍入时机和驱动传输风险。
解释 Redis GEO 的空间候选筛选与距离检查,说明 GEOSEARCH COUNT ANY、坐标范围和业务状态过滤,以及地理距离与导航距离的区别。
对照 Redis 8.2 字典源码解释渐进式 rehash 的新旧表、插入查询和迁移粒度,说明它不是零成本或必然由后台线程执行。
解释 MySQL 备份和 binlog 的时间点恢复,说明事务停止边界、隔离回放与校验,避免直接覆盖生产或丢掉误删后的合法数据。
解释 MySQL ORDER BY 利用索引和 filesort 的条件,区分内存排序与磁盘文件,结合筛选、回表、LIMIT 与执行计划判断优化。
解释分布式 Cron 的任务身份、领取与租约接管,分析 fencing 和业务幂等,说明随机尝试 ID 与 Kubernetes CronJob 的保证边界。
解释 RabbitMQ DLX 与死信队列的关系,比较 requeue、有限重试和隔离,说明死信转发可靠性、受控重放与业务幂等要求。
解释 FastAPI Depends 的依赖图与请求内缓存,通过 yield 理解资源准备和清理,区分 function、request scope 与后台任务边界。
解释 API 路径版本与请求头版本的取舍,区分字段、单位和默认行为的兼容性,说明适配层、契约测试和旧版本下线流程。
解释 Webhook 原始请求体验签、已签名时间戳与事件去重,分析确认前崩溃和乱序事件,说明防重放不能只依靠签名或时间窗。
从 Cookie 域边界解释 SSO 与 OIDC 跳转、授权码兑换和会话建立,说明应用验证要求及单点退出为什么不自动成立。
比较 transition 与 animation 的触发方式和过程编排,解释属性变化、关键帧和结束事件,并说明性能与减少动态效果的注意点。
解释 height: 100% 的包含块与确定高度基准,比较内容撑开、绝对定位和 Flex 剩余空间,说明 min-height 与溢出排查边界。
比较 TypeScript enum、const enum 和 as const 的运行时代码,解释数字反向映射、内联与公共库版本风险,以及字面量类型的限制。
用调用方可传入的值解释 TypeScript 协变与逆变,提供 TS 与 Python 类型示例,说明 strictFunctionTypes 的方法例外和运行时边界。
解释 Monorepo 与 pnpm workspace 的本地依赖链接,区分依赖图、构建任务和发布策略,说明链接成功为什么不代表发布包可用。
解释 Source Map 的位置映射与发布配对,说明私有上传、构建标识和源码暴露风险,避免用同名但不同版本的映射定位错误。
解释 Vue scoped 的属性标记与选择器改写,区分子组件根节点、内部节点和 :deep(),结合 Teleport 排查真实 DOM 边界。
解释 useSyncExternalStore 的订阅、稳定快照与 SSR 初始数据,比较 useEffect 订阅方式,说明对象引用和请求隔离为什么重要。
解释优雅停机的接流、排空与资源释放流程,分析超时、消息确认和强制终止,说明停机流程不能代替业务幂等。
解释 ORM 的 N+1 查询如何产生,比较 JOIN、批量查询与 DataLoader,结合查询次数、结果膨胀和分页判断优化方案。
从首次渲染对照解释 React Hydration,排查 Next.js 水合不一致,说明浏览器专属数据、useEffect 与关闭 SSR 的取舍。
解释 JWT 无感刷新、并发 401 和晚到旧请求的处理方法,区分凭据失效与网络故障,并说明写请求重试的幂等边界。
SLI、SLO 和 SLA 有什么区别?错误预算怎么计算、怎么用?SLI 描述实际服务表现,SLO 指定目标,错误预算把允许的失败变成决策依据。讲清三者的关系。
并查集是什么?路径压缩和按秩合并为什么能提高效率?并查集保存分组代表元,压缩路径缩短查找,合并策略限制树高。讲清两个优化各自解决什么、又如何一起生效。
Linux Page Cache 是什么?write 成功后,为什么数据还可能丢失?write 把数据交给内核不等于持久化完成,fsync 和文件发布各有责任。讲清写入链路上每一步的保证。
服务器出现大量 CLOSE_WAIT 怎么排查?和 TIME_WAIT 堆积有什么区别?CLOSE_WAIT 要追踪谁收到关闭后仍持有 socket,不能套用 TIME_WAIT 的调参思路。给出可执行的排查路径。
MySQL 的 CTE 和子查询有什么区别?WITH RECURSIVE 怎么查询树形数据?CTE 为一次语句中的查询结果命名,递归查询还需要起点、递推和停止条件。讲清写法与常见陷阱。
SSRF 是什么?为什么后端不能直接请求用户传入的 URL?用户提供的地址不能自动获得服务器的网络权限,出站目标和最终连接都需要约束。讲清重定向与内网地址等绕过方式。
用户密码应该怎么存?为什么 MD5 加盐还不够?密码保存适合验证用的慢哈希结果,盐区分用户,成本参数增加离线猜测代价。讲清慢哈希、加盐与算法升级该如何配合。
Python 中什么对象可以作为字典的 key?tuple 一定可哈希吗?字典键需要稳定的哈希与相等关系,元组能否作为键还取决于成员。讲清可哈希的判断条件与常见反例。
JIT 和 AOT 编译有什么区别?Java 服务为什么需要预热?JIT 利用运行时反馈生成代码,AOT 提前生成代码,启动与稳态性能应分别评估。讲清预热成本的来源与观测方式。
HTML 的 srcset、sizes 和 picture 有什么区别?响应式图片怎么选?srcset 提供候选,sizes 提示显示宽度,picture 可以选择不同构图或格式。讲清三者的分工。
Object.defineProperty 是什么?writable、enumerable、configurable 分别控制什么?属性描述符分别控制值、遍历和重新定义,而默认规则随创建方式不同。讲清描述符的组合与陷阱。
ResizeObserver 和 MutationObserver 有什么区别?监听元素变化该用哪个?尺寸变化和 DOM 结构变化是不同事件,观察器需按真正关心的变化选择。讲清各自的适用场景。
AbortController 怎么取消请求?为什么旧请求的结果还可能覆盖新结果?取消旧请求能减少无用工作,界面还要判断返回结果是否属于最新一次输入。讲清竞态的处理方式。
Vue 3 的 shallowRef 和 markRaw 有什么区别?什么时候不需要深度响应式?浅层响应式只跟踪根值替换,markRaw 控制指定对象是否被代理。讲清性能取舍与副作用边界。
工厂模式和策略模式有什么区别?如何配合管理多种实现?工厂负责准备实现,策略负责替换行为,两者可以沿明确接口配合。讲清两种模式的职责划分与协作方式。
如何合并两个有序链表?递归和迭代的复杂度有什么区别?每轮连接两条链表当前较小的头节点,已连接的前缀始终有序。讲清两种写法的差异、空间开销与适用场景。
如何判断括号字符串是否合法?为什么要用栈?右括号必须匹配最近一个尚未关闭的左括号,扫描结束也不能留下未关闭项。讲清匹配规则与容易被忽略的边界情况。
MySQL 的 REPLACE 和 INSERT ON DUPLICATE KEY UPDATE 有什么区别?REPLACE 带有删除再插入语义,Upsert 的更新分支需要明确改哪些字段。讲清两者对自增 ID 与触发器的影响。
MySQL 分区表和分库分表有什么区别?分区后查询一定更快吗?分区裁剪减少要检查的分区,但单库分区不自动增加节点或消除索引需求。讲清两者的适用边界。
fork 和 exec 有什么区别?写时复制 COW 是怎么工作的?fork 创建子进程,exec 替换程序映像,私有内存通常在写入时才复制页面。讲清两个调用为何总是成对出现。
僵尸进程和孤儿进程有什么区别?为什么 kill 不掉僵尸进程?僵尸已经退出但尚未被回收,孤儿只是父进程先退出,两者不能混为一谈。讲清资源回收的责任在谁手上。
IntersectionObserver 是什么?如何实现图片懒加载和滚动加载?交叉观察在边界变化时通知,触发加载后仍要管理请求和观察器的生命周期。讲清实现要点与常见遗漏。
Flex 布局为什么会被长文本撑开?min-width: 0 为什么能解决?flex-shrink 允许收缩,但自动最小尺寸仍可能阻止元素缩到所需宽度。讲清最小尺寸的计算规则与修正方式。
Node.js 的 process.nextTick、Promise 和 setImmediate 按什么顺序执行?Node 的阶段调度和 nextTick 队列需要分开看,输出顺序还受执行环境影响。讲清如何逐步还原真实顺序。
Java interrupt 能直接终止线程吗?中断只是提出停止或取消的请求,执行线程需要按约定检测、退出并释放资源。讲清 Thread.stop 为什么被废弃、如何正确响应中断。
Java 序列化是什么?Serializable、transient 和 serialVersionUID 有什么作用?序列化保存可持久化的对象状态,兼容标识不等于对象一定兼容。讲清版本校验与反序列化风险。
Java 类什么时候初始化?静态变量、静态代码块和构造方法按什么顺序执行?类初始化处理静态状态,对象初始化处理实例状态,两者触发条件不同。以子类首次使用静态字段为例推演。
LongAdder 和 AtomicLong 有什么区别?LongAdder 分散计数竞争,但聚合读取不能充当一次原子的条件判断。讲清高并发计数为什么不一定选 AtomicLong。
Vue 3 自定义指令怎么写?什么时候用指令,什么时候用组件?指令复用元素级 DOM 行为,组件组织界面,Composable 组织有状态逻辑。讲清三者的分工与选择依据。
TypeScript 联合类型和交叉类型有什么区别?类型收窄怎么做?联合表示多种可能,交叉要求同时满足约束,访问具体字段前需要先收窄。讲清判别联合的写法与穷尽性检查。
QPS、TPS、RT 和并发数有什么区别?如何估算并验证系统容量?容量评估需要统一完成量、平均耗时和在途数量的统计边界,再用负载验证。讲清估算思路与验证方法。
如何判断链表有环并找到入环节点?快慢指针为什么有效?快慢指针先在环内相遇,再用距离关系找到入环节点。讲清相遇点的推导过程,以及排查时真正怎么用。
Java 单例模式怎么实现?双重检查锁为什么需要 volatile?单例要同时说清实例创建、发布与唯一范围,实例唯一也不代表成员操作线程安全。讲清指令重排带来的风险。
Redis 内存碎片是什么?为什么删除数据后,内存占用没有明显下降?删除数据释放的是分配,不保证分配器立即把内存归还操作系统。讲清碎片成因与可用的处理手段。
React Suspense 是什么?为什么包住组件以后,接口请求仍然没有显示 loading?Suspense 只响应能让渲染挂起的加载来源,普通 Effect 请求需自行管理状态。讲清两种加载路径的区别。
Object.freeze、Object.seal 和 Object.preventExtensions 有什么区别?能冻结嵌套对象吗?冻结控制的是当前对象的属性,不会自动冻结它引用的所有对象。讲清作用范围与深冻结的代价。
CountDownLatch、CyclicBarrier 和 Semaphore 有什么区别?三者分别对应等任务结束、分轮会合与限制同时进入的人数。讲清三种协作目标的选型依据与常见误用。
Spring 的 @Autowired 和 @Resource 有什么区别?多个 Bean 时怎么选?注入要从候选 Bean 中选出依赖,类型、名称和限定符各有匹配规则。讲清优先级与歧义处理。
TypeScript 的 Partial、Required、Pick、Omit 有什么区别?怎么选择工具类型?工具类型改变的是编译时的字段约束,实际输入仍要在运行时检查。讲清几种工具类型的组合方式。
Java 字符串常量池是什么?String.intern()、字面量和 new String 有什么区别?字符串池复用相同内容的规范对象,但比较内容仍要用 equals。讲清各自的对象数量与判断边界。
RPO 和 RTO 是什么?备份、主从复制和容灾有什么区别?允许丢多少数据与允许停多久是两个目标,备份文件存在也不代表能按目标恢复。讲清各层手段的能力边界。
日志、指标和链路追踪有什么区别?Trace ID 怎样串起跨服务请求?指标指出变化,Trace 连接一次请求的各段,日志解释具体事件。讲清三者如何配合定位问题。
动态规划是什么?爬楼梯直接递归为什么会慢,滚动数组怎么优化空间?先定义状态代表什么,再找最后一步从哪里来,缓存重复子问题。讲清状态定义与空间压缩的思路。
最长无重复子串怎么用滑动窗口实现?为什么左边界只能向前移动?重复字符只影响当前窗口,已经离开窗口的位置不能把左边界拉回去。讲清窗口收缩的判断依据。
两数之和怎么用哈希表实现?为什么要先查再存?每轮只在已经经过的元素里找补数,找到的自然就是另一个位置,也不会重复使用同一个元素。讲清查与存的顺序为何不能颠倒。
二叉树前序、中序、后序遍历有什么区别?递归和迭代怎样实现?前中后说的是根节点被处理的时机,遍历顺序与显式栈要一一对应。讲清两种写法的对应关系与常见错误。
如何用两个栈实现队列?为什么出队可以做到均摊 O(1)?输出栈为空时再搬运,就能保留已经形成的先入先出顺序。讲清搬运时机的选择与均摊复杂度的推导过程。
死锁产生的四个必要条件是什么?预防、避免和检测有什么区别?等待很久不一定就是死锁,关键是资源等待是否形成无法解除的闭环。讲清四个条件如何同时成立、又从哪里打破。
TCP 半连接队列和全连接队列有什么区别?backlog 满了会发生什么?握手未完成和已完成待 accept 是两种排队位置,需要分别排查。讲清丢弃、重传与队列溢出的表现差异。
HTTP Keep-Alive 和 TCP Keepalive 有什么区别?长连接能保证对方一直在线吗?连接复用、空闲探测和业务健康是三个不同目的。讲清三者各自解决什么、又解决不了什么。
Redis 的 listpack 和 ziplist 有什么区别?为什么 listpack 能避免连锁更新?紧凑编码减少指针开销,单项反向长度则避免前项变化一路牵连。讲清两种编码的元数据差异。
Redis 为什么使用 SDS 而不是 C 字符串?二进制安全和预分配是什么?显式保存长度与可用空间,才能既保存零字节,也安全管理扩容。讲清 C 字符串会踩到哪些坑。
Redis 的 SCAN 和 KEYS 有什么区别?COUNT 是每次固定返回的数量吗?游标让全量遍历分批进行,但不提供快照或精确分页。讲清为什么不能用 KEYS,以及 SCAN 的重复返回。
MySQL 的 utf8mb4 和 utf8 有什么区别?Collation 为什么会影响比较和唯一索引?字符集决定如何编码,排序规则决定如何比较,而比较规则也影响唯一性。讲清两者的分工。
MySQL Online DDL 是什么?ALGORITHM=INSTANT、INPLACE 和 COPY 有什么区别?在线能力取决于具体操作和版本,不代表完全无锁、无重建。讲清三种算法的代价与适用条件。
MySQL 自增 ID 为什么不连续?事务回滚和并发插入会影响 AUTO_INCREMENT 吗?编号分配和事务提交不是同一个过程,已分配号码不承诺回收。讲清空洞的几种来源。
MySQL 普通索引和唯一索引有什么区别?Change Buffer 为什么不能随便用于唯一索引?是否允许重复由业务决定,写入优化不能省掉唯一性检查。讲清写入路径与校验的取舍。
MySQL 回表、覆盖索引和索引下推有什么区别?覆盖减少取整行的需求,下推减少不必要的取整行次数。讲清三者各自作用的环节,以及分别减少了哪一部分开销。
Python 的 with 是怎么工作的?发生异常后为什么还能关闭文件?with 规定进入与退出行为,退出阶段既能清理资源,也可能有意吞掉异常。讲清上下文管理器的责任边界。
Python 的 is 和 == 有什么区别?is 判断同一个对象,== 判断类型定义的相等关系。讲清为什么判断 None 用 is、比较字符串却不用,以及小整数缓存这类常见误区。
Spring 单例 Bean 是线程安全的吗?单例只控制实例数量,不保护实例里的可变状态。讲清为什么不能把用户信息放进成员变量,以及无状态与并发安全的边界。
Spring 的 Filter、Interceptor 和 AOP 有什么区别?鉴权和日志该放在哪一层?先选拦截位置,再判断这一层能看到什么。沿一次请求穿过容器、路由与业务方法的路径逐层对照。
Java 的 fail-fast 和 fail-safe 是什么?迭代器检测结构变化只是尽力报错,不是并发安全保证。讲清单线程也会抛异常的原因,以及什么才算结构修改。
Java 虚拟线程是什么?它减少等待任务占用平台线程的代价,但不增加 CPU 或下游容量。讲清与 carrier 的配合、不池化为何仍要限流,以及 pinning 的版本差异。
Java 泛型为什么要类型擦除?运行时对象一般并不携带具体泛型实参。讲清擦除后还剩什么、错误元素为什么可能到读取时才报错,以及一些写法受限的由来。
Java 的 final 有什么作用?final 修饰引用不等于对象不可变,被限制的只是引用不能重新赋值。讲清内部状态暴露、只读视图与快照的区别,以及初始化保证的边界。
Java 内存模型 JMM 是什么?happens-before 不等于代码先执行,跨线程正确性需要可见性与顺序保证。讲清四个动作与锁的作用,以及日志和 sleep 为什么不能当证明。
Webpack 的 HMR 热更新是什么?为什么有时保留状态,有时整页刷新?模块更新需要有接受边界,保留页面也不代表旧副作用自动消失。讲清接受边界与清理责任。
CSS 伪类和伪元素有什么区别?::before 能代替真正的 HTML 内容吗?状态选择和局部生成不是一回事,重要内容仍需要真实语义。讲清选择器写法差异与可访问性边界。
CSS 媒体查询和容器查询有什么区别?响应式组件为什么不能只看屏幕宽度?页面看视口,组件看自己获得的空间。讲清 container-type 的作用与断点选择中容易犯的错。
Vue Teleport 是什么?弹窗移动到 body 后,组件关系和事件会改变吗?DOM 放置位置改变,Vue 的逻辑父子关系不随之改写。讲清它真正解决的层叠与裁剪问题。
Vue 3 的 Composable 是什么?和普通函数、Mixin 有什么区别?复用有状态的逻辑时,要把状态创建、输入和清理都说清楚。讲清它如何避免 Mixin 的命名冲突与来源不清。
React 的 useReducer 是什么?和 useState 有什么区别,异步请求应该写在哪里?把同一功能的状态转换集中起来,但不把副作用塞进 reducer。讲清状态划分与副作用的位置。
React 的 useTransition 和 useDeferredValue 有什么区别?它们等于防抖吗?输入立即响应,昂贵界面可以稍后更新,但计算并不会自动变少。讲清两者与防抖的本质差异。
React 的 useLayoutEffect 和 useEffect 有什么区别?什么时候需要在绘制前测量 DOM?只有必须在显示前测量并纠正布局,才值得阻挡绘制。讲清两者在绘制时机上的差别。
TypeScript 的 satisfies、as 和类型注解有什么区别?能校验接口返回的数据吗?编译时检查配置是否合规,不等于运行时验证外部数据。讲清三种写法的取舍与边界。
TypeScript 结构化类型是什么?为什么对象多一个字段有时能赋值、有时却报错?类型兼容按结构比较,而新鲜对象字面量还会接受额外属性检查。讲清两者为何给出不同结论。
JavaScript 数组去重有哪些方法?为什么 Set 去不掉内容相同的对象?先定义什么叫重复,再决定用值、引用还是业务键去重。讲清各种方法的适用条件与代价。
requestAnimationFrame 和 setTimeout 有什么区别?为什么动画不应该固定每帧移动几像素?动画进度按时间算,更新机会跟着浏览器绘制走。讲清按帧计数为何会让速度不一致。
script 的 defer 和 async 有什么区别?会影响执行顺序和 DOMContentLoaded 吗?下载可以并行,执行时机与依赖顺序仍要分别安排。讲清两种属性下执行与事件触发的差异。
Python 函数默认参数在执行函数定义时求值。默认值是空列表时,这个列表对象会被保存下来;多次省略这个参数,就会使用同一个默认对象。如果函数对它执行 append 等修改,后一次调用就可能看到前一次留下的数据。
Error Boundary 是包住部分 React 子组件树的特殊组件。当子组件在渲染等受支持的阶段抛错时,它可以显示 fallback,避免这个区域的故障直接破坏整个页面。
进程调度从就绪任务中选择下一位使用 CPU 的任务。先来先服务按到达顺序,短任务优先更关注完成时间,优先级调度按优先级,时间片轮转则让就绪任务轮流运行一段时间。
Redis Pub/Sub 面向实时广播。发布时把消息推给当前订阅者,不为离线订阅者保留一份以后补读的历史,交付语义是 at-most-once。Stream 则先把消息保存为带 ID 的条目,可以按进度读取。
反转单链表,是改变节点之间的 next 关系,返回新的头节点,不是只把节点里的值倒过来。迭代写法通常维护 prev 和 curr。
OSI 七层是理解通信职责的参考模型;TCP/IP 四层则更贴近互联网协议体系的组织方式。两者不是两套需要同时逐层运行的机器。常见对应是:OSI 的应用、表示、会话合到 TCP/IP 应用层;传输层对应传输层;网络层对应网际层;
React 合成事件是 React 提供给事件处理函数的事件对象,封装了常用属性与行为,让组件通过 onClick 等声明式接口处理交互,也可以通过 nativeEvent 访问底层原生事件。
G1 和 ZGC 都是面向服务应用的垃圾收集器,但回收工作的安排不同。G1 把堆划分成多个区域,结合并发标记、停顿中的疏散等工作,兼顾吞吐与可控停顿;ZGC 把更多标记和重定位工作与应用并发进行,更重视低暂停。
MySQL 的 DATETIME 主要保存日期时间字段值,不自动根据会话时区转换;TIMESTAMP 则按会话时区解释写入值,转换为 UTC 保存,读取时再转到当前会话时区。
Vue 插槽让子组件保留一个内容出口,父组件提供要显示的模板。默认插槽是没有单独名称的内容出口,具名插槽则通过名字区分标题、正文、操作区等位置。作用域插槽解决的是数据问题,不是另一种布局位置。
Java 是值传递。调用方法时,实参的值被复制给形参;基本类型复制数值等值,对象参数复制的是引用值。如果外部变量 user 和方法参数 p 的引用值相同,它们就指向同一个对象。
IN 判断一个值是否出现在给定集合或子查询结果中;EXISTS 判断子查询有没有符合条件的行,通常可以通过相关条件描述“是否存在关联记录”。两者不能直接套“谁一定更快”的口诀。
px 是 CSS 像素,不必等于一个设备物理像素。em 与字号有关:用于 font-size 时,按继承的字号计算;用于 padding 等属性时,通常按元素自身字号计算。rem 则按根元素字号计算。
Java 接口主要描述一组能力或约定,一个类可以实现多个接口。现代接口不只有抽象方法,还可以有 default、静态方法,以及符合规则的私有辅助方法,但没有每个实现对象独立保存的接口实例字段,也没有实例构造器。
Future 表示一个稍后可获得的计算结果,可以查询状态、尝试取消,也可以通过 get 等待结果。它本身也能对应异步任务,不是只能同步执行。
map 用于把每个元素转换成结果,再收集成一个新数组。forEach 主要用于逐项执行操作,返回值是 undefined,不收集回调的结果。两者都会调用回调,但都不会自动等待 async 回调完成。
排查 OOM,我会先保存完整错误信息和发生时间,区分 Java 堆、元空间、直接内存、线程等不同问题,同时查看进程和容器的资源限制。
MyBatis 的一级缓存通常作用在一个 SqlSession 内。同一会话里重复执行相同查询,可能直接使用本地结果,不再查询数据库。更新、提交、回滚、关闭会话等操作会清理本地缓存,也可以把范围设成单次语句执行。
Vue 3 处理带 key 的子节点时,会先比较两端可以直接匹配的部分,再处理中间发生变化的节点。处理中间部分时,它通过 key 查找对应节点,更新可以复用的节点,删除不存在的旧节点,并识别需要新建的节点。
AQS 是 Java 用来构建锁、信号量等同步器的基础框架。它主要管理一个整型状态和等待队列,让获取失败的线程能够等待,并在资源释放后重新尝试。但是,状态代表什么、怎样才算获取成功,需要具体同步器来定义。
startupProbe 给应用启动阶段一个独立检查。配置它以后,在启动探针成功前,存活和就绪探针不会开始执行;启动检查持续失败达到阈值时,会终止相应容器,再按重启策略处理。readinessProbe 判断当前是否适合接流量。
常见的 Dedicated Web Worker 由页面创建,在独立执行环境里处理计算,通过 postMessage 等方式与页面通信,不能直接操作页面 DOM。它适合把较重计算移出主线程,保持页面响应。
在常见的消费者组订阅模式下,Kafka 把分区分配给组内成员,同一分区正常由一个成员负责。消费者可以负责多个分区,成员超过可分配分区数量时,部分成员可能空闲。
UNION 把多个查询结果纵向合并,并对合并后的重复行去重;UNION ALL 则保留所有行,包括来源之间和单个来源里的重复。去重比较的是输出行,不是自动按某个用户 ID 合并。
for...in 枚举对象的可枚举字符串属性名,既可能有自有属性,也可能包含继承属性;它不会直接给出属性值,也不会枚举 Symbol 键。for...of 则使用迭代协议,从可迭代对象里依次取值。
Redis Bitmap 是 String 上的一组按位操作,不是独立的底层数据类型。可以用每个 bit 的 0、1 表示某个状态,SETBIT 修改,GETBIT 查询,BITCOUNT 统计设为 1 的位数。
用户态和内核态主要区分 CPU 执行权限。应用通常在用户态运行,不能随意执行特权操作或访问受保护资源;内核在更高权限下管理内存、设备和任务等。应用通过系统调用请求内核服务时,会经受控入口进入内核,完成操作后可以返回原来的用户态执行。
虚拟机通常通过虚拟化层提供虚拟硬件,每台虚拟机运行自己的来宾操作系统和内核。普通 Linux 容器则是一组被隔离的进程,多个容器共享它们所在 Linux 环境的内核。
display: none 让元素及其子树不生成相应布局盒,通常不占页面位置,也不能作为普通可见控件接收焦点或点击。visibility: hidden 保留布局位置,但不绘制元素,它本身不能接收焦点;
Java 服务 CPU 飙高怎么排查?先确认影响范围,再用 top -H 找忙线程、转成十六进制对照线程栈。讲清 GC 与业务热点的区分方法与常见误判。
CSS 为同一元素的同一属性选值时,先按层叠规则处理来源、重要性、层叠层等因素;到了相应竞争范围,才比较选择器优先级。普通选择器可以按 ID、类这一组、类型这一组组成三列,按从左到右比较。类这一组包括类、属性选择器和伪类;
Java 反射让代码在运行时,通过 Class 等对象检查类型与成员,并使用 Constructor、Method、Field 等 API 创建实例、调用方法或访问字段。普通调用在编译时就写明类型和方法;
InnoDB 和 MyISAM 都是 MySQL 的存储引擎,负责表数据与索引的具体组织和访问。当前 MySQL 的默认引擎是 InnoDB。
useState 保存参与渲染的状态。通过 setter 请求更新后,React 会根据更新规则安排渲染,组件再用新的状态生成界面。useRef 返回一个在多次渲染之间保持身份的对象。
窗口函数会在相关的一组行上计算,但不会像普通 GROUP BY 聚合那样,把这些明细压成一行。OVER 里可以通过 PARTITION BY 划分计算范围,通过 ORDER BY 指定范围内的顺序。
Object 更适合表达一个有字段的记录,例如用户资料;它的属性键主要是字符串和 Symbol。Map 更适合动态的键值集合,键可以是任意值,提供 size 和明确的遍历接口。如果 Map 的键是对象,比较的是对象身份,不是字段内容。
JavaScript 的 Number 使用二进制浮点数表示数字。像 0.1、0.2 这样的十进制小数,转成二进制以后不能有限地写完,只能保存接近的值。相加以后再舍入,结果就可能和保存下来的 0.3 不完全相同。处理时要看用途。
Java 中可以抛出的异常对象都属于 Throwable 体系,主要分为 Exception 和 Error。Exception 又包含 RuntimeException 及其子类,以及其他常见的受检异常。
Thread.sleep 让当前线程暂停指定时间,适合暂缓执行。线程不会因为 sleep 释放已经持有的监视器锁,所以在同步块里睡觉,其他需要这把锁的线程仍然进不来。Object.wait 则用来等待某个条件。
Vue 的生命周期,就是一个组件从创建、挂载、更新到卸载的过程。生命周期钩子让咱们在这些阶段安排工作,例如挂载后访问 DOM,卸载时清理计时器和事件订阅。
Raft 是管理复制日志的共识算法,把 Leader 选举、日志复制和安全约束分别组织起来,让节点按一致的已提交命令推进状态机。节点主要有 Follower、Candidate、Leader 三种角色,用 term 区分任期。
硬链接是为同一文件增加目录项名字,几个名字对应同一份文件与 inode,不是复制一份内容,也没有哪个名字天然是“主名字”。软链接本身是独立链接对象,保存目标路径;访问时再沿路径寻找目标。
HyperLogLog 是近似基数统计结构,适合估算有多少不同元素。例如把统一身份口径的访客标识加入同一天的结构,再取得近似 UV。
TCP 用字节序号和确认维护可靠传输。发送后没有在重传计时器规定的时间内得到相应确认,可以触发超时重传;超时可能来自数据丢失,也可能是确认丢失或延迟。经典快速重传利用重复 ACK 作为缺口线索。
HTTP 状态码描述本次请求的处理结果与响应语义。1xx 是信息响应,2xx 表示成功处理,3xx 涉及重定向等后续处理,4xx、5xx 分别属于客户端错误和服务端错误类别,但这些分类不是对真实故障责任人的直接判决。
数据库连接池维护一组可复用连接。请求需要访问数据库时取得连接,完成后归还池中,后续请求继续使用,减少反复建连的成本。池也限制同时占用的连接数量。达到上限时,后来的获取请求可能排队或超时。归还通常不等于关闭底层连接,而是让它重新可借用。
Spring MVC 中,DispatcherServlet 是前端控制器,负责协调请求分派,不把所有具体处理都自己完成。HandlerMapping 根据路径、方法等条件找到处理器以及相关拦截器;
受控输入通过 value 或 checked,由 React 提供当前值。用户输入产生事件,代码更新状态,再把新值传回输入框。因此,状态是显示值的主要来源。
then 每次返回一个新的 Promise。这个新 Promise 的结果,主要由回调的执行结果决定,不是原来的 Promise 被反复修改。回调返回普通值,后面得到这个值;
标记清除、复制和标记整理,是理解垃圾回收如何处理空间的几种基础办法,不是三个必须二选一的收集器品牌。标记清除先识别存活对象,再回收未存活对象占用的空间,通常不移动存活对象,但可能留下外部碎片。
ArrayList 主要用可扩容的数组保存元素引用,可以按下标直接访问。尾部追加的均摊成本较低,但中间插入、删除通常需要移动后续引用;容量不足时还要扩容。LinkedList 是双向链表,节点保存元素以及前后节点的联系。
悲观方案通常在事务中先锁住相关记录,再基于受保护的数据判断和更新,其他冲突操作需要等待或按配置失败。乐观方案先读取,写入时再验证数据是否仍符合旧前提。
WHERE 主要筛选参与后续查询的明细行,GROUP BY 把这些明细按指定键分组,聚合函数再计算每组的合计、数量等结果,HAVING 筛选分组后的结果。
在 MySQL 中,DELETE 删除行,可以带 WHERE;不带条件则可能删除全部行,但表定义仍然保留。TRUNCATE 清空整张表,不提供逐行筛选条件,保留可重新使用的表结构,并会重置自增计数等状态。
Spring 循环依赖是 Bean 创建过程中的依赖形成了环,例如 A 需要 B,B 又需要 A。对于允许循环引用的某些 singleton 属性注入场景,可以先创建 A 的实例,再注册取得 A 提前引用的工厂;
CAS 是比较并交换:在一次原子操作中,比较当前位置与预期值;相同才更新,否则失败。它可以帮助实现单变量的条件更新,但普通读取、if 判断和赋值并不等于 CAS。常见做法是读取旧值、计算新值、尝试 CAS;失败后重新读取再计算。
String 的字符内容创建后不再改变,适合表示已经确定的文本。变量可以指向新的 String,但原来那个字符串的内容没有因此被改写。
equals 定义两个对象在当前类型中算不算相等,hashCode 为哈希容器提供用于定位的整数结果。两者的契约是:equals 相等的对象必须返回相同 hashCode;
v-if 是条件渲染,条件不成立时不创建对应分支;已经创建后再变为 false,会卸载这段分支,之后重新满足条件时再创建。v-show 则先渲染元素,主要通过切换 CSS 的 display 控制显示。
var、let、const 的区别,主要看作用域、初始化时机和能不能重新赋值。var 通常以函数为作用域,普通 if、for 代码块不会单独限制它。进入相应作用域时,var 绑定已经初始化为 undefined;
服务熔断和降级解决的是两个不同的问题。熔断根据依赖调用的失败或慢调用情况,暂时阻止继续访问这个依赖,减少无效等待和故障扩散。降级则是在原能力不可用时,提供明确的替代结果,例如备用数据、缓存内容,或者直接说明暂时不可用。
merge 把两条历史合到一起。分支已经分叉时,通常建立一个连接两边历史的合并提交;如果可以快进,也可能只是移动指针,不产生新的合并提交。rebase 则把待迁移提交的改动,在新的基点上重新应用。
CSS 常见定位值包括 static、relative、absolute、fixed 和 sticky。static 参与普通布局,定位偏移不按定位方式生效。relative 保留原本的布局位置,再相对正常位置偏移。
SQL 注入为什么能生效?参数化查询把输入挡在语法结构之外,那动态排序字段为什么仍有风险?讲清预编译的边界与白名单兜底方式。
数据库范式帮助我们按字段之间的依赖关系组织表,减少重复保存同一事实带来的更新、插入和删除异常。第一范式要求按所定义的值域,每个位置保存一个值,避免同一类数据无限扩展成重复字段。第二范式在此基础上,要求非主属性不能只依赖某个候选键的一部分。
TCP 提供有序的字节流,不保证一次发送对应一次接收。接收方可能一次收到多个消息的字节,也可能分几次才收到一条消息。解决办法是在应用层定义消息边界,例如固定长度、分隔符或者长度字段。
=== 是严格相等,不先转换两个操作数的类型。类型不同通常就不相等;对象则比较是否为同一个对象,不逐个比较字段。== 是宽松相等。类型不同时,会按语言规定处理,例如字符串和数字比较时可能转换字符串,布尔值会转成数字。
ThreadLocal 让不同线程分别保存和读取自己的变量值。同一个 ThreadLocal 对象,在不同线程中可以对应不同的值,不是让所有线程共享一个普通字段。线程池会复用线程,因此任务结束不等于线程结束。
标准布隆过滤器用一个位数组和多个哈希函数,判断一个元素是否可能已经加入集合。加入元素时,把它映射到的多个位置设成一。查询时,只要有一个位置是零,就可以判定它没有加入;如果全部为一,只能说可能存在,因为这些位置也可能分别被其他元素设成一。
双亲委派通常指 ClassLoader 默认加载流程中的父委托模型。加载类时,先检查自己是否已经加载过;没有的话,先委托父加载器,父加载器找不到,再尝试自己查找和定义。这样可以让基础类尽量由一致的上层来源提供,也减少不必要的重复加载。
useState、useEffect 等常规 Hook,需要在组件或自定义 Hook 的顶层调用,并且放在条件提前返回之前,不能在条件、循环或普通嵌套函数里调用。
volatile 是 Java 内存模型中的同步机制。对一个 volatile 字段的写,与后续对同一字段的读建立相应的 happens-before 关系,因此可以用于状态标记和满足条件的安全发布。但它没有提供互斥。
Java 的对象存活判断,主要需要理解从 GC Roots 出发的可达性分析,不是只数一个对象被引用了几次。GC Roots 是分析的起点,例如活动线程中的相关引用和 JVM 内部引用。沿引用关系能够到达的对象,仍可能被程序使用;
synchronized 和 ReentrantLock 都可以实现可重入的互斥访问,并提供相应的内存可见性保证。一个线程已经持有这把锁,还能再次进入受同一把锁保护的代码。
typeof 适合先判断字符串、数字、布尔值等基本类别,但它不能细分普通对象、数组和日期,null 的结果也是 object,函数则返回 function。instanceof 通常沿原型链检查一个对象是否与指定构造器关联。
Spring Bean 的常见生命周期可以理解为:根据定义创建实例,完成必要的依赖设置和容器回调,执行初始化,再把可用的 Bean 提供给调用者;容器关闭时,对受管理的 Bean 执行相应销毁回调。实例化是把对象创建出来。
JVM 规范把运行时内存分成程序计数器、虚拟机栈、堆、方法区和本地方法栈等逻辑区域,运行时常量池属于方法区的一部分。程序计数器和虚拟机栈是线程私有的。每次方法调用都会对应一个栈帧,保存局部变量、操作数栈等执行信息。
nextTick 是 Vue 提供的一个等待 DOM 更新完成的 API。修改响应式数据时,数据本身已经变化了,但 Vue 不会因此立刻把每一次修改都更新到页面上。它会把组件更新排进队列,在一个批次里处理,避免连续修改导致重复更新。
Redis 常见的基础类型包括 String、Hash、List、Set 和 ZSet,但 Redis 的类型并不只有这五种。String 适合保存一个完整值,例如缓存 JSON,或者配合自增命令做计数。
事务隔离级别规定的是,多个事务同时读写时,一个事务可以看到其他事务的哪些变化。读未提交可能读到别人还没提交的数据;读已提交只读取已提交的数据,但同一事务里,两次查询可能看到不同结果。可重复读进一步保证重复读取的稳定性;
DDD 是领域驱动设计,把复杂业务中的概念、规则和模型作为设计中心,通过开发者与领域专家共同建立统一语言。战略层面用子域、限界上下文等划清模型适用边界。同一个词在不同上下文可能不同,不必强迫全公司共用一个巨大实体。
单体通常作为一个部署单元,内部仍可做清晰模块化;微服务把能力拆成可独立部署的服务,强调明确职责和数据所有权。微服务适合确有独立扩缩、发布节奏和团队边界需求的系统,但增加网络失败、接口版本、跨服务一致性、可观测性和运维成本。
先确认需求:短码长度、自定义码、过期、目标能否修改、读写规模和安全要求。核心数据是短码到目标地址及状态的映射,存储用唯一约束防止并发冲突。可以采用随机码加碰撞重试,或唯一 ID 编码。Base62 是表示方式,不是加密;
CDN 通过边缘节点分发内容,缓存命中时减少回源访问与传输距离,但不保证所有用户物理最近或所有请求都缓存。缓存键决定哪些请求共用表示,可能涉及路径、查询参数、请求头和 Cookie 等策略。
固定窗口按时间段计数,简单但边界附近可能集中放行;滑动窗口观察最近一段时间,可以采用日志或分段计数,精度和成本不同。令牌桶以设定速率补充令牌,容量限制可积累的突发额度;
分库分表可以按职责垂直拆分,也可以按分片键把同结构数据水平分到多个表或库。它用于处理单节点容量与负载约束,不是数据库变大就自动必须做。水平分片先看访问模式。能带分片键的查询可以定向路由,不带就可能散射到多片再汇总;
直接 hash(key) mod N 分配节点,N 改变时很多键会重新映射。一致性哈希把键和节点映射到同一空间,常见环模型中由顺时针后继节点负责键,增减节点主要改变局部归属。
常见方案有数据库序列或号段、Snowflake 类时间 ID、UUID 等。它们在协调成本、排序特性、长度和故障依赖上不同。
跨服务各自使用本地事务,无法直接靠一个普通数据库事务覆盖全部资源。2PC 让支持协议的参与者准备后统一决定提交或回滚,但有协调、等待和恢复成本。
CAP 在其模型下说明:发生网络分区时,不能同时保证线性一致性和对所有非故障节点请求的可用性。这里的 C 不是泛指数据不出错,A 也不是服务每月可用率。不能把它理解为平时随意从三个按钮选两个。
BFS 按距离起点的层次扩展,常用队列;DFS 沿分支深入再回退,用递归栈或显式栈。邻接表下完整遍历常见复杂度都是 O(V+E)。在无权图或各边等权的情况下,BFS 可以找最少边数的路径;
快速排序先分区,让元素位于基准两侧,再递归处理。常见数组快排平均或期望 O(n log n),不良分区可能 O(n²);常见原地版本不稳定,递归栈也占空间。归并排序先拆分,再把有序子序列合并。
二分适用于有序数组,或者能形成单调真假分界的条件。查一个相等元素和查第一个大于等于目标的位置,是不同任务。我会先定义 lower_bound:返回首个不小于目标的位置,没有则返回 n。
先确认 Top K 的定义:最大 K 个值、不同值,还是出现频率最高的 K 个,三者不是一道题。这里讨论允许重复的最大 K 个值。排序简单,成本 O(n log n)。
LRU 淘汰最近最少使用的条目。命中读取和写入都要更新最近使用位置,容量超限时删除最久未使用的条目。经典结构是哈希表加双向链表:表定位节点,链表移动节点和删除尾部,在常见哈希假设下实现平均 O(1) 的 get、put。
零拷贝通常指减少某条 I/O 路径上的数据复制,尤其避免数据为了转发而在内核和用户缓冲之间来回搬运,不代表完全没有设备传输和任何复制。普通 read 再 write 的文件转发,会经过用户缓冲。
互斥锁主要提供独占临界区,并通常有持有者语义。自旋锁获取失败时反复检查,消耗 CPU,适合很短、能很快结束的临界区,不适合在持锁期间做耗时或阻塞操作。信号量管理可用许可计数。计数为零时等待,释放后允许继续;
IPC 是进程间交换数据或通知的机制。管道适合连接生产者和消费者;消息队列强调消息组织;共享内存让进程访问同一片数据;Socket 适合连接式通信,Unix 域 Socket 用于本机,网络 Socket 可以跨机器。
select、poll 和 epoll 都能等待多个文件描述符的 I/O 状态。select 使用集合,常见 glibc fd_set 有大小限制;poll 使用描述符数组,没有同样的固定集合限制,但仍要处理扫描和传入的集合。
程序通常使用虚拟地址,硬件结合页表把它翻译到物理页。这样可以隔离进程、控制访问,也能让不连续物理页组成连续的虚拟地址范围。页表保存映射,TLB 缓存地址翻译。
301 表示永久迁移,302 表示临时转向。出于历史兼容,它们允许客户端把原来的 POST 改为 GET,不能依赖它们保留 POST 请求体。307 是临时重定向,308 是永久重定向;
GET 的语义是获取目标资源的表示,POST 是让目标资源按自己的规则处理提交的内容。参数放在哪里,不是二者的定义。GET 属于安全、幂等的方法。这里安全指客户端没有请求改变资源状态,不是密码传输安全;
DNS 的作用是查询域名对应的记录,不只查询 IP。应用通常先经过本机解析机制,再向配置的递归解析器请求结果。递归查询是把查到答案的责任交给对方;迭代查询是对方给出答案或下一步该问的服务器,查询方继续查。
TCP 流量控制主要根据接收方通告的窗口 rwnd,避免发送过量让接收缓冲承受不了。拥塞控制由发送方维护 cwnd,根据网络反馈调整发送规模,避免持续把网络压满。发送时,未确认数据量要受两者的较小限制约束。
TCP 提供面向连接、可靠有序的字节流。应用要自己定义消息边界,不能假设一次 write 就对应对方一次 read。UDP 发送数据报,保留数据报边界,但不提供 TCP 那样的顺序、重传与连接级可靠交付保证。
HTTP/1.1 支持连接复用,但同连接的流水线响应仍受顺序限制,实践中常用多连接并发。HTTP/2 使用二进制帧和流,让多个请求在一个连接上交错传输,并通过 HPACK 压缩头字段。
Redis Pipeline 是客户端连续发送多条命令,不在每条后都停下来等待回复,再按顺序处理结果。它主要减少往返等待,并提高批量 IO 效率。服务器仍要执行这些命令,Pipeline 不把十条操作变成一条,也不保证整批原子执行。
Redis 的 MULTI 把命令入队,EXEC 时按顺序集中执行,其间不会插入其他客户端的普通命令。但执行期某条命令报错,不会自动回滚此前成功的修改,其他排队命令仍可能继续执行。
Redis Cluster 把键空间划成 16384 个哈希槽,键通常按 CRC16(key) 对 16384 取模得到槽号,再由槽的归属找到主节点。节点增减通过迁移槽调整数据分布,不是简单改成 hash(key) % 节点数。
Sentinel 为 Redis 主从架构提供监控、通知、自动故障切换和主库发现。它不负责给数据分片,也不在每次业务请求中代转命令。单个 Sentinel 认为主库不可达,是主观下线;达到配置的 quorum 等条件后,才能判断客观下线。
Redis 复制通常先让从库获得基准数据,再持续接收主库的变更流。全量同步会传输数据集,并补上同步期间的后续变更。断线重连时,从库带着复制 ID 和已处理的 offset 发起 PSYNC。
大 Key 指单键的数据量、元素量或操作代价过大;热 Key 指访问或修改集中在少数键。小值也能很热,大集合也可能几乎没人访问。大 Key 会影响内存、网络、命令耗时和删除回收;热 Key 则可能让单节点、CPU 或网络成为瓶颈。
Redis 过期是 TTL 到了以后让键失效,通过访问时检查和主动过期处理等机制回收,不是给每个键安排一个必须毫秒准时执行的定时器。内存淘汰则是在达到 maxmemory 相关条件时,按策略选择键释放空间,键可能还没到期。
ZSet 的成员唯一,每个成员有一个 score。它既支持按成员查分数,也支持按分数或排名读取有序范围。在常见的跳表编码中,字典帮助按成员定位,跳表负责维护顺序和范围。
CHAR 和 VARCHAR 都用字符数声明长度,不是直接用字节数。CHAR 是固定字符长度语义,VARCHAR 按实际字符串长度保存,并需要长度信息;实际字节还取决于字符集和存储格式。
COUNT( ) 数查询结果的行数,不管这一行里有没有 NULL。COUNT(1) 对每行的非空常量 1 计数,因此结果和 COUNT( ) 一样;在 InnoDB 中,不应宣称它天然更快。
INNER JOIN 只保留满足连接条件的配对结果。LEFT JOIN 除了保留配对结果,还会给没有匹配右侧记录的左侧记录补上一份右侧 NULL。两者都不是简单地每个左表记录只出一行。右侧有多条匹配时,一条左记录也可能产生多行。
MySQL 死锁是几个事务各自持有锁,又等待对方的锁,形成无法自行推进的环。InnoDB 检测到后会选择一个事务回滚,让其他事务继续。我会先保留死锁日志,把事务 SQL、持有锁、等待锁和执行顺序对应起来。
Doublewrite 主要防的是数据页写入中途发生故障,导致页只更新了一部分。数据库页的大小和底层写入单位并不天然一致,页写入不一定是原子的。刷页时,InnoDB 会先把页写到 Doublewrite 区域,再写到数据文件的目标位置。
Buffer Pool 是 InnoDB 的内存缓冲区,主要缓存数据页、索引页等内容。查询先利用缓存里的页,缺少时再从磁盘读取,不是按 SQL 文本保存整份结果。更新通常先修改内存页。
MySQL 常见主从复制,是主库把变更记录到 binlog,从库接收后写入 relay log,再由应用线程执行这些变更。接收和应用是两个阶段,所以从库可能落后。异步复制不要求主库每次提交都等从库。
深分页慢,通常是因为数据库要找到有序结果,再跳过前面的很多条,只返回最后一小段。加索引能改善排序和读取,但不会让大 OFFSET 自动消失。
Pod 是 Kubernetes 中部署和调度的一组紧密关联容器的基本单元,同一 Pod 中的容器共享网络等资源。Deployment 声明期望的副本和模板,通常通过 ReplicaSet 等控制器维持 Pod、处理更新。
镜像包含运行需要的文件系统内容与配置,通常由可复用的只读层组成。容器是基于镜像创建的运行实例,有自己的可写层,并使用隔离与资源限制等运行机制。容器写文件通常改变自己的层或挂载的数据,不会直接修改原镜像;
反向代理是客户端先访问代理,由代理代表后端接收并转发请求。负载均衡是在多个上游实例之间选择目标,是反向代理可以提供的一项能力。Nginx 可以按轮询、权重、最少连接或哈希等方式选择上游。轮询适合工作相近的请求;
延迟队列让任务在指定时间以后变成可处理,常见方案有数据库定时扫描、内存时间轮和中间件延迟消息。扫描易于结合持久化与查询,代价是周期和扫描负载;时间轮按时间槽组织大量定时任务,适合近似调度,但内存定时器本身不解决重启恢复;
先确认积压发生在哪个消费组、分区或队列,看消息数量、最旧消息年龄以及增长趋势。再区分是生产突然增加、消费者变慢、失败重试,还是某个热点通道拖住。扩容前要找瓶颈。
先定义顺序范围,例如同一用户或同一业务实体,而不是默认追求全局顺序。同组消息应进入能维持顺序的同一分区、队列或消息组,并在消费端按组串行处理。Broker 的投递有序,不等于异步任务完成有序。
不能只给三种队列排一个固定性能名次。Kafka 的核心是分区日志,适合多组消费者独立读取与重放事件流;RabbitMQ 的传统队列模型通过交换机和绑定路由消息,常用于任务分发与灵活路由;
RBAC 通过用户、角色和权限的关系管理授权。它适合职责相对稳定的能力分组,例如编辑、审核和系统管理。ABAC 则结合主体、资源、操作以及环境等属性评估规则。例如用户所属部门是否与记录一致,记录是否在可操作状态,临时授权是否仍有效。
这三者不是同一层面的三种数据格式。REST 是一组架构约束,常见 HTTP 资源接口用资源、方法和状态表达操作;GraphQL 用类型化 Schema 描述数据,让客户端选择字段;
OAuth 2.0 主要解决授权:让应用在限定范围内访问资源,而不必拿到用户密码。OIDC 在 OAuth 之上增加身份认证语义,通过 ID Token 等信息,让客户端确认登录用户。
Spring Boot 的自动配置,是根据类路径、已有 Bean、配置属性等条件,给应用提供常用的默认配置。当前机制会发现自动配置候选,再判断这些配置及 Bean 方法上的条件。比如依赖类存在,才考虑相关能力;
@Transactional 是事务配置元数据,不是写上去就一定生效。默认代理模式下,要通过容器管理的代理进入匹配的方法;内部调用、自己创建对象或不合适的方法与代理配置,都可能让预期事务没有建立。事务建立后,还要看回滚规则。
Spring AOP 把日志、鉴权等横切逻辑放到业务方法之外,通常通过代理在匹配的方法调用前后执行增强。JDK 动态代理基于接口,调用方通过代理暴露的接口访问;
Express 和 Koa 都用中间件组织请求处理,但 next 的约定不同。Express 调用 next(),把处理交给后面的中间件。
NestJS 的依赖注入,是把对象的创建和依赖关系交给容器管理。使用方声明自己需要哪个 token,模块注册对应 Provider,容器再解析并注入实例。Provider 可以由类、现有值、工厂或已有 Provider 提供。
HashMap 不提供并发读写的同步保证。多个线程共享并修改时,需要外部同步或选择合适的并发容器。ConcurrentHashMap 支持安全的并发访问,但它不是给整个 Map 加一把大锁。读取通常不阻塞,更新按其实现协调。
Java 的 ThreadPoolExecutor 接到任务后,通常先补足核心线程,再尝试入队;队列放不下时,才继续创建线程,直到最大线程数。再接不下,就执行拒绝策略。因此,队列越大并不一定越安全。
生成器按迭代请求逐步执行,遇到 yield 返回一个值并暂停,下一次继续时保留执行位置和局部状态。它不必提前把所有结果放进列表,因此适合按需处理较大数据。但如果最后立即转换成列表,结果仍会全部进入内存;输入或内部缓存也可能继续占空间。
Python 装饰器接收一个函数或其他可装饰对象,返回处理后的对象。对函数来说,@decorator 可以理解为定义完成后执行 func = decorator(func)。
在启用 GIL 的常见 CPython 构建中,同一解释器内通常只有一个线程执行 Python 字节码。它限制的是这一类并行执行,不代表所有 I/O 都必须串行。等待 I/O 或调用会释放 GIL 的原生扩展时,多线程仍可能有效。
背压是下游消费跟不上时,把压力反馈给上游,控制继续生产或读取的节奏,避免缓冲无限增长。Node Writable 的 write 返回 false,通常表示当前缓冲已达到阈值,应等 drain 再继续写后面的数据;
Node.js 常见应用主线程上的 JavaScript 执行是单线程,但整个运行时不只有一条线程。异步 I/O、底层线程池和应用 JavaScript 的执行要分开理解。多进程或多个服务副本可以承接更多请求,并提供进程隔离。
微前端把前端产品拆成具有明确边界的应用或功能单元,让不同团队可以独立开发、构建和交付,再由统一入口组合。实现可以采用不同方式,例如应用生命周期编排、模块联邦或 iframe。它们的集成和隔离能力不同,不能把某一个工具等同于整个微前端概念。
pnpm 使用内容寻址存储复用包文件,再通过项目中的虚拟存储和链接组织依赖关系。不同项目可以复用内容,但各自仍有自己的依赖图和版本组合。lockfile 记录依赖解析结果和相关信息,让后续安装更可复现。
虚拟列表只渲染可见区域附近的少量行,同时用占位空间保留整份列表的滚动范围。用户滚动时,根据位置更新要渲染的数据区间和偏移量。
当前 Core Web Vitals 的三个指标是 LCP、INP 和 CLS。LCP 关注主要内容何时呈现;INP 关注交互到下一次画面反馈的延迟;CLS 关注意外布局偏移。
CSR 主要由浏览器执行应用代码生成界面;SSR 在请求处理时生成 HTML;SSG 在构建阶段预生成页面。它们描述的重点是页面内容的生成位置与时机。
代码分割把代码组织成多个 chunk;懒加载则把部分资源的加载推迟到需要时。代码拆开后,也可能立刻全部加载,所以两者不是同一个概念。常见方式是在路由或较重功能处使用动态 import。
Tree Shaking 是根据模块依赖和导出使用情况,移除可以安全删除的代码。ESM 的静态结构更有利于分析,但使用 ESM 并不保证所有无用代码都能删干净。副作用是关键限制。
Webpack 会从入口建立依赖图,通过模块处理规则、loader 和插件生成构建结果。它的开发服务、缓存和热更新也可以改善开发体验,不是每次修改都重新做全量构建。
hash 模式把前端路由放在后面,这一部分不会随 HTTP 请求发送到服务器,所以静态服务器通常只需要提供入口页面。history 模式使用正常的路径。
KeepAlive 可以缓存被切换出去的组件实例,让它以后重新显示时保留状态,而不是每次都重新创建。进入缓存组件的显示状态,会触发 activated;离开并进入缓存,会触发 deactivated。
父组件向子组件传数据,优先用 props;子组件通知父组件发生了什么,使用 emit。组件事件不会像 DOM 事件一样沿祖先自动冒泡。一组深层组件共享同一个上下文,例如表单、主题或组件库配置,可以用 provide/inject。
组件上的 v-model 本质上是一个约定:父组件传入 modelValue,子组件需要更新时触发 update:modelValue,父组件再更新自己的状态。
computed 适合从已有状态算出新值,例如根据购物车商品算总价。它会跟踪响应式依赖,在依赖没有变化时复用计算结果,计算函数应当保持纯粹。watch 适合有明确监听目标的副作用,例如用户改了搜索词,再请求接口。
Server Components 在服务端或构建环境中执行,原始组件代码不会作为对应客户端组件代码发送到浏览器,可以在允许的服务端环境中读取数据,再把渲染结果交给后续处理。
我会先区分局部交互状态、跨组件共享的客户端状态,以及服务端数据。只在一个表单里使用的输入,通常没必要放到全局 store。
Fiber 可以理解成 React 用来表示组件及其渲染工作的一种内部结构。React 不再只依赖一次递归调用走完整棵树,而是能记录工作进度,并在合适的工作单元边界调度后续计算。
memo 主要尝试在 props 没变化时跳过组件重渲染;useMemo 缓存一次计算的结果;useCallback 保留函数引用。它们作用的边界不同,也都不是正确性的保证。
React 使用元素类型、树中的位置以及 key 等信息来判断组件身份。列表中的 key 用来区分同一组兄弟元素,让重排后的项目能够对应回原来的组件状态。数组下标代表当前位置,不代表业务对象。
以 useState 为例,每次渲染拿到的是这一轮的状态快照。调用 setter 是提交下一次更新,不会把当前事件函数里的 count 变量改成新值。所以连续三次 setCount(count + 1),可能都提交同一个计算结果。
Cookie 的重要特点是浏览器会按域、路径、安全和 SameSite 等规则随匹配请求发送,因此常用于服务端会话;它不是专门用来存大量页面数据的。
重排通常指重新计算元素的几何布局,重绘则是更新外观。尺寸、位置和内容变化可能触发布局;颜色等变化可能只需要绘制。部分 transform、opacity 动画在合适条件下可以主要通过合成完成,但不是无条件的免费操作。
DOM 事件通常经历捕获、目标和冒泡三个阶段。捕获阶段沿祖先路径向目标走,支持冒泡的事件再从目标向外传播;目标阶段是监听目标本身的处理。事件委托通常利用冒泡,把一组子元素的处理放在稳定的父元素上。
浏览器先解析 URL,确定导航目标,再按缓存、已有连接和协议情况获取页面。需要时进行域名解析与连接建立;HTTPS 还涉及安全握手,但不能把每次导航都说成重新走完整 TCP 流程,HTTP/3 也不使用 TCP。
z-index 要放在层叠上下文里理解。同一上下文中的元素按相应绘制规则比较,子上下文作为整体参与父级排序,内部子元素不能靠更大的 z-index 越过这个整体的层级。
Flex 主要沿一条主轴分配空间,适合导航、工具栏和一排需要伸缩的元素。即使换了行,各行也主要独立计算,不天然共享一套列轨道。Grid 则先定义行列轨道,再把元素放进网格,适合需要跨行对齐、跨列占位的页面或卡片区域。
BFC 是普通块布局中的一个独立格式化区域。理解它时,我会先看容器内部和外部哪些布局关系被隔开。建立 BFC 的容器在计算自动高度时会包含内部浮动,内部子元素的外边距也不会与这个容器的外边距合并。
CSS 盒模型从里到外是 content、padding、border 和 margin。默认的 content-box 把 width 和 height 用在内容区上,内边距和边框要另外加。
TypeScript 泛型允许函数或类型接受不同输入,同时保留它们之间的关系。例如输入是某种数组,返回元素时还知道元素的类型,而不是统一变成 any。keyof T 可以取得 T 的属性键类型。
any 允许咱们按需要访问属性、调用方法,编译器会放宽相关检查。这在迁移旧代码时有时方便,但错误也可能一路传到后面的代码。unknown 同样可以接收各种值,但使用前要先判断它是什么。
type 和 interface 都可以描述对象的结构,很多普通业务对象用哪个都能写清楚,不需要把它们分成高低级。interface 适合可扩展的对象契约,可以 extends,也支持声明合并。因此,为库提供扩展点时,它比较方便。
ES Module 通过 import/export 表达模块依赖,导入通常与导出的绑定相连。CommonJS 则通过 require 执行模块并取得 module.exports,可以在运行过程中按条件加载。
Promise.all 要求全部成功,只要有一个失败,聚合结果就会失败。适合几个结果缺一不可的情况,例如页面必须同时拿到配置和权限。allSettled 会等所有任务有结果,再分别给出成功或失败,适合允许局部失败、需要完整报告的批量处理。
防抖会把一段连续触发合并处理。常见的尾部防抖,是每次触发重新计时,等一段时间没有新触发,再执行最后一次。因此,搜索建议、输入校验这类关心最终输入的功能,通常适合防抖。节流则控制执行频率。
浅拷贝会创建新的外层对象,但里面的嵌套对象通常还是原来的引用。因此,修改副本的嵌套数据,可能影响原对象。深拷贝会继续复制内部可复制的数据,让副本和原对象分开。不过,不同方法能处理的类型不同,不能把深拷贝理解成所有对象都能原样复制。
JavaScript 的普通函数,this 通常由调用方式决定。以 obj.run() 调用时,obj 是接收对象;把 run 单独拿出来调用,就不会自动记住原来的 obj。
原型链就是 JavaScript 查找对象属性的一条路径。先查对象自己的属性,没有找到,再查它的原型,继续往上找,直到原型为 null。用 new 创建实例时,实例通常会连接到构造函数的 prototype 对象。
分片上传是把大文件拆成多个部分分别传输,便于控制单次失败成本和并发。服务端需要用上传会话、分片序号与校验信息组织它们,最后完成合并或对象存储提交。断点续传是在中断以后,根据服务端确认的已完成分片继续传缺失部分。
秒杀首先需要保护系统容量。静态资源尽量提前分发,入口做身份校验、重复请求限制与限流,不让所有请求直接进入库存和数据库。库存检查与预占必须在定义好的范围内原子完成,同时记录请求或预占 ID,避免重复请求反复扣减。
消息是否可靠,需要分别检查业务到生产者、生产者到 Broker、Broker 存储与复制,以及消费者处理这几段。生产者要处理发送失败和确认不确定,Broker 要按产品机制配置持久化、复制与故障恢复。
redo log 是 InnoDB 的重做日志,支持在数据页尚未全部落盘时恢复相关修改。它不是 SQL 历史记录。undo log 保存回滚所需的记录,也参与构造一致性读所需要的旧版本。事务提交以后,不代表这些记录马上就可以全部清掉。
XSS 是不可信输入被页面当作可执行内容,攻击者因此获得当前页面里的脚本能力。主要防护是按输出上下文正确编码,富文本使用可靠净化,并避免危险的动态执行入口,CSP 可作为额外防线。
闭包是函数与它所处词法环境的组合,使函数能够访问定义位置外层的变量。外层函数返回以后,只要相关函数及环境仍然可达,需要的变量就可能继续存在。闭包不是把当时所有变量都拍成一份快照。多个函数可以共享同一个变量,读取时看到后续修改;
Vue 3 的 reactive 为对象创建响应式代理。依赖执行时读取属性,系统记录这段逻辑依赖哪个属性;属性改变后,再通知相关依赖更新。Proxy 负责拦截操作,依赖收集和触发机制负责建立对应关系。
useEffect 用来让组件与外部系统保持同步,比如建立连接、订阅事件或管理浏览器资源,不是把所有渲染后的逻辑都装进去。组件提交后,React 根据依赖决定是否运行 Effect。
同源通常要求协议、主机与端口相同。不同来源之间,浏览器按同源策略和 CORS 规则处理。有些请求可以直接发,但响应需要服务端许可,页面脚本才能读取;另一些先发 OPTIONS 预检,询问来源、方法与请求头是否允许,再发正式请求。
Session 方案通常在服务端保存会话状态,浏览器携带会话标识,服务端查到有效记录以后才接受身份。JWT 是一种 Token 格式。常见签名 JWT 携带声明,服务端验证签名、过期时间、签发方和目标接收方等条件后才能接受。
强缓存是浏览器在缓存仍然新鲜时,直接复用已有响应,不需要为了这个资源向服务器验证。常用 Cache-Control: max-age 指定新鲜期。协商缓存是在需要验证时,带着资源标识询问服务器。
浏览器中的 JavaScript,通常先执行当前任务里的同步代码。当前调用栈清空后,会在微任务检查点处理排队的微任务,随后浏览器才有机会渲染、选择下一项任务。Promise 的后续回调和 await 后面的继续执行,通常进入微任务队列;
Redis 快,是多个因素共同作用。常见数据操作主要访问内存,键查找和不同数据类型采用相应结构,网络事件处理也避免为每个连接都创建一个执行线程。“单线程”通常指常见命令的主要执行路径由主线程串行处理,不是说整个进程没有其他线程或子进程。
RDB 保存某个时点的数据快照,文件较紧凑,恢复时直接加载快照,但快照完成以后发生的写入,单靠这份 RDB 无法找回。AOF 记录用于重建数据的写入操作。
HTTP 定义请求和响应的语义,HTTPS 通常指通过 TLS 保护的 HTTP 通信。HTTP/3 使用 QUIC,而 QUIC 也集成了 TLS 1.3 的安全机制。TLS 主要处理保密性、完整性和身份验证。
TCP 三次握手的核心,是同步双方初始序号,并确认各自发送的 SYN 已经被对方收到。客户端先发 SYN,服务端用 SYN 加 ACK 既确认客户端,又提出自己的序号,客户端再发 ACK 确认服务端。
进程是操作系统中的资源与隔离单位,通常有独立地址空间;同一进程里的线程共享很多资源,各自有执行状态,可以由操作系统调度。协程则通常由语言运行时或库安排。
所谓索引失效,实际要分清两种情况:查询条件无法利用索引有效定位,以及索引可用,但优化器没有选择它。例如,对索引列做函数处理、发生某些隐式转换,或者字符串查询以通配符开头,可能无法按原索引缩小范围。
MVCC 是多版本并发控制。InnoDB 为记录保留版本信息,并通过 undo 记录回溯旧版本,让普通一致性读能够读取符合自己快照的数据,而不必总等待其他事务的写锁。Read View 是判断版本是否可见的读取视图。
Redis 分布式锁常见的基础做法,是用一条 SET 命令同时完成“不存在才设置”和“设置有效期”。锁值使用本次申请的唯一标识,释放时只有值仍属于自己,才原子删除。但这只是有租期的互斥。锁过期以后,原来的程序不会自动停止;
这里通常讨论的是 InnoDB 的常见索引,不能把所有 MySQL 索引都说成同一种结构。B+ 树内部节点主要保存键和指向下一层的指针,一个页能容纳较多分支,因此树通常较矮。
缓存穿透、击穿和雪崩,都可能让请求大量访问数据库,但触发原因不同。穿透通常是反复查询本来就不存在的数据,缓存和数据库都没有结果。可以做参数检查、短期空值缓存,必要时用布隆过滤器提前筛选。击穿是某个热点缓存失效以后,大量请求同时回源。