0%

镜像与容器

Docker 镜像和容器的区别是什么?

一句话原理 Docker 镜像是静态的只读模板(相当于“类”或“安装包”),包含了运行应用所需的代码、库和环境;而容器是镜像的动态运行实例(相当于“对象”或“进程”),拥有独立的文件系统和资源隔离环境。

一句话源码 在操作层面,通过 docker builddocker pull 生成镜像,通过 docker run 将镜像实例化为容器,容器在镜像层之上叠加了一个可写的容器层。

一句话项目/场景 在 CI/CD 流水线中,开发人员构建出一个版本固定的 镜像,测试人员将该镜像部署到测试环境运行成 容器,运维人员再将同一镜像部署到生产环境,实现“一次构建,到处运行”。


详细区别对比

维度Docker 镜像Docker 容器
生命周期静态,永久存储(除非手动删除)动态,可创建、启动、停止、销毁
面向对象类比对象
物理文件类比安装包 / 光盘运行中的软件 / 正在播放的电影
读写权限只读,不可修改可读写,修改发生在最上层
关系是容器的基础模板是镜像的运行实例
存储结构分层存储,多层共享,节省空间在镜像层之上增加“容器层”

基础实现

如何用 Redis 实现分布式锁?核心步骤是什么?

一句话原理:Redis 分布式锁基于“占用式”思想,利用 SET NX EX 原子命令抢占锁标识,通过唯一 Value 防止误删,并结合 Lua 脚本确保“判断+删除”解锁过程的原子性。

一句话源码:在 db.c 中,SET NX 命令本质上调用 setKey 函数,在 lookupKeyWrite 查找 Key 不存在时执行 dbAdd 写入并关联 setExpire 过期时间,从而实现互斥。

一句话项目/场景:在电商秒杀扣减库存场景中,使用 SET lock:stock UUID NX EX 10 加锁,业务执行完毕后通过 Lua 脚本校验 UUID 并 DEL,严防超卖与死锁。

Redis 为什么这么快?(内存、IO 多路复用、单线程)

一句话原理:Redis 基于纯内存操作规避磁盘 I/O 瓶颈,利用 epoll 机制实现 IO 多路复用,在单线程事件循环中串行处理命令,彻底避免了多线程上下文切换与锁竞争的开销。

一句话源码:核心逻辑位于 aeProcessEvents 函数,通过 aeApiPoll 监听就绪 Socket,将网络读写与命令执行封装为 FileEvent 事件,在主线程中由 aeMain 循环按顺序无锁调度执行。

一句话项目/场景:在 Redis 6/7 版本的高并发场景下,针对网络 I/O 瓶颈引入多线程进行数据协议的读写解析,但核心命令执行仍保持单线程,既利用多核提升吞吐,又规避了事务与 Lua 脚本的并发原子性问题。

数据库和缓存双写时,如何保证一致性?

一句话原理: 采用“先更新数据库,再删除缓存”的策略(Cache Aside Pattern),配合异步重试机制或 Binlog 订阅(如 Canal),在保证数据库持久化成功的前提下,最终一致性地删除过期缓存。

一句话源码: 在业务 Service 层代码中,通常将数据库更新操作与缓存删除操作封装在同一个本地事务 @Transactional 下,顺序执行 db.update()cache.delete(),并通过消息队列记录删除失败的 Key 以便补偿。

一句话项目/场景: 在电商“订单状态修改”场景中,先更新 MySQL 订单表,再删除 Redis 中的订单缓存,若因网络抖动导致删除失败,通过监听 MySQL Binlog 自动触发缓存删除重试,确保用户查询时能读到最新状态,避免“退款成功但前端仍显示处理中”的业务故障。