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
原创粉丝点击