2

内存缓存-设计

 2 years ago
source link: https://forrestsu.github.io/posts/architecture/cache/memory-cache-design/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

内存缓存-设计

2021年12月8日
| 字数 1226

在业务开发场景中,主要用到两个开发能力:接口粘合+缓存

一个好的缓存设计,能够降低服务的时延,抵抗流量洪峰。 比如最近的西安健康码事件,明显缓存设计上是存在明显问题的 :-)。

2 什么场景需要加缓存?

  • 提高服务质量,降低时延;
  • 减少对下游的请求量,节省资源

3 缓存常见问题

缓存问题 解决办法 (1) 缓存失效的策略 惰性过期(读取时判断如果过期了,就返回且异步更新) (2) 缓存集中失效 设置随机过期时间 (3) 缓存击穿(大量穿透导致雪崩) singleflight 合并多个相同的请求

3.1 50行代码,实现一个可用的 singleflight?

groupCache 库实现了一个可用的 singleflight,借助于 sync.WaitGroupsync.Mutex, 代码非常简洁。

// call is an in-flight or completed Do call
type call struct {
	wg  sync.WaitGroup
	val interface{}
	err error
}

// Group represents a class of work and forms a namespace in which
// units of work can be executed with duplicate suppression.
type Group struct {
	mu sync.Mutex       // protects m
	m  map[string]*call // lazily initialized
}

// Do executes and returns the results of the given function, making
// sure that only one execution is in-flight for a given key at a
// time. If a duplicate comes in, the duplicate caller waits for the
// original to complete and receives the same results.
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.mu.Unlock()
	// execute fn
	c.val, c.err = fn()
	c.wg.Done()
	// remove key
	g.mu.Lock()
	delete(g.m, key)
	g.mu.Unlock()
	return c.val, c.err
}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK