nsq源码阅读 nsqlookupd源码二 registration_db.go
来源:互联网 发布:苹果蜂窝数据打不开 编辑:程序博客网 时间:2024/06/05 17:03
package nsqlookupdimport ("fmt""sync""sync/atomic""time")//定义类型RegistrationDB,字面意思:注册数据库,保存nsqd的注册信息//按照官网的quick start操作,查看终端输出,可发现nsqd每15秒通过4160端口向nsqlookupd发送心跳包//简单跟踪nsqlookupd/nsqlookupd.go中的protocol.TCPServer(tcpListener, tcpServer, l.opts.Logger),//可发现RegistrationDB保存nsqd的注册信息type RegistrationDB struct {sync.RWMutexregistrationMap map[Registration]Producers}//nsqd首次注册时,Category:client Key: SubKey://当nsqd有topic时,Category:topic Key:test SubKey: Key为topic名称type Registration struct {Category stringKey stringSubKey string}type Registrations []Registration//通过curl 'http://127.0.0.1:4161/lookup?topic=topic_name'命令查看对应topic的信息type PeerInfo struct {lastUpdate int64id stringRemoteAddress string `json:"remote_address"`Hostname string `json:"hostname"`BroadcastAddress string `json:"broadcast_address"`TCPPort int `json:"tcp_port"`HTTPPort int `json:"http_port"`Version string `json:"version"`}//对于nsqlookupd来说,它的producer就是nsqdtype Producer struct {peerInfo *PeerInfo//是否删除,关于tombstones官网有介绍http://nsq.io/components/nsqlookupd.html#deletion_tombstones//英语不行,看不懂,网上查了一下,有翻译成逻辑删除的意思,目前还没搞懂这块//大体知道是和删除nsqd有关tombstoned bool//删除时间tombstonedAt time.Time}//定义类型Producers为Producer的slicetype Producers []*Producerfunc (p *Producer) String() string {return fmt.Sprintf("%s [%d, %d]", p.peerInfo.BroadcastAddress, p.peerInfo.TCPPort, p.peerInfo.HTTPPort)}//将Producer标记为tombstone,并记录标记的时间func (p *Producer) Tombstone() {p.tombstoned = truep.tombstonedAt = time.Now()}//判断Producer是否为tombstone状态func (p *Producer) IsTombstoned(lifetime time.Duration) bool {//func (t Time) Sub(u Time) Duration 计算两个时间的差(time.Now() - p.tombstonedAt)return p.tombstoned && time.Now().Sub(p.tombstonedAt) < lifetime}//新建RegistrationDB类型变量func NewRegistrationDB() *RegistrationDB {return &RegistrationDB{//make一个mapregistrationMap: make(map[Registration]Producers),}}// add a registration key//添加一个registration的key,只设置了map的key,value是一个空的Producers slicefunc (r *RegistrationDB) AddRegistration(k Registration) {//写锁r.Lock()defer r.Unlock()_, ok := r.registrationMap[k]if !ok {r.registrationMap[k] = Producers{}}}// add a producer to a registration//添加producer到指定的registration里func (r *RegistrationDB) AddProducer(k Registration, p *Producer) bool {r.Lock()defer r.Unlock()producers := r.registrationMap[k]//遍历producers,看这个producer是否已存在found := falsefor _, producer := range producers {//根据producer.peerInfo.id判断,是否已存在if producer.peerInfo.id == p.peerInfo.id {found = true}}//producer不存在时,添加到RegistrationDB里if found == false {r.registrationMap[k] = append(producers, p)}//返回添加成功或失败(true或false)return !found}// remove a producer from a registration//从registration里删除一个指定的producer//入参:k registration中的key id producer.peerInfo.id//返回操作成功或失败和剩下的producer个数func (r *RegistrationDB) RemoveProducer(k Registration, id string) (bool, int) {r.Lock()defer r.Unlock()//判断registration中是否存在这个keyproducers, ok := r.registrationMap[k]if !ok {return false, 0}removed := false//删除一个producer的方法://新建一个空的Producers slice,把不需要删除的producer都添加到这个slice里,并重新赋值给RegistrationDBcleaned := Producers{}for _, producer := range producers {//id不相同,不是要删除的producer,添加到cleaned slice里if producer.peerInfo.id != id {cleaned = append(cleaned, producer)} else {removed = true}}// Note: this leaves keys in the DB even if they have empty lists//重新赋值给RegistrationDB,这样即使cleaned是个空的slice,RegistrationDB中的键值k依然会存在r.registrationMap[k] = cleaned//返回操作结果和cleaned slice长度return removed, len(cleaned)}// remove a Registration and all it's producers//删除Registration和对应的producersfunc (r *RegistrationDB) RemoveRegistration(k Registration) {r.Lock()defer r.Unlock()delete(r.registrationMap, k)}func (r *RegistrationDB) needFilter(key string, subkey string) bool {return key == "*" || subkey == "*"}//根据category key subkey查找registrations slicefunc (r *RegistrationDB) FindRegistrations(category string, key string, subkey string) Registrations {r.RLock()defer r.RUnlock()//返回指定的category key subkey对应的registration//如果key和subkey使用通配符*查找,则返回该条件下的所有数据if !r.needFilter(key, subkey) {k := Registration{category, key, subkey}if _, ok := r.registrationMap[k]; ok {//返回指定的Registrationsreturn Registrations{k}}return Registrations{}}results := Registrations{}for k := range r.registrationMap {//不符合,则跳过当前循环,继续下一个循环if !k.IsMatch(category, key, subkey) {continue}results = append(results, k)}//返回满足通配符条件的Registrationsreturn results}//根据category key subkey查找Producers slice,逻辑和上面的FindRegistrations差不多func (r *RegistrationDB) FindProducers(category string, key string, subkey string) Producers {r.RLock()defer r.RUnlock()if !r.needFilter(key, subkey) {k := Registration{category, key, subkey}return r.registrationMap[k]}results := Producers{}for k, producers := range r.registrationMap {if !k.IsMatch(category, key, subkey) {continue}for _, producer := range producers {found := falsefor _, p := range results {if producer.peerInfo.id == p.peerInfo.id {found = true}}if found == false {results = append(results, producer)}}}return results}//根据producer.peerInfo.id查找registrationfunc (r *RegistrationDB) LookupRegistrations(id string) Registrations {r.RLock()defer r.RUnlock()results := Registrations{}for k, producers := range r.registrationMap {for _, p := range producers {if p.peerInfo.id == id {results = append(results, k)break}}}return results}func (k Registration) IsMatch(category string, key string, subkey string) bool {if category != k.Category {return false}if key != "*" && k.Key != key {return false}if subkey != "*" && k.SubKey != subkey {return false}return true}//获取指定的registrationsfunc (rr Registrations) Filter(category string, key string, subkey string) Registrations {output := Registrations{}for _, k := range rr {if k.IsMatch(category, key, subkey) {output = append(output, k)}}return output}//获取registrations中的所有keyfunc (rr Registrations) Keys() []string {keys := make([]string, len(rr))for i, k := range rr {keys[i] = k.Key}return keys}//获取registrations中的所有SubKeyfunc (rr Registrations) SubKeys() []string {subkeys := make([]string, len(rr))for i, k := range rr {subkeys[i] = k.SubKey}return subkeys}//获取所有可用的producer,即nsqdfunc (pp Producers) FilterByActive(inactivityTimeout time.Duration, tombstoneLifetime time.Duration) Producers {now := time.Now()results := Producers{}for _, p := range pp {//根据nsqlookupd终端输出,并简单跟踪nsqlookupd/nsqlookupd.go中的protocol.TCPServer(tcpListener, tcpServer, l.opts.Logger),//在nsqlookupd/lookup_protocol_v1.go的LookupProtocolV1.PING()方法中发现atomic.StoreInt64(&client.peerInfo.lastUpdate, now.UnixNano())//可知producer.peerInfo.lastUpdate为producer与nsqlookupd最新交互时间cur := time.Unix(0, atomic.LoadInt64(&p.peerInfo.lastUpdate))//满足下面两个条件的producer将被忽略//1、超过了活跃时间,在inactivityTimeout时间内,没有与nsqlookupd交互//2、被标记为tombstone状态,在tombstoneLifetime时间内标记的producer被忽略if now.Sub(cur) > inactivityTimeout || p.IsTombstoned(tombstoneLifetime) {continue}results = append(results, p)}return results}//获取Producers中的所有peerInfofunc (pp Producers) PeerInfo() []*PeerInfo {results := []*PeerInfo{}for _, p := range pp {results = append(results, p.peerInfo)}return results}
registration_db.go文件用MAP以一对多的形式保存Producer,并提供一系列增、删、改、查的操作封装。同时使用RWMutex做并发控制。
一个topic对应多个Producer,即nsqd
0 0
- nsq源码阅读 nsqlookupd源码二 registration_db.go
- nsq源码阅读 nsqlookupd源码一 nsqlookupd.go
- nsq源码阅读 nsqlookupd源码三 tcp.go tcp_server.go
- nsq源码阅读 nsqlookupd源码五 http.go http_server.go
- nsq源码阅读 nsqlookupd源码四 lookup_protocol_v1.go
- go语言 nsq源码解读三 nsqlookupd源码nsqlookupd.go
- NSQ源码分析之nsqlookupd
- nsq源码阅读 nsqd源码二 nsqd/nsqd.go
- nsq源码阅读 nsqd源码一 apps/nsqd/nsqd.go
- nsq源码阅读 nsqd源码三 tcp.go
- nsq源码分析backend_queue.go
- nsq源码阅读笔记之nsqd(二)——Topic
- nsq源码导读(序)
- kubernetes源码之watch包mux.go阅读理解二
- Go net/PRC源码阅读client.go
- Go net/PRC源码阅读server.go
- Xwork2 源码阅读(二)
- live555源码阅读二
- Linux运维笔记-文档总结-系统恢复技术之Systemd初始化错误恢复技术
- parquet与avro嵌套列存结构比较
- centos7安装composer
- python-Pandas学习 如何对数据集随机抽样?
- 【LeetCode】palindrome-partitioning i&ii
- nsq源码阅读 nsqlookupd源码二 registration_db.go
- MKT LK
- springMVC 中几种获取request和response的方式
- 机器学习实战读书总结
- ReactNative Flux框架使用 进阶篇
- Mybatis返回主键id
- 编程常用函数
- Android坐标系 键盘的关闭和开启
- ZOJ-1577 求素因子个数 + gcd和lcm的性质?(或者你也可以暴力?)