接上,先贴出方法代码:
进入cacheMgn.OpenResourceCache(...)
方法, 注意入参:传递是gray, 正是上篇缓存管理的配置项的最后一个,着重强调是因为下面这个方法是通用的,通过传递不同的入参来区别模块:即开启不同的资源缓存
:
// OpenResourceCache 开启资源缓存
func (nc *CacheManager) OpenResourceCache(entries ...types.ConfigEntry) error {
for _, obj := range nc.caches {
var entryItem *types.ConfigEntry
for _, entry := range entries {
// 每个配置项有不同的Name()实现
if obj.Name() == entry.Name {
entryItem = &entry
break
}
}
if entryItem == nil {
continue
}
if err := obj.Initialize(entryItem.Option); err != nil {
return err
}
// 保存加载成功的配置项
nc.needLoad.Add(entryItem.Name)
}
return nil
}
再次回顾下:
// CacheManager 名字服务缓存
type CacheManager struct {
storage store.Store
caches []types.Cache
// 一个线程安全set集合
needLoad *utils.SyncSet[string]
}
上个方法做的事是:
从缓存管理器管理的(16个)配置项中遍历查找出名称为 指定入参的配置项,
如果找到了,那么就去初始化这个配置项模块,对于当前调用,正是找到 gray配置项(灰度发布),然后去初始化它:
等等???
上一篇不是已经初始化缓存配置项了嘛?怎么又要初始化?
我们进去看看:
对缓存的灰度发布来说,这次的初始化只是初始化了2个属性…
那么上一篇中 灰度发布初始化是做了什么呢?上篇中似乎只是一笔带过…
回顾下:
// NewGrayCache create gray cache obj
func NewGrayCache(storage store.Store, cacheMgr types.CacheManager) types.GrayCache {
return &grayCache{
BaseCache: types.NewBaseCache(storage, cacheMgr),
storage: storage,
}
}
type grayCache struct {
*types.BaseCache
storage store.Store
grayResources *utils.SyncMap[string, []*apimodel.ClientLabel]
updater *singleflight.Group
}
grayCache
结构体就上述4个属性,上一篇初始化了前两个,本篇又初始化了后两个。至此cacheMgn.OpenResourceCache
开启灰度规则缓存 方法介绍完毕,往下:
把错误判断处理省略掉了:
// Initialize 初始化
func Initialize(ctx context.Context, authOpt *Config, storage store.Store, cacheMgn *cache.CacheManager) error {
once.Do(func() {
userMgn, strategyMgn, err = initialize(ctx, authOpt, storage, cacheMgn)
})
return nil
}
进入initialize(...)
:
先看看我们的配置文件关于auth的部分:
如果我们没有配置auth,SetDefault()
会给我们设置默认值:
再次证明了配置项名称不能乱写,是init()早就定好的:
接下来是 用户数据管理 + 策略管理 的初始化:
先看前者:
依据配置初始化了userServer + AuthConfig并校验了密码长度,
开启了用户的资源缓存
type Server struct {
authOpt *AuthConfig
storage store.Store
history plugin.History
cacheMgr cachetypes.CacheManager
helper auth.UserHelper
}
密码长度有要求限制:
缓存用户资源初始化如下:
至此,userCache的属性几乎全部初始化完毕。
再看插件配置:
GetHistory()
:
进去:
History插件执行完毕后,保存值到 userServer的history字段中,至此用户初始化完毕。
再看第174行的 policyMgr.Initialize(authOpt, storage, cacheMgr, userMgr)
:
// Initialize 执行初始化动作
func (svr *Server) Initialize(options *auth.Config, storage store.Store, cacheMgr cachetypes.CacheManager, userSvr auth.UserServer) error {
svr.userSvr = userSvr
return svr.nextSvr.Initialize(options, storage, cacheMgr, userSvr)
}
进入上图中的第96行:初始化几个字段:
// Initialize 执行初始化动作
func (d *DefaultAuthChecker) Initialize(conf *AuthConfig, s store.Store,
cacheMgr cachetypes.CacheManager, userSvr auth.UserServer) error {
d.conf = conf
d.cacheMgr = cacheMgr
d.userSvr = userSvr
return nil
}
初始化命名空间模块和上面2个逻辑一样:不再赘述。
再看第194行StartDiscoverComponents(ctx, cfg, s, cacheMgn);
里面看起来一大片代码,分步说明:
1.取配置文件内容,保存到数据模型,
// Controller 批量控制器
type Controller struct {
register *InstanceCtrl
deregister *InstanceCtrl
heartbeat *InstanceCtrl
clientRegister *ClientCtrl
clientDeregister *ClientCtrl
}
贴出部分配置,心跳部分:
组织好批量控制器(bc)后,我们去看看如何启动:
bc的前3个属性类型为InstanceCtrl,后两个为ClientCtrl
,但是它们的Start(ctx)
实现风格是一致的,我们只拿第一个分析:
// Start 开始启动批量操作实例的相关协程
func (ctrl *InstanceCtrl) Start(ctx context.Context) {
log.Infof("[Batch] Start batch instance, config: %+v", ctrl.config)
// 初始化并且启动多个store协程,并发对数据库写
for i := 0; i < ctrl.config.Concurrency; i++ {
ctrl.storeThreadCh = append(ctrl.storeThreadCh, make(chan []*InstanceFuture))
}
for i := 0; i < ctrl.config.Concurrency; i++ {
go ctrl.storeWorker(ctx, i)
}
// 进入主循环
ctrl.mainLoop(ctx)
}
协程果然是轻量级的,128个,你要是起128个线程试试 )_(~
我们进入上图第140行代码:ctrl.storeWorker(ctx, i)
先跳过上图的第245行 处理逻辑,看看下面代码实现:
所以storeWorker
写协程事先待命,等着ctrl.mainLoop(ctx)
往里面塞数据:生产消费模型,作者方法说明旁白说:mainLoop 注册主协程 从注册队列中获取注册请求,即对应上图的第218行。至于什么时候,谁 往此queue(chan *InstanceFuture
)中写数据,后面有机会再分析,先了解全貌。
再回过头来看看storeWorker
写协程如何写库:
我们回到初始化的地方看看这个函数是哪个:
里面代码汇总如下:
1.遍历InstanceFuture列表,收集成一个map:
2.统一判断实例是否存在,存在则需要更新部分数据
3.构造model列表数据
4.调用batch接口,创建实例
5.响应
至此,bc.Start()
介绍完毕,继续往下:
接下来是健康检查初始化:把它留到下篇吧…
本篇总结:
- 开启灰度规则缓存
- 初始化鉴权层
- 初始化命名空间模块
- 一部分 初始化服务发现模块相关功能…