跳到主要内容

分片与副本机制研究

· 阅读需 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. 可以逆向解码

EditorConfig, ESLint, Prettier 之间的关系

· 阅读需 1 分钟

Gemini Deep research: https://gemini.google.com/share/2881e5f26082

EditorConfig​

EditorConfig 是为了解决不同的操作系统,编辑器之间差异的。如 换行符,tab 字符的长度。对任何文本格式的文件生效。如 .md,Makefile,.yaml,.sh

从 JSLint 到 ESLint​

在不运行代码的前提下,解析代码(AST 静态分析), 发现语法逻辑问题(未定义变量,类型错误等)。

JSLint,不可配置 JSHint, 可配置,不支持第三方插件 ESLint, 一切皆可插拔

ESLint 要求每一个规则都是原子性的。

Prettier​

Prettier 是为了解决代码格式化问题的。

  • 最大行宽
  • 括号对齐
  • 标签闭合
  • ...

eslint-config-prettier​

解决 eslint 与 prettier 职责交叉的问题。

Oxlint​

Rust 开发,性能更好。比 ESLint 快 50~100 倍。

git log 命令过滤提交记录

· 阅读需 1 分钟
git log --grep="feat" --grep="接口" -i --oneline --all-match
  1. 单独使用 --grep="feat" --grep="接口" 表示过滤出 git commit message 包含 feat 或 接口 的提交记录(OR 的逻辑). 如果加上 --all-match 表示要包含 feat 和 接口。(AND 的逻辑)
  2. -i 忽略大小写
  3. `--oneline

Markdown 中的 mermaid 语法

· 阅读需 3 分钟

注释: %%

Flowchart 流程图​

  • TD 表示 "top-down"

  • LR 表示 "left-right"

节点形状​

  • [矩形]
  • (圆角矩形)
  • {菱形} 用于判断条件
  • ((圆))

连接线​

  • --> 带箭头的实线
  • --- 实线
  • ==> 加粗
  • -.-> 带箭头的虚线
  • |文字|,在线上添加文字, 或 --text-->
  • <--> 双向箭头

Sequence Diagram 时序图​

参与者​

  • participant 名字 参与者
  • actor 名字 将参与者显示为小人图标

消息交互​

  • A->>B: 文字 实现箭头 请求
  • B-->>A: 文字 虚线剪头 响应

生命周期​

  • activate A 激活 deactivate A 取消激活 表示一个参与者处于“处理中”的状态
  • ->>+ 激活 -->>- 取消激活

注释​

  • Note right of A: 文字 在 A 的右侧添加注释

扫码登录​

flowchart TD
Start((开始)) --> GetQR[PC端请求登录]
GetQR --> ShowQR[展示二维码]

subgraph Mobile [手机端操作]
Scan[用户打开App扫码] --> Auth{是否授权?}
Auth -->|是| AppConfirm[点击确认登录]
Auth -->|否| AppCancel[点击取消]
end

ShowQR -- 轮询/Scoket --> CheckState{检查二维码状态}

Scan -.-> CheckState
AppConfirm -.-> CheckState

CheckState -->|wait| ShowQR
CheckState -->|scan| Prompt[请在手机端确认]
Prompt --> CheckState

CheckState -->|过期| Expired[二维码失效]
Expired --> Refresh[点击刷新] --> GetQR

CheckState -->|登录成功| Success[获取 token/跳转首页]
Success --> End((结束))

subgraph ... end 表示把这一块逻辑框在一起,在视觉上把他们看成一个整体。

sequenceDiagram
autonumber
participant PC as 浏览器
participant Server as 服务器
participant Phone as 手机APP

Note over PC,Server: 阶段一:初始化二维码
PC->>Server: 1. 请求生成二维码(GET /qrcode)
Server-->>PC: 2. 返回二维码ID(UUID)

Note over PC,Server: 阶段二:轮询检测状态
loop 每隔2秒查询一次
PC->>Server: 3. 询问 UUID状态(GET /check?uuid=xyz)
alt 状态: 已扫码(WAITING)
Server-->>PC: keep waiting
else 状态: 已扫码(SACNNED)
Phone->>Server: 4. 扫码请求(POST /scan)
Server-->>PC: scanned(PC显示用户头像)
else 状态:已确认(CONFIRMED)
Phone->>Server: 5. 登录确认(POST /confirm)
Server-->>PC: token(登录凭证)
end
end

Note over PC: 阶段三: 登录完成
PC->>PC: 写入token并跳转首页
  1. autonumber 表示自动给箭头添加序号
  2. loop...end 表示循环块
  3. alt...else...end 表示 if -else if - else
  4. Note over ... 跨越多个参与者的注释,用于划分流程/阶段。

yaml 的数组语法

· 阅读需 1 分钟

块格式​

fruits:
- Apple
- Orange
numbers:
- 1
- 2

流格式​

fruits: ["Apple", "Orange"]
numbers: [1, 2]

对象数组​

users:
- name: Alice
job: Engineer
active: true
- name: Bob
job: Designer
active: false

- 表示一个新的数组元素的开始。 name,hob,active 属于同一个对象。

多维数组​

matrix_flow:
- [1, 2, 3]
- [11, 22, 33]
- [111, 222, 333]

yaml 的长文本语法

· 阅读需 1 分钟

保留换行 |​

script: |
echo "hello wrold"
date

| 会保留每次换行。 (末尾有多个换行符时,只会保留一个)

{"script": "echo \"Hello World\"\ndate\n"}

折叠换行 >​

description: >
aaa1
bbb2
ccc3

ddd4

> 会将换行符替换为空格。 如果包含空行,会保留一个换行符

{"description":"aaa1 bbb2 ccc3\ndddd4\n"}

剪裁控制​

|- 删除末尾的 \n

|+ 保留末尾的 \n

MySQL with 的用法

· 阅读需 1 分钟

使用 with 创建临时结果集(Common Table Expression - CTE)。

  1. 简单 CTE
WITH sales_summary AS (
SELECT
product_id,
SUM(amount) as total_sales
FROM orders
WHERE order_date >= '2026-01-01'
GROUP BY product_id
)
SELECT
p.product_name,
s.total_sales
FROM products p
JOIN sales_summary s ON p.id = s.product_id;
  1. 多个 CTE
WITH
regional_sales AS (
SELECT region, SUM(amount) AS total_sales
FROM orders
GROUP BY region
),
top_regions AS (
SELECT region
FROM regional_sales
WHERE total_sales > (SELECT SUM(total_sales)/10 FROM regional_sales)
)
SELECT
region,
product,
SUM(quantity) AS product_units
FROM orders
WHERE region IN (SELECT region FROM top_regions)
GROUP BY region, product;
  1. 递归 CTE, 类比为递归函数
WITH RECURSIVE factorial AS (
SELECT 1 AS n, 1 AS fact
UNION ALL
SELECT n + 1, (n + 1) * fact
FROM factorial
WHERE n < 1
)
SELECT * FROM factorial;
WITH RECURSIVE number_seq (num, squared) AS (
-- Anchor: 初始值
SELECT 1, 1

UNION ALL

-- Recursive: num < 5 是终止条件
SELECT num + 1, (num + 1) * (num + 1)
FROM number_seq
WHERE num < 2
)
SELECT * FROM number_seq;

partition by 与 group by 的区别

· 阅读需 1 分钟

group by x1,x2 ...

将除了 x1,x2 以外的字段通过聚合函数 “压缩” 成一行。

select department,avg(salary) from employees group by department;

窗口函数() over (partition by 分组列 order by 排序列)

根据分组列进行分组,然后对每个组通过排序列进行排序,最后通过窗口函数计算每列的值。

select name,department,avg(salary) over (partition by department) as '平均工资',salary - avg(salary) over (partition by department) as '和平均差距' from employees;