Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,在BSD-like 协议下发行。其特点是占有内存少,并发能力强,事实上nginx的并发能力在同类型的网页服务器中表现较好,因此TSINGSEE青犀视频云边端架构视频智能分析平台在运行时也会使用nginx服务器。
部分情况下,EasyNVR启动时只带起来了一个nginx,但是一个nginx的能力不能满足EasyNVR直播转码分发以及存储的需求,因此这时我们需要启动多个nginx。本文就讲一下启动多个Nginx的方法。
在EasyNVR程序启动的时候,会默认启动一个nginx,我们可以查看这部分代码,仿照这部分代码编写启动多个nginx的代码。
func Start() (err error) {
exe := EXE()
MutliStrart(exe, 0)
enable := utils.Conf().Section("base_config").Key("multi_nginx_enable").MustBool(false)
if enable {
number := utils.Conf().Section("base_config").Key("multi_nginx_number").MustInt()
for i := 1; i < number; i++ {
MutliStrart(MultiEXE(i), i)
}
}
return
}
在启动的时候,默认会先启动EasyNVR里面默认的nginx,然后根据配置文件启动多个nginx,参考代码如下:
func MutliStrart(exe string, index int) (err error) {
if exe == "" {
err = fmt.Errorf("dss bin path not found")
return
}
pids, _ := filepath.Glob(filepath.Join(filepath.Dir(exe), "logs/*.pid"))
if pids != nil && index == 0 {
utils.Logf("%s find pid file", filepath.Base(exe))
if err := Stop(); err == nil {
//wait for stop done
for i := 0; i < 10; i++ {
time.Sleep(1 * time.Second)
pids, _ := filepath.Glob(filepath.Join(filepath.Dir(exe), "logs/*.pid"))
if pids == nil {
log.Printf("%s wait for stop done", filepath.Base(exe))
break
}
}
}
}
//var httpPort int
//var rtmpPort int
//if index != 0 {
// httpPort = int(GetHTTPPort()) + index
// rtmpPort = int(GetRTMPPort()) + index
// SetMutliHTTPPort(uint(httpPort), index)
// SetMutliRTMPPort(uint(rtmpPort), index)
//}
if utils.IsPortInUse(int(GetHTTPPort())) && index == 0 {
err = fmt.Errorf("port[%d] In Use", GetHTTPPort())
return
}
if utils.IsPortInUse(int(GetRTMPPort())) && index == 0 {
err = fmt.Errorf("port[%d] In Use", GetRTMPPort())
return
}
err = utils.EnsureDir(HLSDir())
if err != nil {
log.Println(err)
return
}
err = utils.EnsureDir(RecordDir())
if err != nil {
log.Println(err)
return
}
err = utils.EnsureDir(filepath.Join(filepath.Dir(exe), "logs"))
if err != nil {
log.Println(err)
return
}
err = utils.EnsureDir(filepath.Join(filepath.Dir(exe), "temp"))
if err != nil {
log.Println(err)
return
}
cmd := exec.Command(exe)
cmd.Dir = filepath.Dir(exe)
cmd.SysProcAttr = &syscall.SysProcAttr{
HideWindow: true,
CreationFlags: syscall.CREATE_NEW_PROCESS_GROUP,
}
err = cmd.Start()
if err != nil {
log.Printf("start dss error, %v", err)
return
}
go func() {
if err := cmd.Wait(); err != nil {
log.Printf("wait dss error, %v", err)
}
}()
if index == 0 {
go StartTicker()
} else {
go StratMutliTicker(index)
}
if index == 0 {
log.Println("%s start ok, rtmp port[%d], http port[%d]", filepath.Base(exe), GetRTMPPort(), GetHTTPPort())
} else {
log.Println("%s start ok, rtmp port[%d], http port[%d]", filepath.Base(exe), GetMutliRTMPPort(index), GetMutliHTTPPort(index))
}
return
}
至此,启动多个nginx代码就可以了。但是,现在EasyNVR每个通道还是向默认的nginx进行推流录像,推流直播,因此我们需要在相应的地方进行修改。
func (channel *ChannelInfo) InitPushers(camera *models.Camera) {
channel.lock.Lock()
defer channel.lock.Unlock()
if channel.client == nil {
return
}
rtmpHost := utils.Conf().Section("base_config").Key("rtmp_host").MustString("")
// 根据配置文件
enable := utils.Conf().Section("base_config").Key("hls_record_enable").MustBool(true)
var application = ""
if enable {
application = "hls"
} else {
application = "record"
}
if rtmpHost == "" {
var rtmpPort uint
enable := utils.Conf().Section("base_config").Key("multi_nginx_enable").MustBool(false)
if enable {
number := utils.Conf().Section("base_config").Key("multi_nginx_number").MustInt()
channelId := int(channel.Channel)
index := channelId % number
rtmpPort = dss.GetMutliRTMPPort(index)
} else {
rtmpPort = dss.GetRTMPPort()
}
channel.localPusher = stream.NewStreamPusher(fmt.Sprintf("%s - 推流直播", camera.Name), fmt.Sprintf("rtmp://127.0.0.1:%d/%s/%s", rtmpPort, application, StreamID(camera.ID)))
channel.localPusher.AudioEnable = camera.Reserve1 == "1"
channel.recordPusher = stream.NewStreamPusher(fmt.Sprintf("%s - 推流录像", camera.Name), fmt.Sprintf("rtmp://127.0.0.1:%d/record/%s", rtmpPort, StreamID(camera.ID)))
channel.recordPusher.AudioEnable = camera.Reserve1 == "1"
} else {
channel.localPusher = stream.NewStreamPusher(fmt.Sprintf("%s - 推流直播", camera.Name), fmt.Sprintf("rtmp://%s/%s/%s", rtmpHost, application, StreamID(camera.ID)))
channel.localPusher.AudioEnable = camera.Reserve1 == "1"
channel.recordPusher = stream.NewStreamPusher(fmt.Sprintf("%s - 推流录像", camera.Name), fmt.Sprintf("rtmp://%s/record/%s", rtmpHost, StreamID(camera.ID)))
channel.recordPusher.AudioEnable = camera.Reserve1 == "1"
}
经过这样修改后,例如:
EasyNVR配置启动3个nginx,通道1就向nginx1推流,通道2就向nginx2推流,通道3就向nginx3推流,通道4就向nginx1推流…每隔3个通道一次轮回。至此,EasyNVR多nginx方案就已经实现了。
EasyNVR视频平台被运用在很多场景下,包括智慧水利、智慧交通、校园安防等,当然还有更多的场景在拓展当中,如果大家有需求,欢迎联系我们,TSINGSEE青犀视频团队将根据大家的需求出具最合适的解决方案。