Etcd lease leak
jschwinger233 opened this issue · 4 comments
jschwinger233 commented
Lines 15 to 22 in 77be215
这个函数可能会造成锁泄露.
通过 etcd lock 的源码可以知道, 在 store.CreateLock()
成功之后, 就已经创建了 lease 并且有 goroutine 不断 keepalive lease:
func NewSession(client *v3.Client, opts ...SessionOption) (*Session, error) {
ops := &sessionOptions{ttl: defaultSessionTTL, ctx: client.Ctx()}
for _, opt := range opts {
opt(ops)
}
id := ops.leaseID
if id == v3.NoLease {
resp, err := client.Grant(ops.ctx, int64(ops.ttl))
if err != nil {
return nil, err
}
id = resp.ID
}
ctx, cancel := context.WithCancel(ops.ctx)
keepAlive, err := client.KeepAlive(ctx, id)
if err != nil || keepAlive == nil {
cancel()
return nil, err
}
donec := make(chan struct{})
s := &Session{client: client, opts: ops, id: id, cancel: cancel, donec: donec}
// keep the lease alive until client error or cancelled context
go func() {
defer close(donec)
for range keepAlive {
// eat messages until keep alive channel closes
}
}()
return s, nil
所以在 doLock
函数里, 假如 CreateLock()
成功而 lock.Lock()
失败, 已经创建的 lease, keepalive goroutine 都没有被销毁, 而 return 出去之后的上层也没有做处理(也不应该让上层处理, 毕竟 return err), 从而造成 lease + goroutine 泄露.
jschwinger233 commented
等下, 有地方有问题, 我改改
tonicmuroq commented
我倒是觉得这个问题在于 lock 被 keepalive 这点上 = =
似乎也没有什么方法控制这个, 记得有个 Orphan
好像避免创建之后的 keepalive goroutine
jschwinger233 commented
擦 这个如果改掉似乎不会就出现锁泄露了, 因为 revoke lease 会删除 attached keys, 而且我测了一下居然没有 race
jschwinger233 commented
绕来绕去没想到答案早就在手上了...伤心