Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add apiserver-lite proposal #4

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

Rachel-Shao
Copy link
Member

this is a proposal about edgeproxy.

@Rachel-Shao
Copy link
Member Author

@GsssC cc

@Rachel-Shao
Copy link
Member Author

@Peeknut @qclc cc

@GsssC
Copy link
Member

GsssC commented Dec 10, 2020

List请求和Watch请求的时间差

在k8s List Watch 机制中, List请求和Watch请求并不是同时发向api-server的, 两者之间存在一个时间差, 伪代码表示如下:

ListResp := client.Do(ListReq)
/---------------时间差开始------------------/
//主要关注返回list的最大rv(resource version)
//表示此rv前的数据我已经收到, 想我发送此rv之后的事件
WatchReq := BuildWatchReq(ListResp.MaxRv)
/---------------时间差结束------------------/
WatchResp := client.Do(WatchReq)

如果watch请求不带rv, 客户端将会遗漏时间差内的资源变更事件watch.Event, 因此watch请求都是带rv的.

因此, apiserver同时对于每一种类资源对象(以GroupVersionKind区分), 都会维护一份WatchCache, 缓存一定量的资源变更事件, 根据代码

    const(
    	// defaultLowerBoundCapacity is a default value for event cache capacity's lower bound.
    	// TODO: Figure out, to what value we can decreased it.
    	defaultLowerBoundCapacity = 100
    )
    func newWatchCache(
    	keyFunc func(runtime.Object) (string, error),
    	eventHandler func(*watchCacheEvent),
    	getAttrsFunc func(runtime.Object) (labels.Set, fields.Set, error),
    	versioner storage.Versioner,
    	indexers *cache.Indexers,
    	clock clock.Clock,
    	objectType reflect.Type) *watchCache {
    	wc := &watchCache{
    		capacity:            defaultLowerBoundCapacity,
    		keyFunc:             keyFunc,
    		getAttrsFunc:        getAttrsFunc,
    		cache:               make([]*watchCacheEvent, defaultLowerBoundCapacity),
    		lowerBoundCapacity:  defaultLowerBoundCapacity,
    		upperBoundCapacity:  defaultUpperBoundCapacity,
    		startIndex:          0,
    		endIndex:            0,
    		store:               cache.NewIndexer(storeElementKey, storeElementIndexers(indexers)),
    		resourceVersion:     0,
    		listResourceVersion: 0,
    		eventHandler:        eventHandler,
    		clock:               clock,
    		versioner:           versioner,
    		objectType:          objectType,
    	}
    	wc.cond = sync.NewCond(wc.RLocker())
    	return wc
    }

此WatchCache的容量是100, 假设Cache中对象的最小版本问MinRv, 最大版本为MaxRv, WatchReq.rv必须>=MinRv. 如果一个WatchReq.rv过于老旧(<MinRv), apiserver中没有缓存, 服务端会返回410 Gone错误, 客户端触发reListWatch.

apiserver-lite也会遇到同样的问题, 同时MetaManager没有实现资源的按版本缓存, 暂拟解决方案:

  • 构造缓存
    仿照apiserver同样实现一个缓存
    • 优点
    1. 针对边缘区域内节点数, 资源数较大情况, 有效解决边缘数据库更新频繁问题
  • 强制触发reListWatch
    假如时间差内边缘数据库中缓存了新的数据, 即检查发现WatchReq.rv小于当前数据库中某类资源的MaxRv, 向客户端返回错误, 强制触发reListWatch. 此种情况本质上是缓存容量为1的极值情况:
    • 优点
    1. relist apiserver-lite行为是一定程度上可接受的, 且即便触发也是一个小规模请求(规模小于等于节点上client 数)
    2. 少了一层缓存, 资源利用率低
    3. 代码实现简便
    • 缺点
    1. client watch失败会报错, 可能尝试多次reListWatch才正常工作

@GsssC GsssC changed the title add edgeproxy proposal add apiserver-lite proposal Dec 10, 2020
@smartding smartding force-pushed the master branch 4 times, most recently from 3c82643 to 7183a7e Compare August 24, 2021 06:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants