跳到主要内容

sed 命令

· 阅读需 2 分钟

sed 可以在不打开编辑器的情况下,对文件进行精准的增删改。

sed -i

替换

sed -i 's/旧/新/g' path: /s 表示替换, /g 表示全局匹配

# 全局替换
sed -i 's/listen 80/listen 8080/g' nginx.conf

# 只替换 10-20 行之间的内容
sed -i '10,20s/listen 80/listen 8080/g' nginx.conf

# 指定 # 作为分隔符
sed -i 's#/var/log/nginx#/data/logs/nginx#g' docker-compose.yml

删除

/d 删除整行

# 删除包含 DEBUG 字符的行
sed -i '/DEBUG/d' application.log

# 删除第 5 行
sed -i '5d' application.log

# 删除从第 5 行到文件末尾(用$表示)
sed -i '5,$d' application.log

# 删除所有空行
sed -i '/^$/d' application.log

注释

'/搜索模式/s/旧/新/':先找到包含特定字符串的那一行,然后只在这一行内执行替换操作

# 将包含 "PasswordAuthentication" 的行注释掉
sed -i '/PasswordAuthentication/s/^/# /' /etc/ssh/sshd_config

# 开启系统 IP 转发(常用于 VPN 或 K8s 节点配置)
sed -i '/net.ipv4.ip_forward/s/^#\s*//' /etc/sysctl.conf

插入

/a (append)在匹配到的行的下面新增内容, /i (insert)在匹配行上面新增内容.

# 在 "[mysqld]" 这一行下面添加最大连接数配置
sed -i '/\[mysqld\]/a max_connections = 1000' my.cnf

# 在定义 server_name 的行前面插入一条 listen 指令
sed -i '/server_name/i listen 443 ssl;' blog.conf

2026-05-22 sed 指定分隔符

file.txt 中的 /www/abc 替换为 /opt/efg.

sed -i 's|/www/abc|/opt/efg|g' file.txt

2026-0-27 批量修改

本目录下

sed -i 's/abc/123/g' *.txt

指定路径

sed -i 's/abc/123/g'  /xxx/xxx/*.txt

执行 git push 的时候出现报错

· 阅读需 1 分钟

报错信息:

# git push 

Enumerating objects: 9, done.
Counting objects: 100% (9/9), done.
Delta compression using up to 4 threads
Compressing objects: 100% (4/4), done.
Writing objects: 100% (5/5), 511 bytes | 511.00 KiB/s, done.
Total 5 (delta 3), reused 0 (delta 0), pack-reused 0
remote: fatal: not a git repository: '.'
remote: fatal: not in a git directory
remote: fatal: not a git repository: '.'
To xxxx.git
d124998..c69745a master -> master

原因:远程仓库的 git hooks 执行失败。 一般是 post-receive。在 post-receive 脚本中,有 cd 到其他目录执行 git 命令。

解决方法:git 在运行 hook 时,会自动设置一个 GIT_DIR-='.' 的环境变量。需要执行 unset GIT_DIR 来清除这个变量。

Hyper-V 虚拟机无法获取 IP

· 阅读需 1 分钟

在宿主机 Terminal(Admin) 执行下面的命令

Restart-Service hns
Restart-Service SharedAccess

NTP 授时服务器搭建

· 阅读需 2 分钟

以 Ubuntu 为例

安装 chrony

sudo apt update
sudo apt install -y chrony

配置文件

文件路径: /etc/chrony/chrony.conf

  • pool: 配置上游时间源
  • local: 开启“本地参考时钟”模式
  • stratum:可信层级,值越低,可信度越高。只在 local 模式生效。取值范围(1-15,默认 10)
    • local stratum 10 表示即使当前没有上游同步源,也向客户端提供时间
  • allow: 配置允许取时的网段
  • makestep: 当系统时间偏差太大时,不再“慢慢校正”,而是直接把时间调到正确值
    • makestep 1.0 3 表示如果时间偏差大于 1 秒,且在 chrony 启动后的前 3 次时钟更新,就会直接更新时间,否则采用平滑校时(每秒调整 0.083333s)
    • makestep threshold limit limit 为负数表示所有更新都允许直接更新。
  • rtcsync: 定期将当前系统时间写入硬件实时时钟 RTC(Real-Time Clock).

联网授时服务器配置

# 上游时间源
pool ntp.aliyun.com iburst
pool time.cloudflare.com iburst
pool time.google.com iburst

makestep 1.0 3
rtcsync
allow 192.168.1.0/24

离线内网授时服务器

local stratum 10
makestep 1.0 3
rtcsync
allow 192.168.1.0/24

设置开机自启

sudo systemctl enable --now chronyd

防火墙放开 UDP 123 端口

firewall

sudo firewall-cmd --permanent --add-port=123/udp
sudo firewall-cmd --reload

ufw

sudo ufw allow 123/udp

验证

chronyc tracking
chronyc sources -v
ss -tunlp | grep "123"

在 Windows 上验证

w32tm /stripchart /computer:192.168.1.10 /samples:5 /dataonly

问题

1. chrony 已启动,但是没有监听 123 端口

通过 systemctl status chrony 查到 chrony 以启动。

ss -tunlp | grep 123 没有查询到监听 123 的进程。

原因:如果没有配置 allow 指令, chrony 是不会监听 UDP 123 端口的。

通过下面的命令来查询是否有配置 allow

grep -nE '^[[:space:]]*allow|^[[:space:]]*deny|^[[:space:]]*port' /etc/chrony/chrony.conf

2. 立即强制同步时间

chronyc makestep

3. chrony 向上游取时的具体过程

发包 -> 测量 -> 筛选 -> 选源 -> 校时

chrony 不是“从上游拿一个时间就直接设置本机”,而是“持续从多个上游拿样本,评估质量,排除坏源,选出最佳参考,再结合历史频率模型去校正本机时钟”

OpenVPN 的 server.conf 配置

· 阅读需 1 分钟
push "route 192.168.11.0 255.255.255.0"

表示将路由下发给客户端. 当客户端连上 VPN 之后,服务器会通知客户端,到 192.168.11.0/24 这个网段流量,走 VPN 隧道。

route 192.168.11.0 255.255.255.0

CCD 文件 + iroute

route 192.168.11.0 255.255.255.0
client-config-dir ccd
iroute 192.168.11.0 255.255.255.0

让 OpenVPN 进程内部知道这个网段在某个特定客户端后面。

分片与副本机制研究

· 阅读需 2 分钟

Gemini: https://gemini.google.com/share/f5c5f79c9d34

导读

副本

  • 主从复制
  • 多主复制

分片

  • 数据在哪里分片?
    1. 在应用程序管理一个巨大的数据库连接池集合,对 JDBC 进行连接.(Apache-ShardingSphere-JDBC)
    2. 在应用程序与数据库之间搭建一个代理(Vitess)
  • 分片策略
    • 散列算法
    • 范围分片
    • 目录分片
    • 地理位置分片
    • 列表分片
    • 复合/混合分片
  • 读写分离
    • 读请求:负载均衡至所有分片
    • 写请求:请求主库
  • 数据聚合
    • 聚合函数
      • max,min
      • count
      • sum
      • avg -> sun/count
    • 关联查询
      • 从分片上下功夫,将关联条件作为分片的 key
      • 广播表(每个分片中都存在)
      • 数据冗余,避免关联查询
      • 在应用程序层面关联
  • 全局唯一 ID
    • UUID 的升级版(包含时间戳)
    • 号段模式(美团 Leaf)
    • 雪花算法(单机递增,全局趋势递增,时间回拨问题)
    • Redis 自增
    • Zookeeper 自增
  • 分布式事务

短链系统

  1. 号段模式(Segment) + 混淆加密(Feistel Cipher) + Base62 编码
  2. 独立预发号服务(Key Generation Service,KGS)
    • 独立的后台服务,在空闲时不断生成 6-7 位的 Base62 字符串
    • 查询数据库是否已存在
    • 从未使用密钥表中快速拿走一个可用的短字符串。
  3. uuid , 不推荐,长度太长
  4. 雪花算法,长度不符合,递增
  5. 哈希值,取前 6-7 位,有重复危险

Feistel Cipher 算法

  1. 将连续,自增的 ID 转换为完全随机,跳跃的密文整数
  2. 不会出现碰撞
  3. 生成的整数通过 base62 编码等到的字符串长度为 5-7
  4. 可以逆向解码