Polaris系列-03.启动分析二

开始之前补充一个点:main包下引入了一堆其它模块的包,
这些包下有初始化函数init()
在这里插入图片描述
举两个例子:
一.第22行:

_ "github.com/polarismesh/polaris/apiserver/grpcserver/config"

点进去后发现:
// init 自注册到API服务器插槽
func init() {
	_ = apiserver.Register("config-grpc", &ConfigGRPCServer{})
}

// Register 注册API服务器
func Register(name string, server Apiserver) error {
	//全局变量:var Slots = make(map[string]Apiserver)
	if _, exist := Slots[name]; exist {
		return fmt.Errorf("apiserver name:%s exist", name)
	}
	Slots[name] = server
	return nil
}

在这里插入图片描述
二.第50行:

_ "github.com/polarismesh/polaris/store/boltdb"

点进去,找到init(), 再点进去可看到本函数:

// RegisterStore 注册一个新的Store
func RegisterStore(s Store) error {
	name := s.Name()
	// 全局变量 var StoreSlots = make(map[string]Store)
	if _, ok := StoreSlots[name]; ok {
		return errors.New("store name already existed")
	}
	StoreSlots[name] = s
	return nil
}

在这里插入图片描述
在这里插入图片描述
这里需要留意上图第43行代码:name := s.Name(), 查看此接口实现:
在这里插入图片描述
在这里插入图片描述
这意味着我们不能随便写配置项!!!因为上面一堆init()初始化函数已经定死了大部分配置项的名称,当然也有部分配置项允许我们自己编写,去覆盖默认选项,后面再说。

林林总总,都是这种套路,补充完毕,开始进入本篇的启动分析第二部分。

初始化存储层: 把存储相关配置保存到全局变量中

store.SetStoreConfig(&cfg.Store)
里面就一行代码:config = conf

这里再一次贴出截图,后续此类就不再赘述了。
在这里插入图片描述
同时再次提醒一次,请留意层次结构,保存这种配置的类在store包下的store.go中,这是因为。。。看下图👇:store这一类配置可能有不同的存储实现,比如boltdb/mysql/…其它甚至mock。。。。所以把配置放在统管全局的store包下的store.go类中,具体store下面的boltdb/mock/mysql等子包 是具体不同的实现。
在这里插入图片描述
后续很多类似代码组织风格,不再赘述。
在这里插入图片描述
进入s, err = store.GetStore()看看:
在这里插入图片描述
看看上图第64行实现:initialize(store),它是本篇核心内容:

// initialize  包裹了初始化函数,在GetStore的时候会在自动调用,全局初始化一次
func initialize(s Store) {
	once.Do(func() {
		fmt.Printf("[Store][Info] current use store plugin : %s\n", s.Name())
		// 看这里👉 进入此函数查看:
		if err := s.Initialize(config); err != nil {
			fmt.Printf("[ERROR] initialize store `%s` fail: %v", s.Name(), err)
			os.Exit(1)
		}
	})
}

因为我们使用的是boltdb,所以进入下面实现类:
先放一张总代码图:
在这里插入图片描述
先根据配置初始化boltConfig对象:
在这里插入图片描述

存储boltdb文件位置:
// BoltConfig config to initialize boltdb
type BoltConfig struct {
	// FileName boltdb store file
	FileName string
}

进入boltConfig.Parse(c.Option):
核心代码就一行:把option配置值赋值给 c.FileName = value.(string)

重点在第110行:handler, err := NewBoltHandler(boltConfig),进入看看:

// NewBoltHandler create the boltdb handler
func NewBoltHandler(config *BoltConfig) (BoltHandler, error) {
	db, _ := openBoltDB(config.FileName)
	// 好多模块都引用了它!
	return &boltHandler{db: db}, nil
}
// 这个对象封装了对boltdb的操作
type boltHandler struct {
	db *bolt.DB
}

至此,底层boltdb操作对象数据模型已经准备好,那么有哪些模块用到它呢?
我们看一下boltStore数据模型:

type boltStore struct {
	*namespaceStore
	*clientStore

	// 服务注册发现、治理
	*serviceStore
	*instanceStore
	*l5Store
	*routingStore
	*rateLimitStore
	*circuitBreakerStore
	*faultDetectStore
	*routingStoreV2
	*serviceContractStore
	*laneStore

	// 配置中心stores
	*configFileGroupStore
	*configFileStore
	*configFileReleaseStore
	*configFileReleaseHistoryStore
	*configFileTemplateStore

	// adminStore store
	*adminStore
	// 工具
	*toolStore
	// 鉴权模块相关
	*userStore
	*groupStore
	*strategyStore
	*grayStore

	handler BoltHandler
}

模块很多,但是幸运的是,除了 adminStore 和 toolStore稍微有点特殊之外,其它所有的数据模型都是下面这样的:只有一个handler引用,而且引用的对象正是上面介绍的boltHandler对象

type namespaceStore struct {
	handler BoltHandler
}

type clientStore struct {
	handler BoltHandler
}
。。。
type grayStore struct {
	handler BoltHandler
}

而且toolStore模块更绝,整个类内容只有这点:
在这里插入图片描述
它们底层共用一个BoltHandler, 通过typ区分业务数据分类,再通过key区分一个分类在下不同业务。

接下来的代码正是围绕这些模块去做初始化操作的,下面一个一个来说:

进入115行的m.newStore()里面:
在这里插入图片描述
代码风格分三类:

  1. 初始化模块,然后初始化数据(下图中的红框 部分)
  2. 只有初始化模块,没有初始化数据(下图中的蓝框 部分)
  3. 独立的初始化方法(下图中的 绿框部分)
    在这里插入图片描述

因为是首次看到类似代码,我们分析得细点,我们进去看看 红框的 初始化数据方法:
一、l5.go 数据初始化:
在这里插入图片描述
通用Execute方法:
在这里插入图片描述
l5模块数据初始化:

const (
	tblNameL5      = "l5"
	rowSidKey      = "sidSequence"
	colModuleId    = "module_id"
	colInterfaceId = "interface_id"
	colRangeNum    = "range_num"
)

func updateL5SidTable(rowBucket *bolt.Bucket, mid uint64, iid uint64, rnum uint64) error {
	var err error
	if err = rowBucket.Put([]byte(colModuleId), encodeUintBuffer(mid, typeUint32)); err != nil {
		return err
	}
	if err = rowBucket.Put([]byte(colInterfaceId), encodeUintBuffer(iid, typeUint32)); err != nil {
		return err
	}
	if err = rowBucket.Put([]byte(colRangeNum), encodeUintBuffer(rnum, typeUint32)); err != nil {
		return err
	}
	return nil
}

二、namespace数据初始化:
FYI: 省略了err判断代码

const (
	defaultNamespace = "default"
	polarisNamespace = "Polaris"
)

// InitData initialize the namespace data
func (n *namespaceStore) InitData() error {
	namespaces := []string{defaultNamespace, polarisNamespace}
	for _, namespace := range namespaces {
		ns, _ := n.GetNamespace(namespace)
		
		if ns == nil {
			// 我们进去看看这个实现内容:
			err = n.AddNamespace(&model.Namespace{
				Name:       namespace,
				Comment:    namespaceToComment[namespace],
				Token:      namespaceToToken[namespace],
				Owner:      "polaris",
				Valid:      true,
				CreateTime: time.Now(),
				ModifyTime: time.Now(),
			})
		}
	}
	return nil
}

// AddNamespace add a namespace
func (n *namespaceStore) AddNamespace(namespace *model.Namespace) error {
	// 先删除无效数据,再添加新数据
	if err := n.cleanNamespace(namespace.Name); err != nil {
		return err
	}

	tn := time.Now()

	namespace.CreateTime = tn
	namespace.ModifyTime = tn
	namespace.Valid = true
	// 最后再看看这里面的实现:
	return n.handler.SaveValue(tblNameNamespace, namespace.Name, n.toStore(namespace))
}

// SaveValue insert data object, each data object should be identified by unique key
func (b *boltHandler) SaveValue(typ string, key string, value interface{}) error {
	return b.db.Update(func(tx *bolt.Tx) error {
		return saveValue(tx, typ, key, value)
	})
}

看上述代码后知道了为什么我们登录Polaris控制台时,能看到默认有2个命名空间:default + Polaris 了吧?!
另外:初始化数据的最后,都回归到 boltHandler下的db操作,只不过不同模块初始化的数据不同。

第2类初始化跳过。。。

继续说第3类初始化:

m.newDiscoverModuleStore()
m.newAuthModuleStore()
m.newConfigModuleStore()
m.newMaintainModuleStore()

原来全是这样的初始化,那也先不用看:
在这里插入图片描述
总结:这么多模块初始化工作:都持有m.handler( BoltHandler类型)引用,然后根据模块本身的类型值 去做区分,对应不同的boltdb数据。
m.newStore(); 方法介绍完毕,下面代码如下所示:

在这里插入图片描述
上图中的if… else 会走哪一分支呢?再复习下咱们的yaml配置内容:
在这里插入图片描述
咱们只配置了path项,没有loadFile,所以走else. 如果想自定义加载配置option,可以看看代码,或者参照默认加载的配置内容 去配置,加载逻辑是相通的。另外,想必能看到这里的朋友也有点累了,咱们也看简单的默认分支代码部分:
进入第125行的m.loadByDefault()

func (m *boltStore) loadByDefault() error {
	// 1.初始化授权存储数据
	if err := m.initAuthStoreData(); err != nil {
		_ = m.handler.Close()
		return err
	}
	// 2.初始化命名存储数据
	if err := m.initNamingStoreData(); err != nil {
		_ = m.handler.Close()
		return err
	}
	return nil
}

其中的saveValue(...)也是boltdb底层bucket那些操作:
在这里插入图片描述
初始化两个namespace: default + Polaris, 以及一个服务:polaris.checker
在这里插入图片描述
在这里插入图片描述
FYI: 方法名是AddNamespaceAddService, 其实都是先删除再新增 操作。

至此,我们分析了整个 store.GetStore(),代码进入下面:
在这里插入图片描述
本篇总结:

  1. 根据polaris-server.yaml中store相关配置初始化boltHandler
  2. 初始化一堆模块的初始化: 持有1中的boltHandler引用
  3. 初始化授权存储相关配置:主体账户+鉴权策略
  4. 初始化命名空间+检查服务
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值