nsq源碼閱讀筆記之nsqd(一)——nsqd的配置解析和初始化
配置解析
nsqd的主函數位於apps/nsqd.go
中的main
函數
首先main
函數調用nsqFlagset
和Parse
進行命令行參數集初始化,
然後判斷version
參數是否存在,若存在,則打印版本號並退出程序
接下來鉤住系統的syscall.SIGINT
和syscall.SIGTERM
消息,用來阻塞主goroutine防止退出
隨後判斷config
參數是否存在,若存在的話還需進行配置文件的讀取,
nsq使用toml格式的配置文件,並通過github.com/BurntSushi/toml
庫進行配置文件的讀取和解析
如果配置文件存在並且符合toml格式,則調用cfg.Validate
對配置文件的各項進行進一步的合法性檢查。
主要是檢查配置文件中有關tls的選項(是否支持以及支持的版本)
配置文件檢查通過後,創建默認配置opts
,並於命令行參數和配置文件進行合並。
合並時用到了github.com/mreiferson/go-options
庫。
若出現沖突,則優先級從高到低排序依次是命令行、配置文件和默認配置
使用合並後的參數集初始化真正的nsqd對象
最後,nsqd對象進行初始化和檢查後,啟動nsqd包的主函數,程序從跳轉apps/nsqd.go
到nsqd/nsqd.go
初始化
nsqd真正開始運行前需要執行nsqd/nsqd.go
中的LoadMetadata
和PersistMetadata
兩個函數
LoadMetadata
初始化nsqd的LoadMetadata
函數使用atomic
包中的方法來保證方法執行前和執行後isLoading
元數據以json
格式保存在nsqd可執行文件目錄下的nsqd.%d.dat中。其中%d
為代表該程序的ID,
通過在啟動時的命令行worker-id
或者配置文件中的id
指定。默認ID是通過對主機名散列後獲得。
因此保證了同一臺機器每次啟動的ID相同。
解析元數據的文件得到系統中的存在的topic列表,遍歷topic列表中的每個topic:
- 檢查topic名稱是否合法(長度在1-64之間,滿足正則表達式
^[\.a-zA-Z0-9_-]+(#ephemeral)?$
)
,若不合法則忽略 - 使用
GetTopic
函數通過名字獲得topic對象 - 判斷當前topic對象是否處於暫停狀態,是的話調用
Pause
函數暫停topic - 獲取當前topic下所有的channel,並且遍歷channel,執行的操作與topic基本一致
- 檢查channel名稱是否合法(長度在1-64之間,滿足正則表達式
^[\.a-zA-Z0-9_-]+(#ephemeral)?$
)
,若不合法則忽略 - 使用
GetChannel
函數通過名字獲得channel對象 - 判斷當前channel對象是否處於暫停狀態,是的話調用
Pause
函數暫停channel
- 檢查channel名稱是否合法(長度在1-64之間,滿足正則表達式
至此,元數據的載入完成
PersistMetadata
PersistMetadata
將當前的topic和channel信息寫入nsqd.%d.dat文件中,
主要步驟是忽略#ephemeral
結尾的topic和channel後將topic和channel列表json序列化後寫回文件中
寫入文件時先創建擴展名為tmp的臨時文件,寫入內容後並保存後再調用atomicRename
函數將tmp文件重命名為nsqd.%d.dat。
其中atomicRename
函數在windows和其他操作系統下實現方式不同,分別位於nsqd/rename_windows.go
和rename.go
中。在Linux下直接調用了os.Rename
函數,而Windows下則使用Win32 API實現了文件的重命名。
這是因為go的早期版本中Windows下調用os.Rename
函數時如果重命名後的文件已經存在則會失敗。
這個bug在os: make Rename atomic on Windows中提到,
並且已經在os: windows Rename should overwrite destination file.提交中被修復,
因此,Golang1.5不存在這一bug
Main
在Main
函數中,nsqd真正開始運行。Main
監聽tcp,https(如果設置了相關參數),http端口並通過WaitGroupWrapper
的Wrap
函數以goroutine方式啟動主要的組件。
其中WaitGroupWrapper
是對sync.WaitGroup
的簡單包裝
執行完Main
函數後,配置和初始化工作全部完成,各個組件啟動運行,而主goroutine會阻塞在<-signalChan
處,直到收到中斷程序的信號,隨後執行nsqd.Exit
函數。 Exit
函數將進行socket
關閉等清理工作,隨後結束整個程序的運行。
nsq源碼閱讀筆記之nsqd(一)——nsqd的配置解析和初始化