github.com/TeaOSLab/EdgeNode@v1.3.8/internal/nodes/node.go (about)

     1  package nodes
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"encoding/json"
     7  	"errors"
     8  	"fmt"
     9  	"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
    10  	iplib "github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
    11  	"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
    12  	"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
    13  	"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
    14  	"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs"
    15  	"github.com/TeaOSLab/EdgeNode/internal/caches"
    16  	"github.com/TeaOSLab/EdgeNode/internal/configs"
    17  	"github.com/TeaOSLab/EdgeNode/internal/conns"
    18  	teaconst "github.com/TeaOSLab/EdgeNode/internal/const"
    19  	"github.com/TeaOSLab/EdgeNode/internal/events"
    20  	"github.com/TeaOSLab/EdgeNode/internal/firewalls"
    21  	"github.com/TeaOSLab/EdgeNode/internal/goman"
    22  	"github.com/TeaOSLab/EdgeNode/internal/iplibrary"
    23  	"github.com/TeaOSLab/EdgeNode/internal/metrics"
    24  	"github.com/TeaOSLab/EdgeNode/internal/remotelogs"
    25  	"github.com/TeaOSLab/EdgeNode/internal/rpc"
    26  	"github.com/TeaOSLab/EdgeNode/internal/stats"
    27  	"github.com/TeaOSLab/EdgeNode/internal/trackers"
    28  	"github.com/TeaOSLab/EdgeNode/internal/utils"
    29  	_ "github.com/TeaOSLab/EdgeNode/internal/utils/agents" // 引入Agent管理器
    30  	_ "github.com/TeaOSLab/EdgeNode/internal/utils/clock"  // 触发时钟更新
    31  	fsutils "github.com/TeaOSLab/EdgeNode/internal/utils/fs"
    32  	"github.com/TeaOSLab/EdgeNode/internal/utils/jsonutils"
    33  	memutils "github.com/TeaOSLab/EdgeNode/internal/utils/mem"
    34  	"github.com/TeaOSLab/EdgeNode/internal/waf"
    35  	"github.com/andybalholm/brotli"
    36  	"github.com/iwind/TeaGo/Tea"
    37  	"github.com/iwind/TeaGo/lists"
    38  	"github.com/iwind/TeaGo/maps"
    39  	"github.com/iwind/TeaGo/types"
    40  	"github.com/iwind/gosock/pkg/gosock"
    41  	"log"
    42  	"os"
    43  	"os/exec"
    44  	"os/signal"
    45  	"path/filepath"
    46  	"runtime"
    47  	"runtime/debug"
    48  	"sort"
    49  	"strings"
    50  	"sync"
    51  	"syscall"
    52  	"time"
    53  )
    54  
    55  var sharedNodeConfig *nodeconfigs.NodeConfig
    56  var nodeTaskNotify = make(chan bool, 8)
    57  var nodeConfigChangedNotify = make(chan bool, 8)
    58  var nodeConfigUpdatedAt int64
    59  var DaemonIsOn = false
    60  var DaemonPid = 0
    61  var nodeInstance *Node
    62  
    63  // Node 节点
    64  type Node struct {
    65  	isLoaded bool
    66  	sock     *gosock.Sock
    67  	locker   sync.Mutex
    68  
    69  	oldMaxCPU               int32
    70  	oldMaxThreads           int
    71  	oldTimezone             string
    72  	oldHTTPCachePolicies    []*serverconfigs.HTTPCachePolicy
    73  	oldHTTPFirewallPolicies []*firewallconfigs.HTTPFirewallPolicy
    74  	oldFirewallActions      []*firewallconfigs.FirewallActionConfig
    75  	oldMetricItems          []*serverconfigs.MetricItemConfig
    76  
    77  	updatingServerMap map[int64]*serverconfigs.ServerConfig
    78  
    79  	lastAPINodeVersion int64
    80  	lastAPINodeAddrs   []string // 以前的API节点地址
    81  
    82  	lastTaskVersion          int64
    83  	lastUpdatingServerListId int64
    84  }
    85  
    86  func NewNode() *Node {
    87  	nodeInstance = &Node{
    88  		sock:              gosock.NewTmpSock(teaconst.ProcessName),
    89  		oldMaxThreads:     -1,
    90  		oldMaxCPU:         -1,
    91  		updatingServerMap: map[int64]*serverconfigs.ServerConfig{},
    92  	}
    93  	return nodeInstance
    94  }
    95  
    96  // Test 检查配置
    97  func (this *Node) Test() error {
    98  	// 检查是否能连接API
    99  	rpcClient, err := rpc.SharedRPC()
   100  	if err != nil {
   101  		return fmt.Errorf("test rpc failed: %w", err)
   102  	}
   103  	_, err = rpcClient.APINodeRPC.FindCurrentAPINodeVersion(rpcClient.Context(), &pb.FindCurrentAPINodeVersionRequest{})
   104  	if err != nil {
   105  		return fmt.Errorf("test rpc failed: %w", err)
   106  	}
   107  
   108  	return nil
   109  }
   110  
   111  // Start 启动
   112  func (this *Node) Start() {
   113  	// 设置netdns
   114  	// 这个需要放在所有网络访问的最前面
   115  	_ = os.Setenv("GODEBUG", "netdns=go")
   116  
   117  	_, ok := os.LookupEnv("EdgeDaemon")
   118  	if ok {
   119  		remotelogs.Println("NODE", "start from daemon")
   120  		DaemonIsOn = true
   121  		DaemonPid = os.Getppid()
   122  	}
   123  
   124  	// 处理异常
   125  	this.handlePanic()
   126  
   127  	// 监听signal
   128  	this.listenSignals()
   129  
   130  	// 本地Sock
   131  	err := this.listenSock()
   132  	if err != nil {
   133  		remotelogs.Error("NODE", err.Error())
   134  		return
   135  	}
   136  
   137  	// 启动IP库
   138  	remotelogs.Println("NODE", "initializing ip library ...")
   139  	err = iplib.InitDefault()
   140  	if err != nil {
   141  		remotelogs.Error("NODE", "initialize ip library failed: "+err.Error())
   142  	}
   143  
   144  	// 启动事件
   145  	events.Notify(events.EventStart)
   146  
   147  	// 读取API配置
   148  	remotelogs.Println("NODE", "init config ...")
   149  	err = this.syncConfig(0)
   150  	if err != nil {
   151  		_, err = nodeconfigs.SharedNodeConfig()
   152  		if err != nil {
   153  			// 无本地数据时,会尝试多次读取
   154  			tryTimes := 0
   155  			for {
   156  				err = this.syncConfig(0)
   157  				if err != nil {
   158  					tryTimes++
   159  
   160  					if tryTimes%10 == 0 {
   161  						remotelogs.Error("NODE", err.Error())
   162  					}
   163  					time.Sleep(1 * time.Second)
   164  
   165  					// 不做长时间的无意义的重试
   166  					if tryTimes > 1000 {
   167  						return
   168  					}
   169  				} else {
   170  					break
   171  				}
   172  			}
   173  		}
   174  	}
   175  
   176  	// 启动同步计时器
   177  	this.startSyncTimer()
   178  
   179  	// 更新IP库
   180  	goman.New(func() {
   181  		iplib.NewUpdater(NewIPLibraryUpdater(), 10*time.Minute).Start()
   182  	})
   183  
   184  	// 监控节点运行状态
   185  	goman.New(func() {
   186  		NewNodeStatusExecutor().Listen()
   187  	})
   188  
   189  	// 读取配置
   190  	nodeConfig, err := nodeconfigs.SharedNodeConfig()
   191  	if err != nil {
   192  		remotelogs.Error("NODE", "start failed: read node config failed: "+err.Error())
   193  		return
   194  	}
   195  	teaconst.NodeId = nodeConfig.Id
   196  	teaconst.NodeIdString = types.String(teaconst.NodeId)
   197  	err, serverErrors := nodeConfig.Init(context.Background())
   198  	if err != nil {
   199  		remotelogs.Error("NODE", "init node config failed: "+err.Error())
   200  		return
   201  	}
   202  	if len(serverErrors) > 0 {
   203  		for _, serverErr := range serverErrors {
   204  			remotelogs.ServerError(serverErr.Id, "NODE", serverErr.Message, nodeconfigs.NodeLogTypeServerConfigInitFailed, maps.Map{})
   205  		}
   206  	}
   207  	sharedNodeConfig = nodeConfig
   208  	this.onReload(nodeConfig, true)
   209  
   210  	// 调整系统参数
   211  	go this.tuneSystemParameters()
   212  
   213  	// 发送事件
   214  	events.Notify(events.EventLoaded)
   215  
   216  	// 设置rlimit
   217  	_ = utils.SetRLimit(1 << 20)
   218  
   219  	// 连接API
   220  	goman.New(func() {
   221  		NewAPIStream().Start()
   222  	})
   223  
   224  	// 统计
   225  	goman.New(func() {
   226  		stats.SharedTrafficStatManager.Start()
   227  	})
   228  	goman.New(func() {
   229  		stats.SharedHTTPRequestStatManager.Start()
   230  	})
   231  
   232  	// 硬盘TRIM任务
   233  	goman.New(func() {
   234  		NewTrimDisksTask().Start()
   235  	})
   236  
   237  	// 启动端口
   238  	err = sharedListenerManager.Start(nodeConfig)
   239  	if err != nil {
   240  		remotelogs.Error("NODE", "start failed: "+err.Error())
   241  		return
   242  	}
   243  
   244  	// hold住进程
   245  	select {}
   246  }
   247  
   248  // Daemon 实现守护进程
   249  func (this *Node) Daemon() {
   250  	var isDebug = lists.ContainsString(os.Args, "debug")
   251  	for {
   252  		conn, err := this.sock.Dial()
   253  		if err != nil {
   254  			if isDebug {
   255  				log.Println("[DAEMON]starting ...")
   256  			}
   257  
   258  			// 尝试启动
   259  			err = func() error {
   260  				exe, err := os.Executable()
   261  				if err != nil {
   262  					return err
   263  				}
   264  
   265  				// 可以标记当前是从守护进程启动的
   266  				_ = os.Setenv("EdgeDaemon", "on")
   267  				_ = os.Setenv("EdgeBackground", "on")
   268  
   269  				var cmd = exec.Command(exe)
   270  				var buf = &bytes.Buffer{}
   271  				cmd.Stderr = buf
   272  				err = cmd.Start()
   273  				if err != nil {
   274  					return err
   275  				}
   276  				err = cmd.Wait()
   277  				if err != nil {
   278  					if isDebug {
   279  						log.Println("[DAEMON]" + buf.String())
   280  					}
   281  					return err
   282  				}
   283  				return nil
   284  			}()
   285  
   286  			if err != nil {
   287  				if isDebug {
   288  					log.Println("[DAEMON]", err)
   289  				}
   290  				time.Sleep(1 * time.Second)
   291  			} else {
   292  				time.Sleep(5 * time.Second)
   293  			}
   294  		} else {
   295  			_ = conn.Close()
   296  			time.Sleep(5 * time.Second)
   297  		}
   298  	}
   299  }
   300  
   301  // InstallSystemService 安装系统服务
   302  func (this *Node) InstallSystemService() error {
   303  	shortName := teaconst.SystemdServiceName
   304  
   305  	exe, err := os.Executable()
   306  	if err != nil {
   307  		return err
   308  	}
   309  
   310  	manager := utils.NewServiceManager(shortName, teaconst.ProductName)
   311  	err = manager.Install(exe, []string{})
   312  	if err != nil {
   313  		return err
   314  	}
   315  	return nil
   316  }
   317  
   318  // 读取API配置
   319  func (this *Node) syncConfig(taskVersion int64) error {
   320  	this.locker.Lock()
   321  	defer this.locker.Unlock()
   322  
   323  	// 检查api_node.yaml是否存在
   324  	var apiConfigFile = Tea.ConfigFile(configs.ConfigFileName)
   325  	_, err := os.Stat(apiConfigFile)
   326  	if err != nil {
   327  		if os.IsNotExist(err) {
   328  			clusterErr := this.checkClusterConfig()
   329  			if clusterErr != nil {
   330  				if os.IsNotExist(clusterErr) {
   331  					return fmt.Errorf("can not find config file 'configs/%s'", configs.ConfigFileName)
   332  				}
   333  				return fmt.Errorf("check cluster config failed: %w", clusterErr)
   334  			}
   335  		} else {
   336  			return err
   337  		}
   338  	}
   339  
   340  	rpcClient, err := rpc.SharedRPC()
   341  	if err != nil {
   342  		return fmt.Errorf("create rpc client failed: %w", err)
   343  	}
   344  
   345  	// 获取同步任务
   346  	// TODO 这里考虑只同步版本号有变更的
   347  	configResp, err := rpcClient.NodeRPC.FindCurrentNodeConfig(rpcClient.Context(), &pb.FindCurrentNodeConfigRequest{
   348  		Version:         -1, // 更新所有版本
   349  		Compress:        true,
   350  		NodeTaskVersion: taskVersion,
   351  		UseDataMap:      true,
   352  	})
   353  	if err != nil {
   354  		return fmt.Errorf("read config from rpc failed: %w", err)
   355  	}
   356  	if !configResp.IsChanged {
   357  		return nil
   358  	}
   359  
   360  	var configJSON = configResp.NodeJSON
   361  	if configResp.IsCompressed {
   362  		var reader = brotli.NewReader(bytes.NewReader(configJSON))
   363  		var configBuf = &bytes.Buffer{}
   364  		var buf = make([]byte, 32*1024)
   365  		for {
   366  			n, err := reader.Read(buf)
   367  			if n > 0 {
   368  				configBuf.Write(buf[:n])
   369  			}
   370  			if err != nil {
   371  				break
   372  			}
   373  		}
   374  		configJSON = configBuf.Bytes()
   375  	}
   376  
   377  	nodeConfigUpdatedAt = time.Now().Unix()
   378  
   379  	var nodeConfig = &nodeconfigs.NodeConfig{}
   380  	err = json.Unmarshal(configJSON, nodeConfig)
   381  	if err != nil {
   382  		return fmt.Errorf("decode config failed: %w", err)
   383  	}
   384  	teaconst.NodeId = nodeConfig.Id
   385  	teaconst.NodeIdString = types.String(teaconst.NodeId)
   386  
   387  	// 检查时间是否一致
   388  	// 这个需要在 teaconst.NodeId 设置之后,因为上报到API节点的时候需要节点ID
   389  	if configResp.Timestamp > 0 {
   390  		var timestampDelta = configResp.Timestamp - time.Now().Unix()
   391  		if timestampDelta > 60 || timestampDelta < -60 {
   392  			remotelogs.Error("NODE", "node timestamp ('"+types.String(time.Now().Unix())+"') is not same as api node ('"+types.String(configResp.Timestamp)+"'), please sync the time")
   393  		}
   394  	}
   395  
   396  	// 写入到文件中
   397  	err = nodeConfig.Save()
   398  	if err != nil {
   399  		return err
   400  	}
   401  
   402  	err, serverErrors := nodeConfig.Init(context.Background())
   403  	if err != nil {
   404  		return err
   405  	}
   406  	if len(serverErrors) > 0 {
   407  		for _, serverErr := range serverErrors {
   408  			remotelogs.ServerError(serverErr.Id, "NODE", serverErr.Message, nodeconfigs.NodeLogTypeServerConfigInitFailed, maps.Map{})
   409  		}
   410  	}
   411  
   412  	// 刷新配置
   413  	if this.isLoaded {
   414  		remotelogs.Println("NODE", "reloading node config ...")
   415  	} else {
   416  		remotelogs.Println("NODE", "loading node config ...")
   417  	}
   418  
   419  	this.onReload(nodeConfig, true)
   420  
   421  	// 发送事件
   422  	events.Notify(events.EventReload)
   423  
   424  	if this.isLoaded {
   425  		return sharedListenerManager.Start(nodeConfig)
   426  	}
   427  
   428  	this.isLoaded = true
   429  
   430  	// 整体更新不需要再更新单个服务
   431  	this.updatingServerMap = map[int64]*serverconfigs.ServerConfig{}
   432  
   433  	return nil
   434  }
   435  
   436  // 读取单个服务配置
   437  func (this *Node) syncServerConfig(serverId int64) error {
   438  	rpcClient, err := rpc.SharedRPC()
   439  	if err != nil {
   440  		return err
   441  	}
   442  	resp, err := rpcClient.ServerRPC.ComposeServerConfig(rpcClient.Context(), &pb.ComposeServerConfigRequest{ServerId: serverId})
   443  	if err != nil {
   444  		return err
   445  	}
   446  
   447  	this.locker.Lock()
   448  	defer this.locker.Unlock()
   449  	if len(resp.ServerConfigJSON) == 0 {
   450  		this.updatingServerMap[serverId] = nil
   451  	} else {
   452  		var config = &serverconfigs.ServerConfig{}
   453  		err = json.Unmarshal(resp.ServerConfigJSON, config)
   454  		if err != nil {
   455  			return err
   456  		}
   457  		this.updatingServerMap[serverId] = config
   458  	}
   459  	return nil
   460  }
   461  
   462  // 同步某个用户下的所有服务配置
   463  func (this *Node) syncUserServersConfig(userId int64) error {
   464  	rpcClient, err := rpc.SharedRPC()
   465  	if err != nil {
   466  		return err
   467  	}
   468  	serverConfigsResp, err := rpcClient.ServerRPC.ComposeAllUserServersConfig(rpcClient.Context(), &pb.ComposeAllUserServersConfigRequest{
   469  		UserId: userId,
   470  	})
   471  	if err != nil {
   472  		return err
   473  	}
   474  	if len(serverConfigsResp.ServersConfigJSON) == 0 {
   475  		return nil
   476  	}
   477  	var serverConfigs = []*serverconfigs.ServerConfig{}
   478  	err = json.Unmarshal(serverConfigsResp.ServersConfigJSON, &serverConfigs)
   479  	if err != nil {
   480  		return err
   481  	}
   482  	this.locker.Lock()
   483  	defer this.locker.Unlock()
   484  
   485  	for _, config := range serverConfigs {
   486  		this.updatingServerMap[config.Id] = config
   487  	}
   488  
   489  	return nil
   490  }
   491  
   492  // 启动同步计时器
   493  func (this *Node) startSyncTimer() {
   494  	// TODO 这个时间间隔可以自行设置
   495  	var taskTicker = time.NewTicker(60 * time.Second)
   496  	var serverChangeTicker = time.NewTicker(5 * time.Second)
   497  
   498  	events.OnKey(events.EventQuit, this, func() {
   499  		remotelogs.Println("NODE", "quit sync timer")
   500  		taskTicker.Stop()
   501  		serverChangeTicker.Stop()
   502  	})
   503  	goman.New(func() {
   504  		for {
   505  			select {
   506  			case <-taskTicker.C: // 定期执行
   507  				err := this.loopTasks()
   508  				if err != nil {
   509  					remotelogs.Error("NODE", "sync config error: "+err.Error())
   510  					continue
   511  				}
   512  			case <-serverChangeTicker.C: // 服务变化
   513  				this.reloadServer()
   514  			case <-nodeTaskNotify: // 有新的更新任务
   515  				err := this.loopTasks()
   516  				if err != nil {
   517  					remotelogs.Error("NODE", "sync config error: "+err.Error())
   518  					continue
   519  				}
   520  			case <-nodeConfigChangedNotify: // 节点变化通知
   521  				err := this.syncConfig(0)
   522  				if err != nil {
   523  					remotelogs.Error("NODE", "sync config error: "+err.Error())
   524  					continue
   525  				}
   526  			}
   527  		}
   528  	})
   529  }
   530  
   531  // 检查集群设置
   532  func (this *Node) checkClusterConfig() error {
   533  	config, err := configs.LoadClusterConfig()
   534  	if err != nil {
   535  		return err
   536  	}
   537  	rpcClient, err := rpc.NewRPCClient(&configs.APIConfig{
   538  		RPCEndpoints:     config.RPCEndpoints,
   539  		RPCDisableUpdate: config.RPCDisableUpdate,
   540  		NodeId:           config.ClusterId,
   541  		Secret:           config.Secret,
   542  	})
   543  	if err != nil {
   544  		return err
   545  	}
   546  
   547  	remotelogs.Debug("NODE", "registering node to cluster ...")
   548  	resp, err := rpcClient.NodeRPC.RegisterClusterNode(rpcClient.ClusterContext(config.ClusterId, config.Secret), &pb.RegisterClusterNodeRequest{Name: HOSTNAME})
   549  	if err != nil {
   550  		return err
   551  	}
   552  	remotelogs.Debug("NODE", "registered successfully")
   553  
   554  	// 写入到配置文件中
   555  	if len(resp.Endpoints) == 0 {
   556  		resp.Endpoints = []string{}
   557  	}
   558  	var apiConfig = &configs.APIConfig{
   559  		RPCEndpoints:     resp.Endpoints,
   560  		RPCDisableUpdate: false,
   561  		NodeId:           resp.UniqueId,
   562  		Secret:           resp.Secret,
   563  	}
   564  	remotelogs.Debug("NODE", "writing 'configs/"+configs.ConfigFileName+"' ...")
   565  	err = apiConfig.WriteFile(Tea.ConfigFile(configs.ConfigFileName))
   566  	if err != nil {
   567  		return err
   568  	}
   569  	remotelogs.Debug("NODE", "wrote 'configs/"+configs.ConfigFileName+"' successfully")
   570  
   571  	return nil
   572  }
   573  
   574  // 监听一些信号
   575  func (this *Node) listenSignals() {
   576  	var queue = make(chan os.Signal, 8)
   577  	signal.Notify(queue, syscall.SIGTERM, syscall.SIGINT, syscall.SIGKILL, syscall.SIGQUIT)
   578  	goman.New(func() {
   579  		for range queue {
   580  			time.Sleep(100 * time.Millisecond)
   581  			utils.Exit()
   582  			return
   583  		}
   584  	})
   585  }
   586  
   587  // 监听本地sock
   588  func (this *Node) listenSock() error {
   589  	// 检查是否在运行
   590  	if this.sock.IsListening() {
   591  		reply, err := this.sock.Send(&gosock.Command{Code: "pid"})
   592  		if err == nil {
   593  			return errors.New("error: the process is already running, pid: " + types.String(maps.NewMap(reply.Params).GetInt("pid")))
   594  		} else {
   595  			return errors.New("error: the process is already running")
   596  		}
   597  	}
   598  
   599  	// 启动监听
   600  	goman.New(func() {
   601  		this.sock.OnCommand(func(cmd *gosock.Command) {
   602  			switch cmd.Code {
   603  			case "pid":
   604  				_ = cmd.Reply(&gosock.Command{
   605  					Code: "pid",
   606  					Params: map[string]interface{}{
   607  						"pid": os.Getpid(),
   608  					},
   609  				})
   610  			case "info":
   611  				exePath, _ := os.Executable()
   612  				_ = cmd.Reply(&gosock.Command{
   613  					Code: "info",
   614  					Params: map[string]interface{}{
   615  						"pid":     os.Getpid(),
   616  						"version": teaconst.Version,
   617  						"path":    exePath,
   618  					},
   619  				})
   620  			case "stop":
   621  				_ = cmd.ReplyOk()
   622  
   623  				// 退出主进程
   624  				events.Notify(events.EventQuit)
   625  				time.Sleep(100 * time.Millisecond)
   626  				utils.Exit()
   627  			case "quit":
   628  				_ = cmd.ReplyOk()
   629  				_ = this.sock.Close()
   630  
   631  				events.Notify(events.EventQuit)
   632  				events.Notify(events.EventTerminated)
   633  
   634  				// 监控连接数,如果连接数为0,则退出进程
   635  				goman.New(func() {
   636  					for {
   637  						countActiveConnections := sharedListenerManager.TotalActiveConnections()
   638  						if countActiveConnections <= 0 {
   639  							utils.Exit()
   640  							return
   641  						}
   642  						time.Sleep(1 * time.Second)
   643  					}
   644  				})
   645  			case "trackers":
   646  				_ = cmd.Reply(&gosock.Command{
   647  					Params: map[string]interface{}{
   648  						"labels": trackers.SharedManager.Labels(),
   649  					},
   650  				})
   651  			case "goman":
   652  				var posMap = map[string]maps.Map{} // file#line => Map
   653  				for _, instance := range goman.List() {
   654  					var pos = instance.File + "#" + types.String(instance.Line)
   655  					m, ok := posMap[pos]
   656  					if ok {
   657  						m["count"] = m["count"].(int) + 1
   658  					} else {
   659  						m = maps.Map{
   660  							"pos":   pos,
   661  							"count": 1,
   662  						}
   663  						posMap[pos] = m
   664  					}
   665  				}
   666  
   667  				var result = []maps.Map{}
   668  				for _, m := range posMap {
   669  					result = append(result, m)
   670  				}
   671  
   672  				sort.Slice(result, func(i, j int) bool {
   673  					return result[i]["count"].(int) > result[j]["count"].(int)
   674  				})
   675  
   676  				_ = cmd.Reply(&gosock.Command{
   677  					Params: map[string]interface{}{
   678  						"total":  runtime.NumGoroutine(),
   679  						"result": result,
   680  					},
   681  				})
   682  			case "conns":
   683  				var connMaps = []maps.Map{}
   684  				var connMap = conns.SharedMap.AllConns()
   685  				for _, conn := range connMap {
   686  					var createdAt int64
   687  					var lastReadAt int64
   688  					var lastWriteAt int64
   689  					var lastErrString = ""
   690  					var protocol = "tcp"
   691  					clientConn, ok := conn.(*ClientConn)
   692  					if ok {
   693  						createdAt = clientConn.CreatedAt()
   694  						lastReadAt = clientConn.LastReadAt()
   695  						lastWriteAt = clientConn.LastWriteAt()
   696  
   697  						var lastErr = clientConn.LastErr()
   698  						if lastErr != nil {
   699  							lastErrString = lastErr.Error()
   700  						}
   701  					} else {
   702  						protocol = "udp"
   703  					}
   704  					var age int64 = -1
   705  					var lastReadAge int64 = -1
   706  					var lastWriteAge int64 = -1
   707  					var currentTime = time.Now().Unix()
   708  					if createdAt > 0 {
   709  						age = currentTime - createdAt
   710  					}
   711  					if lastReadAt > 0 {
   712  						lastReadAge = currentTime - lastReadAt
   713  					}
   714  					if lastWriteAt > 0 {
   715  						lastWriteAge = currentTime - lastWriteAt
   716  					}
   717  
   718  					connMaps = append(connMaps, maps.Map{
   719  						"protocol": protocol,
   720  						"addr":     conn.RemoteAddr().String(),
   721  						"age":      age,
   722  						"readAge":  lastReadAge,
   723  						"writeAge": lastWriteAge,
   724  						"lastErr":  lastErrString,
   725  					})
   726  				}
   727  				sort.Slice(connMaps, func(i, j int) bool {
   728  					var m1 = connMaps[i]
   729  					var m2 = connMaps[j]
   730  					return m1.GetInt64("age") < m2.GetInt64("age")
   731  				})
   732  
   733  				_ = cmd.Reply(&gosock.Command{
   734  					Params: map[string]interface{}{
   735  						"conns": connMaps,
   736  						"total": len(connMaps),
   737  					},
   738  				})
   739  			case "dropIP":
   740  				var m = maps.NewMap(cmd.Params)
   741  				var ip = m.GetString("ip")
   742  				var timeSeconds = m.GetInt("timeoutSeconds")
   743  				var async = m.GetBool("async")
   744  				err := firewalls.Firewall().DropSourceIP(ip, timeSeconds, async)
   745  				if err != nil {
   746  					_ = cmd.Reply(&gosock.Command{
   747  						Params: map[string]interface{}{
   748  							"error": err.Error(),
   749  						},
   750  					})
   751  				} else {
   752  					_ = cmd.ReplyOk()
   753  				}
   754  			case "rejectIP":
   755  				var m = maps.NewMap(cmd.Params)
   756  				var ip = m.GetString("ip")
   757  				var timeSeconds = m.GetInt("timeoutSeconds")
   758  				err := firewalls.Firewall().RejectSourceIP(ip, timeSeconds)
   759  				if err != nil {
   760  					_ = cmd.Reply(&gosock.Command{
   761  						Params: map[string]interface{}{
   762  							"error": err.Error(),
   763  						},
   764  					})
   765  				} else {
   766  					_ = cmd.ReplyOk()
   767  				}
   768  			case "closeIP":
   769  				var m = maps.NewMap(cmd.Params)
   770  				var ip = m.GetString("ip")
   771  				conns.SharedMap.CloseIPConns(ip)
   772  				_ = cmd.ReplyOk()
   773  			case "removeIP":
   774  				var m = maps.NewMap(cmd.Params)
   775  				var ip = m.GetString("ip")
   776  				err := firewalls.Firewall().RemoveSourceIP(ip)
   777  				if err != nil {
   778  					_ = cmd.Reply(&gosock.Command{
   779  						Params: map[string]interface{}{
   780  							"error": err.Error(),
   781  						},
   782  					})
   783  				} else {
   784  					_ = cmd.ReplyOk()
   785  				}
   786  			case "gc":
   787  				var before = time.Now()
   788  				runtime.GC()
   789  				debug.FreeOSMemory()
   790  
   791  				var costSeconds = time.Since(before).Seconds()
   792  				var gcStats = &debug.GCStats{}
   793  				debug.ReadGCStats(gcStats)
   794  				var pauseMS float64
   795  				if len(gcStats.Pause) > 0 {
   796  					pauseMS = gcStats.Pause[0].Seconds() * 1000
   797  				}
   798  				_ = cmd.Reply(&gosock.Command{
   799  					Params: map[string]any{
   800  						"pauseMS": pauseMS,
   801  						"costMS":  costSeconds * 1000,
   802  					},
   803  				})
   804  			case "reload":
   805  				err := this.syncConfig(0)
   806  				if err != nil {
   807  					_ = cmd.Reply(&gosock.Command{
   808  						Params: map[string]interface{}{
   809  							"error": err.Error(),
   810  						},
   811  					})
   812  				} else {
   813  					_ = cmd.ReplyOk()
   814  				}
   815  			case "accesslog":
   816  				err := sharedHTTPAccessLogViewer.Start()
   817  				if err != nil {
   818  					_ = cmd.Reply(&gosock.Command{
   819  						Code: "error",
   820  						Params: map[string]interface{}{
   821  							"message": "start failed: " + err.Error(),
   822  						},
   823  					})
   824  				} else {
   825  					_ = cmd.ReplyOk()
   826  				}
   827  			case "bandwidth":
   828  				var m = stats.SharedBandwidthStatManager.Map()
   829  				_ = cmd.Reply(&gosock.Command{Params: maps.Map{
   830  					"stats": m,
   831  				}})
   832  			case "cache.garbage":
   833  				var shouldDelete = maps.NewMap(cmd.Params).GetBool("delete")
   834  
   835  				var count = 0
   836  				var sampleFiles = []string{}
   837  				err := caches.SharedManager.ScanGarbageCaches(func(path string) error {
   838  					count++
   839  					if len(sampleFiles) < 10 {
   840  						sampleFiles = append(sampleFiles, path)
   841  					}
   842  
   843  					if shouldDelete {
   844  						_ = os.Remove(path)                               // .cache
   845  						_ = os.Remove(caches.PartialRangesFilePath(path)) // @range.cache
   846  					}
   847  
   848  					return nil
   849  				})
   850  				if err != nil {
   851  					_ = cmd.Reply(&gosock.Command{Params: maps.Map{
   852  						"isOk":  false,
   853  						"error": err.Error(),
   854  					}})
   855  				} else {
   856  					_ = cmd.Reply(&gosock.Command{Params: maps.Map{
   857  						"isOk":        true,
   858  						"count":       count,
   859  						"sampleFiles": sampleFiles,
   860  					}})
   861  				}
   862  			}
   863  		})
   864  
   865  		err := this.sock.Listen()
   866  		if err != nil {
   867  			remotelogs.Debug("NODE", err.Error())
   868  		}
   869  	})
   870  
   871  	events.OnKey(events.EventQuit, this, func() {
   872  		remotelogs.Debug("NODE", "quit unix sock")
   873  		_ = this.sock.Close()
   874  	})
   875  
   876  	return nil
   877  }
   878  
   879  // 重载配置调用
   880  func (this *Node) onReload(config *nodeconfigs.NodeConfig, reloadAll bool) {
   881  	nodeconfigs.ResetNodeConfig(config)
   882  	sharedNodeConfig = config
   883  
   884  	// 并发读写数
   885  	fsutils.ReaderLimiter.SetThreads(config.MaxConcurrentReads)
   886  	fsutils.WriterLimiter.SetThreads(config.MaxConcurrentWrites)
   887  
   888  	if reloadAll {
   889  		// 缓存策略
   890  		var subDirs = config.CacheDiskSubDirs
   891  		for _, subDir := range subDirs {
   892  			subDir.Path = filepath.Clean(subDir.Path)
   893  		}
   894  		if len(subDirs) > 0 {
   895  			sort.Slice(subDirs, func(i, j int) bool {
   896  				return subDirs[i].Path < subDirs[j].Path
   897  			})
   898  		}
   899  
   900  		var cachePoliciesChanged = !jsonutils.Equal(caches.SharedManager.MaxDiskCapacity, config.MaxCacheDiskCapacity) ||
   901  			!jsonutils.Equal(caches.SharedManager.MaxMemoryCapacity, config.MaxCacheMemoryCapacity) ||
   902  			!jsonutils.Equal(caches.SharedManager.MainDiskDir, config.CacheDiskDir) ||
   903  			!jsonutils.Equal(caches.SharedManager.SubDiskDirs, subDirs) ||
   904  			!jsonutils.Equal(this.oldHTTPCachePolicies, config.HTTPCachePolicies)
   905  
   906  		caches.SharedManager.MaxDiskCapacity = config.MaxCacheDiskCapacity
   907  		caches.SharedManager.MaxMemoryCapacity = config.MaxCacheMemoryCapacity
   908  		caches.SharedManager.MainDiskDir = config.CacheDiskDir
   909  		caches.SharedManager.SubDiskDirs = subDirs
   910  
   911  		if cachePoliciesChanged {
   912  			// copy
   913  			this.oldHTTPCachePolicies = []*serverconfigs.HTTPCachePolicy{}
   914  			err := jsonutils.Copy(&this.oldHTTPCachePolicies, config.HTTPCachePolicies)
   915  			if err != nil {
   916  				remotelogs.Error("NODE", "onReload: copy HTTPCachePolicies failed: "+err.Error())
   917  			}
   918  
   919  			// update
   920  			if len(config.HTTPCachePolicies) > 0 {
   921  				caches.SharedManager.UpdatePolicies(config.HTTPCachePolicies)
   922  			} else {
   923  				caches.SharedManager.UpdatePolicies([]*serverconfigs.HTTPCachePolicy{})
   924  			}
   925  		}
   926  	}
   927  
   928  	// WAF策略
   929  	// 包含了服务里的WAF策略,所以需要整体更新
   930  	var allFirewallPolicies = config.FindAllFirewallPolicies()
   931  	if !jsonutils.Equal(allFirewallPolicies, this.oldHTTPFirewallPolicies) {
   932  		// copy
   933  		this.oldHTTPFirewallPolicies = []*firewallconfigs.HTTPFirewallPolicy{}
   934  		err := jsonutils.Copy(&this.oldHTTPFirewallPolicies, allFirewallPolicies)
   935  		if err != nil {
   936  			remotelogs.Error("NODE", "onReload: copy HTTPFirewallPolicies failed: "+err.Error())
   937  		}
   938  
   939  		// update
   940  		waf.SharedWAFManager.UpdatePolicies(allFirewallPolicies)
   941  	}
   942  
   943  	if reloadAll {
   944  		if !jsonutils.Equal(config.FirewallActions, this.oldFirewallActions) {
   945  			// copy
   946  			this.oldFirewallActions = []*firewallconfigs.FirewallActionConfig{}
   947  			err := jsonutils.Copy(&this.oldFirewallActions, config.FirewallActions)
   948  			if err != nil {
   949  				remotelogs.Error("NODE", "onReload: copy FirewallActionConfigs failed: "+err.Error())
   950  			}
   951  
   952  			// update
   953  			iplibrary.SharedActionManager.UpdateActions(config.FirewallActions)
   954  		}
   955  
   956  		// 统计指标
   957  		if !jsonutils.Equal(this.oldMetricItems, config.MetricItems) {
   958  			// copy
   959  			this.oldMetricItems = []*serverconfigs.MetricItemConfig{}
   960  			err := jsonutils.Copy(&this.oldMetricItems, config.MetricItems)
   961  			if err != nil {
   962  				remotelogs.Error("NODE", "onReload: copy MetricItemConfigs failed: "+err.Error())
   963  			}
   964  
   965  			// update
   966  			metrics.SharedManager.Update(config.MetricItems)
   967  		}
   968  
   969  		// max cpu
   970  		if config.MaxCPU != this.oldMaxCPU {
   971  			if config.MaxCPU > 0 && config.MaxCPU < int32(runtime.NumCPU()) {
   972  				runtime.GOMAXPROCS(int(config.MaxCPU))
   973  				remotelogs.Println("NODE", "[CPU]set max cpu to '"+types.String(config.MaxCPU)+"'")
   974  			} else {
   975  				var threads = runtime.NumCPU()
   976  				runtime.GOMAXPROCS(threads)
   977  				remotelogs.Println("NODE", "[CPU]set max cpu to '"+types.String(threads)+"'")
   978  			}
   979  
   980  			this.oldMaxCPU = config.MaxCPU
   981  		}
   982  
   983  		// max threads
   984  		if config.MaxThreads != this.oldMaxThreads {
   985  			if config.MaxThreads > 0 {
   986  				debug.SetMaxThreads(config.MaxThreads)
   987  				remotelogs.Println("NODE", "[THREADS]set max threads to '"+types.String(config.MaxThreads)+"'")
   988  			} else {
   989  				debug.SetMaxThreads(nodeconfigs.DefaultMaxThreads)
   990  				remotelogs.Println("NODE", "[THREADS]set max threads to '"+types.String(nodeconfigs.DefaultMaxThreads)+"'")
   991  			}
   992  			this.oldMaxThreads = config.MaxThreads
   993  		}
   994  
   995  		// timezone
   996  		var timeZone = config.TimeZone
   997  		if len(timeZone) == 0 {
   998  			timeZone = "Asia/Shanghai"
   999  		}
  1000  
  1001  		if this.oldTimezone != timeZone {
  1002  			location, err := time.LoadLocation(timeZone)
  1003  			if err != nil {
  1004  				remotelogs.Error("NODE", "[TIMEZONE]change time zone failed: "+err.Error())
  1005  				return
  1006  			}
  1007  
  1008  			remotelogs.Println("NODE", "[TIMEZONE]change time zone to '"+timeZone+"'")
  1009  			time.Local = location
  1010  			this.oldTimezone = timeZone
  1011  		}
  1012  
  1013  		// product information
  1014  		if config.ProductConfig != nil {
  1015  			teaconst.GlobalProductName = config.ProductConfig.Name
  1016  		}
  1017  
  1018  		// DNS resolver
  1019  		if config.DNSResolver != nil {
  1020  			var err error
  1021  			switch config.DNSResolver.Type {
  1022  			case nodeconfigs.DNSResolverTypeGoNative:
  1023  				err = os.Setenv("GODEBUG", "netdns=go")
  1024  			case nodeconfigs.DNSResolverTypeCGO:
  1025  				err = os.Setenv("GODEBUG", "netdns=cgo")
  1026  			default:
  1027  				// 默认使用go原生
  1028  				err = os.Setenv("GODEBUG", "netdns=go")
  1029  			}
  1030  			if err != nil {
  1031  				remotelogs.Error("NODE", "[DNS_RESOLVER]set env failed: "+err.Error())
  1032  			}
  1033  		} else {
  1034  			// 默认使用go原生
  1035  			err := os.Setenv("GODEBUG", "netdns=go")
  1036  			if err != nil {
  1037  				remotelogs.Error("NODE", "[DNS_RESOLVER]set env failed: "+err.Error())
  1038  			}
  1039  		}
  1040  
  1041  		// API Node地址,这里不限制是否为空,因为在为空时仍然要有对应的处理
  1042  		this.changeAPINodeAddrs(config.APINodeAddrs)
  1043  	}
  1044  
  1045  	// 刷新IP库
  1046  	this.reloadIPLibrary()
  1047  }
  1048  
  1049  // reload server config
  1050  func (this *Node) reloadServer() {
  1051  	this.locker.Lock()
  1052  	defer this.locker.Unlock()
  1053  
  1054  	var countUpdatingServers = len(this.updatingServerMap)
  1055  	const maxPrintServers = 10
  1056  	if countUpdatingServers > 0 {
  1057  		var updatingServerMap = this.updatingServerMap
  1058  		this.updatingServerMap = map[int64]*serverconfigs.ServerConfig{}
  1059  		newNodeConfig, err := nodeconfigs.CloneNodeConfig(sharedNodeConfig)
  1060  		if err != nil {
  1061  			remotelogs.Error("NODE", "apply server config error: "+err.Error())
  1062  			return
  1063  		}
  1064  		for serverId, serverConfig := range updatingServerMap {
  1065  			if serverConfig != nil {
  1066  				if countUpdatingServers < maxPrintServers {
  1067  					remotelogs.Debug("NODE", "reload server '"+types.String(serverId)+"'")
  1068  				}
  1069  				newNodeConfig.AddServer(serverConfig)
  1070  			} else {
  1071  				if countUpdatingServers < maxPrintServers {
  1072  					remotelogs.Debug("NODE", "remove server '"+types.String(serverId)+"'")
  1073  				}
  1074  				newNodeConfig.RemoveServer(serverId)
  1075  			}
  1076  		}
  1077  
  1078  		if countUpdatingServers >= maxPrintServers {
  1079  			remotelogs.Debug("NODE", "reload "+types.String(countUpdatingServers)+" servers")
  1080  		}
  1081  
  1082  		err, serverErrors := newNodeConfig.Init(context.Background())
  1083  		if err != nil {
  1084  			remotelogs.Error("NODE", "apply server config error: "+err.Error())
  1085  			return
  1086  		}
  1087  		if len(serverErrors) > 0 {
  1088  			for _, serverErr := range serverErrors {
  1089  				remotelogs.ServerError(serverErr.Id, "NODE", serverErr.Message, nodeconfigs.NodeLogTypeServerConfigInitFailed, maps.Map{})
  1090  			}
  1091  		}
  1092  
  1093  		this.onReload(newNodeConfig, false)
  1094  
  1095  		err = sharedListenerManager.Start(newNodeConfig)
  1096  		if err != nil {
  1097  			remotelogs.Error("NODE", "apply server config error: "+err.Error())
  1098  		}
  1099  
  1100  		// notify event
  1101  		events.Notify(events.EventReloadSomeServers)
  1102  	}
  1103  }
  1104  
  1105  // 检查系统
  1106  func (this *Node) tuneSystemParameters() {
  1107  	if runtime.GOOS != "linux" || os.Getgid() != 0 {
  1108  		return
  1109  	}
  1110  
  1111  	if sharedNodeConfig == nil || !sharedNodeConfig.AutoSystemTuning {
  1112  		return
  1113  	}
  1114  
  1115  	type variable struct {
  1116  		name     string
  1117  		minValue int
  1118  		maxValue int
  1119  	}
  1120  
  1121  	const dir = "/proc/sys"
  1122  
  1123  	// net
  1124  	var systemParameters = []variable{
  1125  		{name: "net.core.somaxconn", minValue: 2048},
  1126  		{name: "net.ipv4.tcp_max_syn_backlog", minValue: 2048},
  1127  		{name: "net.core.netdev_max_backlog", minValue: 4096},
  1128  		{name: "net.ipv4.tcp_fin_timeout", maxValue: 10},
  1129  		{name: "net.ipv4.tcp_max_tw_buckets", minValue: 65535},
  1130  		{name: "net.core.rmem_default", minValue: 4 << 20},
  1131  		{name: "net.core.wmem_default", minValue: 4 << 20},
  1132  		{name: "net.core.rmem_max", minValue: 32 << 20},
  1133  		{name: "net.core.wmem_max", minValue: 32 << 20},
  1134  		{name: "vm.max_map_count", minValue: 256 << 10},
  1135  	}
  1136  
  1137  	// vm
  1138  	var systemMemory = memutils.SystemMemoryGB()
  1139  	if systemMemory >= 128 {
  1140  		systemParameters = append(systemParameters, []variable{
  1141  			{name: "vm.dirty_background_ratio", minValue: 40},
  1142  			{name: "vm.dirty_ratio", minValue: 60},
  1143  		}...)
  1144  	} else if systemMemory >= 64 {
  1145  		systemParameters = append(systemParameters, []variable{
  1146  			{name: "vm.dirty_background_ratio", minValue: 30},
  1147  			{name: "vm.dirty_ratio", minValue: 50},
  1148  		}...)
  1149  	} else if systemMemory >= 16 {
  1150  		systemParameters = append(systemParameters, []variable{
  1151  			{name: "vm.dirty_background_ratio", minValue: 15},
  1152  			{name: "vm.dirty_ratio", minValue: 30},
  1153  		}...)
  1154  	}
  1155  
  1156  	for _, v := range systemParameters {
  1157  		var path = dir + "/" + strings.Replace(v.name, ".", "/", -1)
  1158  		data, err := os.ReadFile(path)
  1159  		if err != nil {
  1160  			continue
  1161  		}
  1162  		data = bytes.TrimSpace(data)
  1163  		if len(data) == 0 {
  1164  			continue
  1165  		}
  1166  
  1167  		var oldValue = types.Int(string(data))
  1168  		if v.minValue > 0 && oldValue < v.minValue {
  1169  			err = os.WriteFile(path, []byte(types.String(v.minValue)), 0666)
  1170  			if err == nil {
  1171  				remotelogs.Println("NODE", "change kernel parameter '"+v.name+"' from '"+types.String(oldValue)+"' to '"+types.String(v.minValue)+"'")
  1172  			}
  1173  		} else if v.maxValue > 0 && oldValue > v.maxValue {
  1174  			err = os.WriteFile(path, []byte(types.String(v.maxValue)), 0666)
  1175  			if err == nil {
  1176  				remotelogs.Println("NODE", "change kernel parameter '"+v.name+"' from '"+types.String(oldValue)+"' to '"+types.String(v.maxValue)+"'")
  1177  			}
  1178  		}
  1179  	}
  1180  }
  1181  
  1182  // 检查API节点地址
  1183  func (this *Node) changeAPINodeAddrs(apiNodeAddrs []*serverconfigs.NetworkAddressConfig) {
  1184  	var addrs = []string{}
  1185  	for _, addr := range apiNodeAddrs {
  1186  		err := addr.Init()
  1187  		if err != nil {
  1188  			remotelogs.Error("NODE", "changeAPINodeAddrs: validate api node address '"+configutils.QuoteIP(addr.Host)+":"+addr.PortRange+"' failed: "+err.Error())
  1189  		} else {
  1190  			addrs = append(addrs, addr.FullAddresses()...)
  1191  		}
  1192  	}
  1193  	sort.Strings(addrs)
  1194  
  1195  	if utils.EqualStrings(this.lastAPINodeAddrs, addrs) {
  1196  		return
  1197  	}
  1198  
  1199  	this.lastAPINodeAddrs = addrs
  1200  
  1201  	config, err := configs.LoadAPIConfig()
  1202  	if err != nil {
  1203  		remotelogs.Error("NODE", "changeAPINodeAddrs: "+err.Error())
  1204  		return
  1205  	}
  1206  	if config == nil {
  1207  		return
  1208  	}
  1209  	var oldEndpoints = config.RPCEndpoints
  1210  
  1211  	rpcClient, err := rpc.SharedRPC()
  1212  	if err != nil {
  1213  		return
  1214  	}
  1215  	if len(addrs) > 0 {
  1216  		this.lastAPINodeVersion++
  1217  		var v = this.lastAPINodeVersion
  1218  
  1219  		// 异步检测,防止阻塞
  1220  		go func(v int64) {
  1221  			// 测试新的API节点地址
  1222  			if rpcClient.TestEndpoints(addrs) {
  1223  				config.RPCEndpoints = addrs
  1224  			} else {
  1225  				config.RPCEndpoints = oldEndpoints
  1226  				this.lastAPINodeAddrs = nil // 恢复为空,以便于下次更新重试
  1227  			}
  1228  
  1229  			// 检查测试中间有无新的变更
  1230  			if v != this.lastAPINodeVersion {
  1231  				return
  1232  			}
  1233  
  1234  			err = rpcClient.UpdateConfig(config)
  1235  			if err != nil {
  1236  				remotelogs.Error("NODE", "changeAPINodeAddrs: update rpc config failed: "+err.Error())
  1237  			}
  1238  		}(v)
  1239  		return
  1240  	}
  1241  
  1242  	err = rpcClient.UpdateConfig(config)
  1243  	if err != nil {
  1244  		remotelogs.Error("NODE", "changeAPINodeAddrs: update rpc config failed: "+err.Error())
  1245  	}
  1246  }