特性 聚合 (Aggregation) 组合 (Composition)
菱形 空心 ◇ 实心 ◆
强度 弱拥有 强拥有
生命周期 部分独立 部分与整体同生共死
共享性 部分可被多个整体共享 部分仅属于一个整体
典型例子 班级 - 学生、汽车 - 轮胎 人 - 心脏、订单 - 订单项、房子 - 房间

pk代表主键 fk代表外键

map 必须初始化才能用,零值是 nil,直接赋值会 panic

var m map[string]int // nil map
m[“a”] = 1 // panic: assignment to nil map

m := make(map[string]int)
m[“a”] = 1 // 正常

判断 key 是否存在,不能直接用值

_, ok := m[“a”]
if ok {
// 存在
} else {
// 不存在
}

1
2
3
v := m["key"]
if v == 0 { // 错!key 不存在 或 值真的是 0,分不清
}

不能取 map 元素的地址

p := &m[“key”] // 编译错误!

delete () 是安全操作,删不存在的 key 不会报错

delete(m, “not-exist-key”) // 啥事没有,不 panic

map 作为函数参数是传引用(本质是指针包装)

nil map 可以读、可以遍历、可以 delete,但不能写

var m map[string]int
v, ok := m[“a”] // 可以
delete(m, “a”) // 可以
for range m {} // 可以
m[“a”] = 1 // panic

map 中的 map 必须初始化才能用[可以嵌套 map,但内层必须初始化]

m := make(map[string]map[string]int)
m[“outer”] = make(map[string]int) // 必须初始化内层
m[“outer”][“inner”] = 1

cap () 看最大容量,map 不能用

go Map

hmap + 桶数组(bmap)+ 溢出链表
C++ std::map:红黑树,有序,O (log n)
C++ unordered_map:哈希表,无序,类似 Go map

溢出桶

溢出桶是临时方案,不能无限链下去。
map 扩容触发条件(满足其一):
负载因子 ≥ 6.5(元素数 / 桶数)
溢出桶总数 ≥ 桶总数 / 16(链太长)
扩容时:
桶数翻倍(B+1)
所有 KV 重新哈希到新桶
溢出链全部打散,缩短查找路径。

固定窗口的致命问题:边界突刺

假设:1 秒最多允许 5 个请求
第 0.9 秒 来了 5 个
第 1.1 秒 又来了 5 个
这 0.2 秒内,瞬间进来 10 个请求

分布式认证与集中式认证

  1. 集中式认证(Session 模式)
    原理:用户登录后,服务端生成 Session ID,把用户数据存服务端内存 / Redis,只把 SessionId 下发给客户端。
    特征:
    状态存储在服务端
    多服务 / 集群时,必须做 Session 共享(Redis 统一存储),否则登录态失效
    认证校验:每次请求服务端都要查存储拿到用户信息
    归类:集中式认证
  2. JWT(JSON Web Token)
    原理:登录后,把用户身份、权限、基本信息加密编码进 Token 字符串,全部下发给客户端保存。
    特征:
    服务端不存储任何会话状态(无状态)
    校验逻辑:服务端只做签名验签,解码就能拿到用户信息,不用查第三方存储
    多节点、分布式集群、跨服务、跨域名天然支持,无需共享会话
    归类:分布式 / 无状态认证