作者小头像 Lv.2
84 成长值

个人介绍

这个人很懒,什么都没有留下

感兴趣或擅长的领域

暂无数据
个人勋章
TA还没获得勋章~
成长雷达
75
9
0
0
0

个人资料

个人介绍

这个人很懒,什么都没有留下

感兴趣或擅长的领域

暂无数据

达成规则

他的回复:
两阶段提交(2PC)解决的是:redo log(引擎层,保证 crash-safe)和 binlog(Server 层,用于主从复制/归档)两份日志必须状态一致,否则会出现「主库恢复后数据与 binlog 不符」,进而主从不一致。一条 UPDATE 的写入时序(以 InnoDB + 开启 binlog 为例):执行器取数据、改内存数据页;Prepare 阶段:写 redo log,状态置为 prepare,并刷盘(由 innodb_flush_log_at_trx_commit 决定);写 binlog(Server 层),刷盘(由 sync_binlog 决定);Commit 阶段:把 redo log 状态改成 commit,事务提交完成。崩溃恢复时 MySQL 怎么判定(这正是 2PC 的关键):redo 里事务是 commit → 直接提交;redo 里是 prepare,但binlog 完整存在(有 XID event 且完整) → 提交;redo 里是 prepare,binlog 不完整或不存在 → 回滚。判定的桥梁是 XID:redo 和 binlog 用同一个 XID 关联,崩溃恢复时扫描 binlog 末尾找到已写入的 XID 集合,与 prepare 状态的 redo 事务比对,从而决定提交还是回滚。没有两阶段提交会怎样:先写 redo 后写 binlog,中间崩溃 → redo 提交成功(主库有这条数据),binlog 没记(从库没有)→ 主从数据不一致,从库少数据;先写 binlog 后写 redo,中间崩溃 → binlog 有(从库同步了这条),redo 没提交(主库崩溃恢复后回滚,数据没了)→ 从库多数据,同样不一致。顺带说两个常被追问的点:为什么还需要 redo,不能只靠 binlog:binlog 是逻辑日志(记录 SQL 或行变更前后的逻辑值),没有「数据页恢复到某个时刻」的能力;而且 binlog 没有页级 checksum 和 crash recovery 机制。redo 是物理日志,能把崩溃时只写了一半的数据页恢复出来。组提交(group commit):单事务两次刷盘(redo prepare + binlog)代价高,MySQL 用组提交把多个事务的刷盘合并,配合 binlog_group_commit_sync_delay / _no_delay_count 可提升吞吐(会略微增加单事务延迟)。生产上建议 innodb_flush_log_at_trx_commit=1 + sync_binlog=1(双 1),这是数据不丢的最低要求;能接受秒级丢失才考虑放宽。
发布时间 2026/10/18 16:30:24 最后回复 yd_292694877 2026/10/22 13:40:47 版块 数据库
10 3 0
他的回复:
Online DDL 的核心是「把阻塞性的表重建动作,改成在后台增量进行 + 用 row log 补齐增量」,从 5.6 起引入,8.0 又加了 instant 算法。三种算法:ALGORITHM=INSTANT(8.0+):只改数据字典元数据,秒级完成,不重建表。适用:加列(默认加到末尾)、改列默认值、改 ENUM/SET 末尾追加值、重命名表。ALGORITHM=INPLACE:不建临时表,在原地重建/修改,期间允许并发 DML(靠 row log 记录在 DDL 期间产生的变更,最后回放)。适用:加/删二级索引、改列长度(不缩小)、OPTIMIZE TABLE、加主键(需重建)。ALGORITHM=COPY:拷表 + 全程锁,最慢,基本等于 offline。锁的三种粒度(用 LOCK=NONE / SHARED / EXCLUSIVE 指定,MySQL 会自动降级取最强可用的):LOCK=NONE:不阻塞读写,真正的「Online」;LOCK=SHARED:允许读、阻塞写;LOCK=EXCLUSIVE:读写全阻塞。哪些常见 ALTER 可以做到不锁表(LOCK=NONE):创建/删除二级索引(CREATE INDEX、DROP INDEX);8.0 加列(INSTANT,秒级);修改列默认值、改列名(8.0)、改 VARCHAR 长度(字节数不减小且不超过 255→256 这类跨长度字节边界的情况);增删外键(需各自开关 foreign_key_checks);OPTIMIZE TABLE、ALTER TABLE ... FORCE(INPLACE + 并发 DML)。哪些一定会锁(要避开业务高峰):删列、改列类型(如 INT→BIGINT)、改字符集、缩 VARCHAR 长度、加主键(要重建数据)、改表级 ROW_FORMAT。实操建议:先显式写 ALTER TABLE t ADD COLUMN c INT, ALGORITHM=INSTANT, LOCK=NONE; —— 不支持时 MySQL 会直接报错,而不是悄悄退化成 COPY,避免踩坑;大表改结构优先用 gh-ost / pt-online-schema-change(触发器或 binlog 追增量),可控可限速可暂停;注意 元数据锁(MDL):即使 DDL 本身是 LOCK=NONE,若事务里有未提交的旧事务持有 MDL,DDL 会卡在 Waiting for table metadata lock 并阻塞后续所有查询——上线前先查 performance_schema.metadata_locks 杀掉长事务;从库延迟:DDL 在主库完成后才传到从库,大表 DDL 会造成从库延迟突增,读写分离场景要评估。
他的回复:
两个工具都用过,直接说结论:华为云生态用 obsutil 最稳,跨云/通用场景 rclone 更灵活。结合你的场景(轻量服务器 + Docker + SQLite 每日异地备份)给一套配置思路:工具选择obsutil 是华为云官方工具,对 OBS 的特性支持最全(断点续传、跨域复制、存量对比),命令 obsutil sync /data obs://bucket/backup 只传变化的文件;rclone 走 S3 兼容协议(endpoint 配 obs.cn-north-4.myhuaweicloud.com),优势是配置统一、后端可换(S3/MinIO/本地),rclone sync 语义相同。省流量和省请求费的几个关键点1. 同区域走内网 endpoint:ECS 和 OBS 桶同区域时用内网域名(obs.internal 或控制台展示的内网 endpoint),流量免费且更快,这是最大的一笔节省;2. 别全量 cp,用增量 sync:每天打包全量再传是最费流量和请求的。SQLite 用 sqlite3 db ".backup /data/backup.db" 做在线热备,再配合 rsync/rclone sync 增量传;3. 打包成大对象:OBS 按请求次数计费,几千个小文件的请求费很可观。按天打包 tar.gz 再传,一个对象一次 PUT;4. 生命周期自动清理:桶策略配置"创建 7 天后自动删除"(控制台 → 基础配置 → 生命周期),旧备份自动清,不用自己写 rm;5. 限速防抖动:obsutil 加 -threshold=52428800(分块阈值)、rclone 加 --bwlimit 10M,避免备份流量把业务带宽打满。定时与安全crontab 里 0 3 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1;AK/SK 不要写脚本,用环境变量或 obsutil 的 obsutil config -i 生成的配置文件(权限 600)。恢复演练建议每季度做一次,备份没验证过等于没备份。
发布时间 2026/10/21 15:52:15 最后回复 yd_265768724 2026/10/22 15:10:39 版块 开发者空间
30 5 0
他的回复:
ABA 是什么:线程 1 读出共享变量值是 A,准备 CAS 更新成 C;此时线程 2 把值改成 B 又改回 A。线程 1 的 CAS 执行时发现"值还是 A",校验通过,更新成功——但中间语义已经变过一次(A 早已不是原来那个 A)。经典场景是无锁栈弹出节点:节点被 POP 后释放、内存被复用、又被 PUSH 回同一个地址,CAS 会误判"栈没变"。三种解法分别从不同角度动手:1. Tagged Pointer(版本号):把"值+版本计数器"打包成一个机器字(利用指针低位寻址对齐空闲位,或 64 位系统高 16 位存版本号),每次 CAS 比对整个字。Java 里的 AtomicStampedReference 就是这个思路(value + stamp 一起 CAS)。改动最小、最实用,绝大多数业务场景用它就够了。2. Hazard Pointer(风险指针):每个读线程在访问共享节点前,把自己的"正在用这个指针"发布到全局表;回收方在 free 之前扫描全表,发现有人还在用就推迟回收。它解决的是 ABA 的根源——节点被提前释放/复用,而不是比对逻辑。代价是每次读要写两次内存(发布+清除),且需要精心设计 retire 链表。3. RCU(Read-Copy-Update):读侧完全无锁无同步,写方先改副本再原子替换指针,然后等待一个"宽限期"(所有读线程都已完成临界区)后才回收旧数据。Linux 内核和很多高并发库用它,适合读多写极少的场景(路由表、配置)。实践建议:业务代码先上带版本号的 CAS(AtomicStampedReference 或自己维护 version 字段);只有自研并发数据结构(队列、哈希表)才需要考虑 Hazard Pointer/RCU。另外,现代语言里 GC 已经消灭了"节点释放后复用"这一类 ABA 的温床(Java 的 ConcurrentLinkedQueue 靠 GC + 自旋就能防住大部分问题),真遇到再说。
发布时间 2026/10/21 21:39:14 最后回复 yd_252909794 2026/10/22 12:54:43 版块 智慧园区
12 4 0
发布时间 2026/10/21 21:49:32 最后回复 yd_292694877 2026/10/22 10:40:26 版块 智慧园区
10 3 0
他的回复:
灰度发布的核心是把请求流量按规则分流到新旧版本,再配合可观测和快速回滚。常见实现按层分:1. 接入层分流(最常用,改配置即生效)Nginx/API 网关按权重分流,配两个 upstream,按百分比切流量:upstream app { server 10.0.1.10:8080 weight=95; # 旧版 server 10.0.1.11:8080 weight=5; # 新版}优点:不动业务代码、秒级生效秒级回滚;缺点:只能按整体比例,细粒度要配合 cookie/header。按用户白名单灰度可用 map + cookie 精确到人。2. 服务网格(细粒度)Istio VirtualService 可以按 header(如 userId、租户 ID)、路径、权重多维分流,规则集中在控制面,不侵入应用。适合微服务多版本并存、AB 实验场景,代价是引入 mesh 运维复杂度。3. 部署策略配合蓝绿部署:两套完整环境,流量整体切换,回滚最快但成本双倍;金丝雀:先 1 台/1% 流量,观察错误率、P99 延迟、业务指标(转化率)再逐步放量 5%→25%→100%;滚动发布:分批替换实例,无需双倍资源但回滚慢。安全控制新旧版本流量比例的关键实践:1. 放量阶梯固定化(1%→5%→25%→全量),每档设置最短观察期(如 30 分钟),指标劣化自动回滚;2. 关键路径加 feature flag(配置中心动态开关),出问题先关功能再谈回滚;3. 灰度期打标(trace 里带版本 tag),出问题能按版本定位;4. 数据库 schema 必须向后兼容:新版本先兼容旧结构(加字段不删字段、不改类型),旧版本代码要能跑在新 schema 上,否则回滚即事故。中小规模系统用 Nginx 权重+feature flag 就够了;多团队微服务再上 Istio。
发布时间 2026/10/21 22:11:05 最后回复 yd_292694877 2026/10/22 10:40:03 版块 智慧园区
13 4 0
他的回复:
多实例环境下(无单点 DB/缓存可用时)选型,按一致性要求从松到紧:1. Redis 方案(最常用,性能最好)加锁用一条原子命令,value 放唯一标识(UUID+线程名),NX 保证互斥,PX 保证兜底过期:SET lock:order:12345 {uuid} NX PX 30000释放必须用 Lua 脚本比对 value 再删,防止误解锁(自己的锁超时后被别人拿到,直接 DEL 会删掉别人的锁):if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("del", KEYS[1])end工程要点:① 执行业务超过锁过期时间要配看门狗续期(Redisson 的 watchdog 默认 30s 续到 30s);② 单实例 Redis 主从切换会丢锁,要求严格互斥要么用 RedLock(多主多数派,有争议但比裸单节点强),要么接受极小概率互斥失效并在业务层做幂等兜底;③ 锁粒度尽量细到业务 ID,别用全局大锁。2. 数据库唯一索引(最简单可靠)建一张锁表,(lock_name) 加唯一索引,插入成功即拿到锁,删除即释放。优点是不依赖额外组件、强一致;缺点是性能差(单行插入几千 QPS 上限)、需要定期清理僵死行。适合低频关键操作(对账、结算、发奖)。3. ZooKeeper/etcd 临时顺序节点(强一致但重)客户端在锁路径下创建临时顺序节点,序号最小者持锁,其余 watch 前一个节点。会话断开自动删除,不会有死锁;raft/zab 保证强一致。适合已有 zk/etcd 基建、对正确性敏感但量不大的场景,延迟比 Redis 高一个量级。选型建议:高并发短任务用 Redis+看门狗;已有 DB 且并发低用唯一索引;金融级强一致且已有 etcd 用 etcd。任何方案都建议业务侧做幂等(锁只是减少并发,不是正确性保证)。
他的回复:
两种方案都可行,结合你的场景(单机小内存 Debian 12 + lxcbr0 + 只想暴露一个 Web 服务),按推荐程度排序:方案一:宿主机反代(最省心,推荐)如果容器里跑的就是 HTTP 服务,根本不用动 iptables。在宿主机装 nginx 或 caddy,直接反代到容器内网地址:server { listen 8080; location / { proxy_pass http://10.0.3.10:80; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; }}优点:不用开 ip_forward、不用写 NAT 规则、顺手解决 TLS(caddy 自动签证书)、能加访问日志和基础认证。缺点是多一跳,性能损耗在小内存机器上可以忽略。方案二:LXC 原生端口转发(容器配置即文档)LXC 4.x 没有内置端口映射参数(不像 Docker -p),但可以在容器 config 里用 script.up 挂钩子,把 DNAT 规则和容器生命周期绑定,容器停止时自动清理:/var/lib/lxc/你的容器名/config 末尾加:lxc.net.0.script.up = /usr/local/bin/lxc-up-dnatlxc.net.0.script.down = /usr/local/bin/lxc-down-dnat/usr/local/bin/lxc-up-dnat:#!/bin/sh[ "$LXC_NET_TYPE" = "veth" ] || exit 0sysctl -w net.ipv4.ip_forward=1iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 10.0.3.10:80iptables -t nat -A POSTROUTING -s 10.0.3.0/24 ! -d 10.0.3.0/24 -j MASQUERADElxc-down-dnat 把两条规则换成 -D 删除即可。好处是规则跟着容器走,重启不丢;lxcbr0 的子网掩码一般是 /24,按实际改。方案三:手写 iptables/nftables(Debian 12 注意)Debian 12 的 iptables 默认已是 nft 后端(iptables-nft),命令照常用,但持久化要用 nftables 的方式:sysctl -w net.ipv4.ip_forward=1iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 10.0.3.10:80持久化:apt install iptables-persistent(Debian 12 里它会调 netfilter-persistent,规则存 /etc/iptables/rules.v4);或者干脆写原生 nft 规则到 /etc/nftables.conf。只加 PREROUTING 不够——回程包需要 MASQUERADE/SNAT,否则容器回包源地址是 10.0.3.10,客户端收到直接丢弃。几个容易踩的坑1. 容器内服务必须监听 0.0.0.0:80,只听 127.0.0.1 的话 DNAT 进去了也没人应答;2. 云服务器控制台的安全组入方向要放行 TCP 8080,和系统内规则是两道门;3. 如果之后要给第二个容器映射同一个宿主机端口,用 --dport 区分,DNAT 的 to-destination 可以带端口做转换;4. 想验证规则是否生效:宿主机上 curl -H "Host: xxx" http://127.0.0.1:8080 走的是 PREROUTING 之前的 OUTPUT 链,测试外网映射要用另一台机器,或者加一条 -A OUTPUT -t nat 规则。个人建议:单容器单服务直接上方案一,规则可控、排查最直观;容器数量多了再上方案二做生命周期绑定。