docs(note): 新增 excel/正则/Nginx 笔记并整理目录
- 新增 AGENTS.md 仓库说明与 excelize 依赖 - 新增正则表达式、go操作excel、Nginx常见错误、Golang底层架构笔记 - 布尔变量命名迁移至资源/编程/规范,删除随手记旧笔记
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
## Nginx 反代未透传客户端 IP 导致服务端日志全量变为 127.0.0.1
|
||||
|
||||
### 现象
|
||||
|
||||
后端解析IP后全量变成 `127.0.0.1`。
|
||||
|
||||
### 原因
|
||||
|
||||
后端解析IP的顺序是
|
||||
```
|
||||
X-Forwarded-For → X-Real-IP → RemoteAddr
|
||||
```
|
||||
|
||||
**Nginx**转发至后端服务的 location 块缺少`proxy_set_header`指令:
|
||||
|
||||
```nginx
|
||||
location /olive3 {
|
||||
|
||||
proxy_pass http://127.0.0.1:55430;
|
||||
|
||||
proxy_connect_timeout 300s;
|
||||
|
||||
proxy_send_timeout 300s;
|
||||
|
||||
proxy_read_timeout 300s;
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
### 修复
|
||||
|
||||
在缺失的 location 块中补充 header 透传:
|
||||
|
||||
```nginx
|
||||
location /api {
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_pass http://127.0.0.1:55430;
|
||||
# ... 其他配置不变
|
||||
}
|
||||
```
|
||||
|
||||
- `$proxy_add_x_forwarded_for`:将客户端真实 IP 追加到已有 `X-Forwarded-For` 尾部,而非覆盖
|
||||
- `$remote_addr`:Nginx 直接看到的对端地址,作为 `X-Real-IP` 传递
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
Go 1.24 起,`map` 的底层实现从传统的 `hmap` + `bmap` 哈希表,彻底切换到了 Swiss Table(瑞士表)
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
### Group内存布局图
|
||||
|
||||
你可以直接复制以下文本块到你的 Markdown 笔记中(使用 text 包裹):
|
||||
|
||||
codeText
|
||||
|
||||
|
||||
|
||||
```
|
||||
+-------------------------------------------------------------------------------+
|
||||
| 单 Group 内存布局 |
|
||||
+--------------------------+----------------------------+-----------------------+
|
||||
| 1. Metadata 控制字节区 | 2. 连续 Key 存储区 | 3. 连续 Value 存储区 |
|
||||
+--------------------------+----------------------------+-----------------------+
|
||||
| [M0][M1][M2]...[M7] | [K0][K1][K2]...[K7] | [V0][V1][V2]...[V7] |
|
||||
+--------------------------+----------------------------+-----------------------+
|
||||
| <- 固定 8 个字节 -> | <- 长度取决于 Key 类型 -> | <- 长度取决于 Val -> |
|
||||
| <- 一次性载入寄存器对比 -> | |
|
||||
```
|
||||
|
||||
**为什么这样设计?(设计优势):**
|
||||
|
||||
1.
|
||||
2. **避免内存对齐填充(Padding)**:如果采用 [Meta][Key][Value] 交叉排列,由于不同类型的 Key/Value 字节大小不同,为了对齐,Go 必须在它们之间插入大量空白填充字节,浪费空间。分块连续存储消除了组内的对齐损耗。
|
||||
3. **对 CPU 缓存友好**:8 字节的 Metadata 紧密相连,一次 Cache Line 填充就能把整组的控制信息全部读入,极大地提高了缓存命中率。
|
||||
|
||||
------
|
||||
|
||||
|
||||
|
||||
### 读取流程
|
||||
|
||||
以下为您整理的完整、正确的读取逻辑,您可以直接复制使用:
|
||||
|
||||
#### 1.哈希计算与分段 (Hash Splitting)
|
||||
|
||||
- 将 Key 传入哈希函数,计算出一个 **64 位的哈希值**。
|
||||
- 该哈希值被拆分为两部分:**H1(高 57 位)**:用于定位哈希表中的初始 Group 索引。**H2(低 7 位)**:作为特征值(指纹),存储在 Group 的 Metadata 中,用于快速匹配。
|
||||
|
||||
#### 2.定位初始 Group (Locate Group)
|
||||
|
||||
- 计算初始 Group 索引:group_index = H1 & (Group数量 - 1)。
|
||||
|
||||
> 可以理解与$2^B$进行取模运算,但是**位与运算**效率更高且等价。
|
||||
|
||||
#### 3.组内快速匹配 (Group-level SWAR Match)
|
||||
|
||||
- **一次性加载**:将目标 Group 的 8 字节 Metadata 一次性载入一个 64 位寄存器中。
|
||||
- **并行对比(SWAR 技术)**:利用位运算,将 7 位的 H2 同时与这 8 个 Metadata 字节进行并行对比,输出一个 8 位的位掩码(Bitmask)。位掩码中为 1 的位,代表该位置的 H2 与目标 H2 匹配成功。这一步极快,完全避免了循环遍历。
|
||||
|
||||
#### 4.冲突解决与探测循环 (Verification & Probing Loop)
|
||||
|
||||
根据位掩码的匹配结果,执行以下逻辑:
|
||||
|
||||
1. 依次根据匹配成功的索引,去 **Key 存储区** 找到对应的真实 Key。
|
||||
2. 进行完整的 Key 等值对比(如 if key == targetKey):**若匹配成功**:直接去 **Value 存储区** 对应偏移量取出 Value 并返回。**若匹配失败**:说明发生了 **H2 哈希冲突**(即不同的 Key 产生了相同的 H2),继续对比下一个匹配的槽位。
|
||||
3. 如果当前 Group 中所有匹配了 H2 的槽位都对比完了,仍未找到匹配的 Key,则**跳转至【情况 B】**。
|
||||
|
||||
此时需要检查当前 Group 的 Metadata 状态,决定是继续向后寻找还是停止:
|
||||
|
||||
- **若当前 Group 中存在“空位”(Empty,0xFF)**:
|
||||
|
||||
说明探测链在此处断开,该 Key 在 Map 中**一定不存在**,直接返回 nil 或零值。
|
||||
|
||||
- **若当前 Group 中无空位,但存在“墓碑”(Tombstone,0x80)或已满**:
|
||||
|
||||
虽然当前 Group 没找到,但可能因为历史删除操作(留下了墓碑)或哈希冲突,导致数据被存到了后续的 Group。不能停止!使用**二次探测算法(Quadratic Probing)**计算下一个 Group 的索引,跳转回 **【3.组内快速匹配】** 继续循环寻找。
|
||||
@@ -0,0 +1,17 @@
|
||||
## 命名规则
|
||||
|
||||
> [《布尔变量起名的艺术》](https://thatamazingprogrammer.com/posts/stop-naming-your-variables-flag-the-art-of-boolean-prefixes/)
|
||||
|
||||
### 使用正确的前缀
|
||||
|
||||
(1)**is**:描述事物的状态,后面跟形容词,比如 isActive,isDeleted,isEmpty。
|
||||
|
||||
(2)**has**:描述事物的所有权或包含关系,后面跟名词,比如 hasAccess,hasChildren,hasValidationErrors。
|
||||
|
||||
(3)**can**:描述事物的能力或权限,比如 canEdit,canDelete,canRetry。
|
||||
|
||||
(4)**should**:描述事物的意图或逻辑,比如 shouldRetry,shouldCacheResponse。
|
||||
|
||||
### 其他
|
||||
|
||||
永远不在布尔变量名中使用否定词,比如isDisabled,因为当使用在if语句中会让大脑进行双重否定运算
|
||||
Reference in New Issue
Block a user