-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
73 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,19 @@ | ||
## 分布式缓存 | ||
|
||
#### 对于给定的 key,每次都选择同一个节点 | ||
#### 一致性哈希 | ||
|
||
对于给定的 key,每次都选择同一个节点 | ||
|
||
节点固定时: | ||
|
||
把 key 的每一个字符的 ASCII 码加起来,除以 10 取余数 | ||
|
||
hash('Tom') % 10 | ||
hash('Tom') % 10 | ||
|
||
#### 防止缓存击穿 | ||
|
||
**缓存雪崩**:缓存在同一时刻全部失效,造成瞬时DB请求量大、压力骤增,引起雪崩。缓存雪崩通常因为缓存服务器宕机、缓存的 key 设置了相同的过期时间等引起。 | ||
|
||
**缓存击穿**:一个存在的key,在缓存过期的一刻,同时有大量的请求,这些请求都会击穿到 DB ,造成瞬时DB请求量大、压力骤增。 | ||
|
||
**缓存穿透**:查询一个不存在的数据,因为不存在则不会写到缓存中,所以每次都会去请求 DB,如果瞬间流量过大,穿透到 DB,导致宕机。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package singleflight | ||
|
||
import "sync" | ||
|
||
// 正在进行中,或已经结束的请求 | ||
type call struct { | ||
wg sync.WaitGroup | ||
val interface{} | ||
err error | ||
} | ||
|
||
// 管理不同 key 的请求(call) | ||
type Group struct { | ||
mu sync.Mutex // 保护 m 不被并发读写 | ||
m map[string]*call | ||
} | ||
|
||
func (g *Group) Do(key string, fn func() (interface{}, error)) (interface{}, error) { | ||
g.mu.Lock() | ||
if g.m == nil { | ||
g.m = make(map[string]*call) | ||
} | ||
if c, ok := g.m[key]; ok { | ||
g.mu.Unlock() | ||
c.wg.Wait() // 如果请求正在进行中,则等待 | ||
return c.val, c.err // 请求结束,返回结果 | ||
} | ||
c := new(call) | ||
c.wg.Add(1) // 发起请求前加锁 | ||
g.m[key] = c // 添加到 g.m,表明 key 已经有对应的请求在处理 | ||
g.mu.Unlock() | ||
|
||
c.val, c.err = fn() // 调用 fn,发起请求 | ||
c.wg.Done() // 请求结束 | ||
|
||
g.mu.Lock() | ||
delete(g.m, key) // 更新 g.m | ||
g.mu.Unlock() | ||
|
||
return c.val, c.err // 返回结果 | ||
} |