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 }