mirror of
https://github.com/TeaOSLab/EdgeNode.git
synced 2025-11-24 16:00:24 +08:00
优化NTP时钟自动同步
This commit is contained in:
@@ -23,7 +23,7 @@ import (
|
|||||||
"github.com/TeaOSLab/EdgeNode/internal/stats"
|
"github.com/TeaOSLab/EdgeNode/internal/stats"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/trackers"
|
"github.com/TeaOSLab/EdgeNode/internal/trackers"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/utils"
|
"github.com/TeaOSLab/EdgeNode/internal/utils"
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/utils/clock"
|
_ "github.com/TeaOSLab/EdgeNode/internal/utils/clock" // 触发时钟更新
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/waf"
|
"github.com/TeaOSLab/EdgeNode/internal/waf"
|
||||||
"github.com/andybalholm/brotli"
|
"github.com/andybalholm/brotli"
|
||||||
"github.com/iwind/TeaGo/Tea"
|
"github.com/iwind/TeaGo/Tea"
|
||||||
@@ -170,11 +170,6 @@ func (this *Node) Start() {
|
|||||||
NewNodeStatusExecutor().Listen()
|
NewNodeStatusExecutor().Listen()
|
||||||
})
|
})
|
||||||
|
|
||||||
// 同步时间
|
|
||||||
goman.New(func() {
|
|
||||||
clock.Start()
|
|
||||||
})
|
|
||||||
|
|
||||||
// 读取配置
|
// 读取配置
|
||||||
nodeConfig, err := nodeconfigs.SharedNodeConfig()
|
nodeConfig, err := nodeconfigs.SharedNodeConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
158
internal/utils/clock/manager.go
Normal file
158
internal/utils/clock/manager.go
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package clock
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
|
||||||
|
"github.com/TeaOSLab/EdgeNode/internal/events"
|
||||||
|
"github.com/TeaOSLab/EdgeNode/internal/goman"
|
||||||
|
"github.com/TeaOSLab/EdgeNode/internal/remotelogs"
|
||||||
|
executils "github.com/TeaOSLab/EdgeNode/internal/utils/exec"
|
||||||
|
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||||
|
"net"
|
||||||
|
"os/exec"
|
||||||
|
"runtime"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var hasSynced = false
|
||||||
|
var sharedClockManager = NewClockManager()
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
events.On(events.EventLoaded, func() {
|
||||||
|
goman.New(sharedClockManager.Start)
|
||||||
|
})
|
||||||
|
events.On(events.EventReload, func() {
|
||||||
|
if !hasSynced {
|
||||||
|
hasSynced = true
|
||||||
|
|
||||||
|
goman.New(func() {
|
||||||
|
err := sharedClockManager.Sync()
|
||||||
|
if err != nil {
|
||||||
|
remotelogs.Error("CLOCK", "sync clock failed: "+err.Error())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type ClockManager struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewClockManager() *ClockManager {
|
||||||
|
return &ClockManager{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start 启动
|
||||||
|
func (this *ClockManager) Start() {
|
||||||
|
var ticker = time.NewTicker(1 * time.Hour)
|
||||||
|
for range ticker.C {
|
||||||
|
err := this.Sync()
|
||||||
|
if err != nil {
|
||||||
|
remotelogs.Error("CLOCK", "sync clock failed: "+err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sync 自动校对时间
|
||||||
|
func (this *ClockManager) Sync() error {
|
||||||
|
if runtime.GOOS != "linux" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeConfig, _ := nodeconfigs.SharedNodeConfig()
|
||||||
|
if nodeConfig == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var config = nodeConfig.Clock
|
||||||
|
if config == nil || !config.AutoSync {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var server = config.Server
|
||||||
|
if len(server) == 0 {
|
||||||
|
server = "pool.ntp.org"
|
||||||
|
}
|
||||||
|
|
||||||
|
ntpdate, err := exec.LookPath("ntpdate")
|
||||||
|
if err != nil {
|
||||||
|
// 使用 date 命令设置
|
||||||
|
// date --set TIME
|
||||||
|
dateExe, err := exec.LookPath("date")
|
||||||
|
if err == nil {
|
||||||
|
currentTime, err := this.readServer(server)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("read server failed: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
var delta = time.Now().Unix() - currentTime.Unix()
|
||||||
|
if delta > 1 || delta < -1 { // 相差比较大的时候才会同步
|
||||||
|
var err = executils.NewTimeoutCmd(3*time.Second, dateExe, "--set", timeutil.Format("Y-m-d H:i:s+P", currentTime)).
|
||||||
|
Run()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if len(ntpdate) > 0 {
|
||||||
|
return this.syncNtpdate(ntpdate, server)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *ClockManager) syncNtpdate(ntpdate string, server string) error {
|
||||||
|
var cmd = executils.NewTimeoutCmd(30*time.Second, ntpdate, server)
|
||||||
|
cmd.WithStderr()
|
||||||
|
err := cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
return errors.New(err.Error() + ": " + cmd.Stderr())
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 参考自:https://medium.com/learning-the-go-programming-language/lets-make-an-ntp-client-in-go-287c4b9a969f
|
||||||
|
func (this *ClockManager) readServer(server string) (time.Time, error) {
|
||||||
|
conn, err := net.Dial("udp", server+":123")
|
||||||
|
if err != nil {
|
||||||
|
return time.Time{}, errors.New("connect to server failed: " + err.Error())
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
_ = conn.Close()
|
||||||
|
}()
|
||||||
|
err = conn.SetDeadline(time.Now().Add(5 * time.Second))
|
||||||
|
if err != nil {
|
||||||
|
return time.Time{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// configure request settings by specifying the first byte as
|
||||||
|
// 00 011 011 (or 0x1B)
|
||||||
|
// | | +-- client mode (3)
|
||||||
|
// | + ----- version (3)
|
||||||
|
// + -------- leap year indicator, 0 no warning
|
||||||
|
|
||||||
|
var req = &NTPPacket{Settings: 0x1B}
|
||||||
|
err = binary.Write(conn, binary.BigEndian, req)
|
||||||
|
if err != nil {
|
||||||
|
return time.Time{}, errors.New("write request failed: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
var resp = &NTPPacket{}
|
||||||
|
err = binary.Read(conn, binary.BigEndian, resp)
|
||||||
|
if err != nil {
|
||||||
|
return time.Time{}, errors.New("write server response failed: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
const ntpEpochOffset = 2208988800
|
||||||
|
|
||||||
|
var secs = float64(resp.TxTimeSec) - ntpEpochOffset
|
||||||
|
var nanos = (int64(resp.TxTimeFrac) * 1e9) >> 32
|
||||||
|
return time.Unix(int64(secs), nanos), nil
|
||||||
|
}
|
||||||
11
internal/utils/clock/manager_test.go
Normal file
11
internal/utils/clock/manager_test.go
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package clock_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestReadServer(t *testing.T) {
|
||||||
|
|
||||||
|
}
|
||||||
21
internal/utils/clock/ntp_packet.go
Normal file
21
internal/utils/clock/ntp_packet.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||||
|
|
||||||
|
package clock
|
||||||
|
|
||||||
|
type NTPPacket struct {
|
||||||
|
Settings uint8 // leap yr indicator, ver number, and mode
|
||||||
|
Stratum uint8 // stratum of local clock
|
||||||
|
Poll int8 // poll exponent
|
||||||
|
Precision int8 // precision exponent
|
||||||
|
RootDelay uint32 // root delay
|
||||||
|
RootDispersion uint32 // root dispersion
|
||||||
|
ReferenceID uint32 // reference id
|
||||||
|
RefTimeSec uint32 // reference timestamp sec
|
||||||
|
RefTimeFrac uint32 // reference timestamp fractional
|
||||||
|
OrigTimeSec uint32 // origin time secs
|
||||||
|
OrigTimeFrac uint32 // origin time fractional
|
||||||
|
RxTimeSec uint32 // receive time secs
|
||||||
|
RxTimeFrac uint32 // receive time frac
|
||||||
|
TxTimeSec uint32 // transmit time secs
|
||||||
|
TxTimeFrac uint32 // transmit time frac
|
||||||
|
}
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
|
||||||
|
|
||||||
package clock
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"github.com/TeaOSLab/EdgeNode/internal/remotelogs"
|
|
||||||
executils "github.com/TeaOSLab/EdgeNode/internal/utils/exec"
|
|
||||||
"os/exec"
|
|
||||||
"runtime"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Start TODO 需要可以在集群中配置
|
|
||||||
func Start() {
|
|
||||||
// sync once
|
|
||||||
err := Sync()
|
|
||||||
if err != nil {
|
|
||||||
remotelogs.Warn("CLOCK", "sync time clock failed: "+err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
var ticker = time.NewTicker(1 * time.Hour)
|
|
||||||
for range ticker.C {
|
|
||||||
err := Sync()
|
|
||||||
if err != nil {
|
|
||||||
// ignore error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sync 自动校对时间
|
|
||||||
func Sync() error {
|
|
||||||
if runtime.GOOS != "linux" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
ntpdate, err := exec.LookPath("ntpdate")
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if len(ntpdate) > 0 {
|
|
||||||
return syncNtpdate(ntpdate)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func syncNtpdate(ntpdate string) error {
|
|
||||||
var cmd = executils.NewTimeoutCmd(30*time.Second, ntpdate, "pool.ntp.org")
|
|
||||||
cmd.WithStderr()
|
|
||||||
err := cmd.Run()
|
|
||||||
if err != nil {
|
|
||||||
return errors.New(err.Error() + ": " + cmd.Stderr())
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user