Repository: nacos-group/nacos-sdk-go (go)

Issue:
服务掉线后重新注册逻辑有误，可能导致服务丢失
假设连接断开，go sdk 会重新建连，建连后调用 `r.notifyConnectionChange(CONNECTED)` 触发服务重新注册；
重新注册如果失败，会调用 `r.switchServerAsync(ServerInfo{}, true)` ，最终调用到 `reconnect(serverInfo ServerInfo, onRequestFail bool)`，此时，如果健康检查通过，则不会调用 `r.notifyConnectionChange(CONNECTED)` 进而导致服务丢失；

该问题，我们生产环境真实发生，查阅代码，发现存在该风险，通过压测，发现注册 5 万 client 并重启 nacos server 后，无法恢复到 5 万，总是缺失几十个，这里不仅 client 有bug，nacos server 也有服务注册失败，吞掉异常，返回注册成功的 bug
简单点，建议做如下变更：
<img width="1410" alt="图片" src="https://github.com/nacos-group/nacos-sdk-go/assets/6041166/b76c2567-8437-47f1-bb2e-28cc55adc975">
新增 313 行，进而触发服务再次注册；如果健康检查失败，触发事件，再次 reconnect 前，发现健康检查通过，也将重新注册，如果需要优化这个，可加下判断，不过重新注册并没有啥问题。

Pull request:
fix #736, [掉线重连可能导致服务丢失](https://github.com/nacos-group/nacos-sdk-go/…
…issues/736)

Patch:
diff --git a/clients/config_client/config_proxy.go b/clients/config_client/config_proxy.go
index 18efa4a..f21a139 100644
--- a/clients/config_client/config_proxy.go
+++ b/clients/config_client/config_proxy.go
@@ -166,7 +166,7 @@ func (cp *ConfigProxy) createRpcClient(ctx context.Context, taskId string, clien
 		"taskId":                taskId,
 	}
 
-	iRpcClient, _ := rpc.CreateClient(ctx, "config-"+taskId+"-"+client.uid, rpc.GRPC, labels, cp.nacosServer)
+	iRpcClient, _ := rpc.CreateClient(ctx, "config-"+taskId+"-"+client.uid, rpc.GRPC, labels, cp.nacosServer, &cp.clientConfig.TLSCfg, cp.clientConfig.AppConnLabels)
 	rpcClient := iRpcClient.GetRpcClient()
 	if rpcClient.IsInitialized() {
 		rpcClient.RegisterServerRequestHandler(func() rpc_request.IRequest {
diff --git a/clients/naming_client/naming_cache/subscribe_callback.go b/clients/naming_client/naming_cache/subscribe_callback.go
index 1f4964d..1a7ba02 100644
--- a/clients/naming_client/naming_cache/subscribe_callback.go
+++ b/clients/naming_client/naming_cache/subscribe_callback.go
@@ -42,8 +42,8 @@ func (ed *SubscribeCallback) IsSubscribed(serviceName, clusters string) bool {
 
 func (ed *SubscribeCallback) AddCallbackFunc(serviceName string, clusters string, callbackFunc *func(services []model.Instance, err error)) {
 	key := util.GetServiceCacheKey(serviceName, clusters)
-	defer ed.mux.Unlock()
 	ed.mux.Lock()
+	defer ed.mux.Unlock()
 	var funcSlice []*func(services []model.Instance, err error)
 	old, ok := ed.callbackFuncMap.Get(key)
 	if ok {
diff --git a/clients/naming_client/naming_grpc/connection_event_listener.go b/clients/naming_client/naming_grpc/connection_event_listener.go
index c4f9937..2073a66 100644
--- a/clients/naming_client/naming_grpc/connection_event_listener.go
+++ b/clients/naming_client/naming_grpc/connection_event_listener.go
@@ -52,6 +52,11 @@ func (c *ConnectionEventListener) OnDisConnect() {
 }
 
 func (c *ConnectionEventListener) redoSubscribe() {
+	grpcProxy, ok := c.clientProxy.(*NamingGrpcProxy)
+	if !ok {
+		logger.Error("redo subscribe clientProxy type error")
+		return
+	}
 	for _, key := range c.subscribes.Keys() {
 		info := strings.Split(key, constant.SERVICE_INFO_SPLITER)
 		var err error
@@ -61,15 +66,9 @@ func (c *ConnectionEventListener) redoSubscribe() {
 		} else {
 			service, err = c.clientProxy.Subscribe(info[1], info[0], "")
 		}
-
 		if err != nil {
 			logger.Warnf("redo subscribe service:%s faild:%+v", info[1], err)
-			return
-		}
-
-		grpcProxy, ok := c.clientProxy.(*NamingGrpcProxy)
-		if !ok {
-			return
+			continue
 		}
 		grpcProxy.serviceInfoHolder.ProcessService(&service)
 	}
diff --git a/clients/naming_client/naming_grpc/naming_grpc_proxy.go b/clients/naming_client/naming_grpc/naming_grpc_proxy.go
index bc88539..39fd85f 100644
--- a/clients/naming_client/naming_grpc/naming_grpc_proxy.go
+++ b/clients/naming_client/naming_grpc/naming_grpc_proxy.go
@@ -61,7 +61,7 @@ func NewNamingGrpcProxy(ctx context.Context, clientCfg constant.ClientConfig, na
 		constant.LABEL_MODULE: constant.LABEL_MODULE_NAMING,
 	}
 
-	iRpcClient, err := rpc.CreateClient(ctx, uid.String(), rpc.GRPC, labels, srvProxy.nacosServer)
+	iRpcClient, err := rpc.CreateClient(ctx, uid.String(), rpc.GRPC, labels, srvProxy.nacosServer, &clientCfg.TLSCfg, clientCfg.AppConnLabels)
 	if err != nil {
 		return nil, err
 	}
diff --git a/common/constant/client_config_options.go b/common/constant/client_config_options.go
index 75b2cbf..7befcff 100644
--- a/common/constant/client_config_options.go
+++ b/common/constant/client_config_options.go
@@ -222,6 +222,13 @@ func WithLogRollingConfig(rollingConfig *ClientLogRollingConfig) ClientOption {
 
 func WithTLS(tlsCfg TLSConfig) ClientOption {
 	return func(config *ClientConfig) {
+		tlsCfg.Appointed = true
 		config.TLSCfg = tlsCfg
 	}
 }
+
+func WithAppConnLabels(appConnLabels map[string]string) ClientOption {
+	return func(config *ClientConfig) {
+		config.AppConnLabels = appConnLabels
+	}
+}
diff --git a/common/constant/config.go b/common/constant/config.go
index 478c457..0d5998e 100644
--- a/common/constant/config.go
+++ b/common/constant/config.go
@@ -58,6 +58,7 @@ type ClientConfig struct {
 	EndpointContextPath  string                   // the address server  endpoint contextPath
 	EndpointQueryParams  string                   // the address server  endpoint query params
 	ClusterName          string                   // the address server  clusterName
+	AppConnLabels        map[string]string        // app conn labels
 }
 
 type ClientLogSamplingConfig struct {
@@ -94,7 +95,9 @@ type ClientLogRollingConfig struct {
 }
 
 type TLSConfig struct {
+	Appointed          bool   // Appointed or not ,if false,will get from env.
 	Enable             bool   // enable tls
+	TrustAll           bool   // trust all server
 	CaFile             string // clients use when verifying server certificates
 	CertFile           string // server use when verifying client certificates
 	KeyFile            string // server use when verifying client certificates
diff --git a/common/constant/const.go b/common/constant/const.go
index 73c8fd5..cc9375b 100644
--- a/common/constant/const.go
+++ b/common/constant/const.go
@@ -76,7 +76,7 @@ const (
 	KEY_BEAT                    = "beat"
 	KEY_DOM                     = "dom"
 	DEFAULT_CONTEXT_PATH        = "/nacos"
-	CLIENT_VERSION              = "Nacos-Go-Client:v2.2.4"
+	CLIENT_VERSION              = "Nacos-Go-Client:v2.2.6"
 	REQUEST_DOMAIN_RETRY_TIME   = 3
 	SERVICE_INFO_SPLITER        = "@@"
 	CONFIG_INFO_SPLITER         = "@@"
diff --git a/common/logger/logger.go b/common/logger/logger.go
index b154fef..f0d5110 100644
--- a/common/logger/logger.go
+++ b/common/logger/logger.go
@@ -118,9 +118,6 @@ func BuildLoggerConfig(clientConfig constant.ClientConfig) Config {
 func InitLogger(config Config) (err error) {
 	logLock.Lock()
 	defer logLock.Unlock()
-	if logger != nil {
-		return
-	}
 	logger, err = InitNacosLogger(config)
 	return
 }
diff --git a/common/nacos_server/nacos_server.go b/common/nacos_server/nacos_server.go
index 75e230c..fcd3c99 100644
--- a/common/nacos_server/nacos_server.go
+++ b/common/nacos_server/nacos_server.go
@@ -92,13 +92,13 @@ func NewNacosServer(ctx context.Context, serverList []constant.ServerConfig, cli
 		ns.initRefreshSrvIfNeed(ctx)
 	}
 
-	_, err := securityLogin.Login()
+	_, err := ns.securityLogin.Login()
 
 	if err != nil {
 		logger.Errorf("login in err:%v", err)
 	}
 
-	securityLogin.AutoRefresh(ctx)
+	ns.securityLogin.AutoRefresh(ctx)
 	return &ns, nil
 }
 
@@ -344,6 +344,7 @@ func (server *NacosServer) refreshServerSrvIfNeed(urlString string, header map[s
 				server.ServerSrcChangeSignal <- struct{}{}
 			}
 			server.lastSrvRefTime = util.CurrentMillis()
+			server.securityLogin.UpdateServerList(servers)
 			server.Unlock()
 		}
 
diff --git a/common/remote/rpc/grpc_client.go b/common/remote/rpc/grpc_client.go
index 9037201..eba40c1 100644
--- a/common/remote/rpc/grpc_client.go
+++ b/common/remote/rpc/grpc_client.go
@@ -18,8 +18,13 @@ package rpc
 
 import (
 	"context"
+	"crypto/tls"
+	"crypto/x509"
 	"encoding/json"
+	"fmt"
+	"google.golang.org/grpc/credentials"
 	"io"
+	"log"
 	"os"
 	"strconv"
 	"sync"
@@ -41,9 +46,10 @@ import (
 
 type GrpcClient struct {
 	*RpcClient
+	*constant.TLSConfig
 }
 
-func NewGrpcClient(ctx context.Context, clientName string, nacosServer *nacos_server.NacosServer) *GrpcClient {
+func NewGrpcClient(ctx context.Context, clientName string, nacosServer *nacos_server.NacosServer, tlsConfig *constant.TLSConfig) *GrpcClient {
 	rpcClient := &GrpcClient{
 		&RpcClient{
 			ctx:              ctx,
@@ -54,7 +60,7 @@ func NewGrpcClient(ctx context.Context, clientName string, nacosServer *nacos_se
 			reconnectionChan: make(chan ReconnectContext, 1),
 			nacosServer:      nacosServer,
 			mux:              new(sync.Mutex),
-		},
+		}, tlsConfig,
 	}
 	rpcClient.RpcClient.lastActiveTimestamp.Store(time.Now())
 	rpcClient.executeClient = rpcClient
@@ -87,6 +93,41 @@ func getInitialConnWindowSize() int32 {
 	return int32(initialConnWindowSize)
 }
 
+func getTLSCredentials(tlsConfig *constant.TLSConfig, serverInfo ServerInfo) credentials.TransportCredentials {
+
+	logger.Infof("build tls config for connecting to server %s,tlsConfig = %s", serverInfo.serverIp, tlsConfig)
+
+	certPool, err := x509.SystemCertPool()
+	if err != nil {
+		log.Fatalf("load root cert pool fail : %v", err)
+	}
+	if len(tlsConfig.CaFile) != 0 {
+		cert, err := os.ReadFile(tlsConfig.CaFile)
+		if err != nil {
+			fmt.Errorf("err, %v", err)
+		}
+		if ok := certPool.AppendCertsFromPEM(cert); !ok {
+			fmt.Errorf("failed to append ca certs")
+		}
+	}
+
+	config := tls.Config{
+		InsecureSkipVerify: tlsConfig.TrustAll,
+		RootCAs:            certPool,
+		Certificates:       []tls.Certificate{},
+	}
+	if len(tlsConfig.CertFile) != 0 && len(tlsConfig.KeyFile) != 0 {
+		cert, err := tls.LoadX509KeyPair(tlsConfig.CertFile, tlsConfig.KeyFile)
+
+		if err != nil {
+			log.Fatalf("load cert fail : %v", err)
+		}
+		config.Certificates = append(config.Certificates, cert)
+	}
+	credentials := credentials.NewTLS(&config)
+	return credentials
+}
+
 func getInitialGrpcTimeout() int32 {
 	initialGrpcTimeout, err := strconv.Atoi(os.Getenv("nacos.remote.client.grpc.timeout"))
 	if err != nil {
@@ -117,6 +158,11 @@ func (c *GrpcClient) createNewConnection(serverInfo ServerInfo) (*grpc.ClientCon
 	opts = append(opts, grpc.WithInsecure())
 	opts = append(opts, grpc.WithInitialWindowSize(getInitialWindowSize()))
 	opts = append(opts, grpc.WithInitialConnWindowSize(getInitialConnWindowSize()))
+	c.getEnvTLSConfig(c.TLSConfig)
+	if c.TLSConfig.Enable {
+		logger.Infof(" tls enable ,trying to connection to server %s with tls config %s", serverInfo.serverIp, c.TLSConfig)
+		opts = append(opts, grpc.WithTransportCredentials(getTLSCredentials(c.TLSConfig, serverInfo)))
+	}
 	rpcPort := serverInfo.serverGrpcPort
 	if rpcPort == 0 {
 		rpcPort = serverInfo.serverPort + c.rpcPortOffset()
@@ -125,6 +171,39 @@ func (c *GrpcClient) createNewConnection(serverInfo ServerInfo) (*grpc.ClientCon
 
 }
 
+func (c *GrpcClient) getEnvTLSConfig(config *constant.TLSConfig) {
+	logger.Infof("check tls config ", config)
+
+	if config.Appointed == true {
+		return
+	}
+	logger.Infof("try to get tls config from env")
+
+	enableTls, err := strconv.ParseBool(os.Getenv("nacos_remote_client_rpc_tls_enable"))
+	if err == nil {
+		config.Enable = enableTls
+		logger.Infof("get tls config from env ，key = enableTls value = %s", enableTls)
+	}
+
+	if enableTls != true {
+		logger.Infof(" tls config from env is not enable")
+		return
+	}
+	trustAll, err := strconv.ParseBool(os.Getenv("nacos_remote_client_rpc_tls_trustAll"))
+	if err == nil {
+		config.TrustAll = trustAll
+		logger.Infof("get tls config from env ，key = trustAll value = %s", trustAll)
+	}
+
+	config.CaFile = os.Getenv("nacos_remote_client_rpc_tls_trustCollectionChainPath")
+	logger.Infof("get tls config from env ，key = trustCollectionChainPath value = %s", config.CaFile)
+	config.CertFile = os.Getenv("nacos_remote_client_rpc_tls_certChainFile")
+	logger.Infof("get tls config from env ，key = certChainFile value = %s", config.CertFile)
+	config.KeyFile = os.Getenv("nacos_remote_client_rpc_tls_certPrivateKey")
+	logger.Infof("get tls config from env ，key = certPrivateKey value = %s", config.KeyFile)
+
+}
+
 func (c *GrpcClient) connectToServer(serverInfo ServerInfo) (IConnection, error) {
 	var client nacos_grpc_service.RequestClient
 	var biStreamClient nacos_grpc_service.BiRequestStreamClient
@@ -180,6 +259,7 @@ func (c *GrpcClient) bindBiRequestStream(streamClient nacos_grpc_service.BiReque
 		for {
 			select {
 			case <-streamClient.Context().Done():
+				logger.Warnf("connectionId %s stream client close", grpcConn.getConnectionId())
 				return
 			default:
 				payload, err := streamClient.Recv()
@@ -197,7 +277,7 @@ func (c *GrpcClient) bindBiRequestStream(streamClient nacos_grpc_service.BiReque
 							return
 						}
 					} else {
-						logger.Infof("connectionId %s received error event, isRunning:%v, isAbandon=%v, error=%v", grpcConn.getConnectionId(), running, abandon, err)
+						logger.Errorf("connectionId %s received error event, isRunning:%v, isAbandon=%v, error=%v", grpcConn.getConnectionId(), running, abandon, err)
 						return
 					}
 				} else {
diff --git a/common/remote/rpc/grpc_connection.go b/common/remote/rpc/grpc_connection.go
index 3bb9bf2..30d808e 100644
--- a/common/remote/rpc/grpc_connection.go
+++ b/common/remote/rpc/grpc_connection.go
@@ -18,6 +18,7 @@ package rpc
 
 import (
 	"context"
+	"github.com/nacos-group/nacos-sdk-go/v2/common/logger"
 	"time"
 
 	"github.com/golang/protobuf/ptypes/any"
@@ -55,15 +56,17 @@ func (g *GrpcConnection) request(request rpc_request.IRequest, timeoutMills int6
 	defer cancel()
 	responsePayload, err := g.client.Request(ctx, p)
 	if err != nil {
+		logger.Debugf("%s grpc request nacos server failed, request=%+v, err=%v ", g.getConnectionId(), p, err)
 		return nil, err
 	}
 
 	responseFunc, ok := rpc_response.ClientResponseMapping[responsePayload.Metadata.GetType()]
-
 	if !ok {
 		return nil, errors.Errorf("request:%s,unsupported response type:%s", request.GetRequestType(),
 			responsePayload.Metadata.GetType())
 	}
+
+	logger.Debugf("%s grpc request nacos server success, request=%+v, response=%s", g.getConnectionId(), p, string(responsePayload.GetBody().Value))
 	return rpc_response.InnerResponseJsonUnmarshal(responsePayload.GetBody().Value, responseFunc)
 }
 
diff --git a/common/remote/rpc/rpc_client.go b/common/remote/rpc/rpc_client.go
index 06d8b48..634eacf 100644
--- a/common/remote/rpc/rpc_client.go
+++ b/common/remote/rpc/rpc_client.go
@@ -18,8 +18,11 @@ package rpc
 
 import (
 	"context"
+	"fmt"
 	"math"
+	"os"
 	"reflect"
+	"strings"
 	"sync"
 	"sync/atomic"
 	"time"
@@ -147,17 +150,31 @@ func getClient(clientName string) IRpcClient {
 	return clientMap[clientName]
 }
 
-func CreateClient(ctx context.Context, clientName string, connectionType ConnectionType, labels map[string]string, nacosServer *nacos_server.NacosServer) (IRpcClient, error) {
+func CreateClient(ctx context.Context, clientName string, connectionType ConnectionType, labels map[string]string, nacosServer *nacos_server.NacosServer, tlsConfig *constant.TLSConfig, appConnLabels map[string]string) (IRpcClient, error) {
 	cMux.Lock()
 	defer cMux.Unlock()
 	if _, ok := clientMap[clientName]; !ok {
+		logger.Infof("init rpc client for name ", clientName)
 		var rpcClient IRpcClient
 		if GRPC == connectionType {
-			rpcClient = NewGrpcClient(ctx, clientName, nacosServer)
+			rpcClient = NewGrpcClient(ctx, clientName, nacosServer, tlsConfig)
 		}
 		if rpcClient == nil {
 			return nil, errors.New("unsupported connection type")
 		}
+
+		logger.Infof("get app conn labels from client config %v ", appConnLabels)
+		appConnLabelsEnv := getAppLabelsFromEnv()
+		logger.Infof("get app conn labels from env %v ", appConnLabelsEnv)
+
+		appConnLabelsFinal := mergerAppLabels(appConnLabels, appConnLabelsEnv)
+		logger.Infof("final app conn labels : %v ", appConnLabelsFinal)
+
+		appConnLabelsFinal = addPrefixForEachKey(appConnLabelsFinal, "app_")
+		if len(appConnLabelsFinal) != 0 {
+			rpcClient.putAllLabels(appConnLabelsFinal)
+		}
+
 		rpcClient.putAllLabels(labels)
 		clientMap[clientName] = rpcClient
 		return rpcClient, nil
@@ -165,6 +182,92 @@ func CreateClient(ctx context.Context, clientName string, connectionType Connect
 	return clientMap[clientName], nil
 }
 
+func mergerAppLabels(appLabelsAppointed map[string]string, appLabelsEnv map[string]string) map[string]string {
+	preferred := strings.ToLower(os.Getenv("nacos_app_conn_labels_preferred"))
+
+	var preferFirst bool
+	if preferred != "env" {
+		preferFirst = true
+	} else {
+		preferFirst = false
+	}
+	return mergeMaps(appLabelsAppointed, appLabelsEnv, preferFirst)
+}
+
+func mergeMaps(map1, map2 map[string]string, preferFirst bool) map[string]string {
+	result := make(map[string]string, 8)
+
+	for k, v := range map1 {
+		result[k] = v
+	}
+
+	for k, v := range map2 {
+		_, ok := map1[k]
+		if preferFirst && ok {
+			continue
+		}
+		result[k] = v
+	}
+
+	return result
+}
+
+func getAppLabelsFromEnv() map[string]string {
+	configMap := make(map[string]string, 8)
+
+	// nacos_config_gray_label
+	grayLabel := os.Getenv("nacos_config_gray_label")
+	if grayLabel != "" {
+		configMap["nacos_config_gray_label"] = grayLabel
+	}
+
+	// nacos_app_conn_labels
+	connLabels := os.Getenv("nacos_app_conn_labels")
+	if connLabels != "" {
+		labelsMap := parseLabels(connLabels)
+		for k, v := range labelsMap {
+			configMap[k] = v
+		}
+	}
+
+	return configMap
+}
+
+func parseLabels(rawLabels string) map[string]string {
+	if strings.TrimSpace(rawLabels) == "" {
+		return make(map[string]string, 2)
+	}
+
+	resultMap := make(map[string]string, 2)
+	labels := strings.Split(rawLabels, ",")
+	for _, label := range labels {
+		if strings.TrimSpace(label) != "" {
+			kv := strings.Split(label, "=")
+			if len(kv) == 2 {
+				resultMap[strings.TrimSpace(kv[0])] = strings.TrimSpace(kv[1])
+			} else {
+				fmt.Println("unknown label format:", label)
+			}
+		}
+	}
+	return resultMap
+}
+
+func addPrefixForEachKey(m map[string]string, prefix string) map[string]string {
+	if len(m) == 0 {
+		return m
+	}
+
+	newMap := make(map[string]string, len(m))
+	for k, v := range m {
+		if strings.TrimSpace(k) != "" {
+			newKey := prefix + k
+			newMap[newKey] = v
+		}
+	}
+	return newMap
+}
+
 func (r *RpcClient) Start() {
 	if ok := atomic.CompareAndSwapInt32((*int32)(&r.rpcClientStatus), (int32)(INITIALIZED), (int32)(STARTING)); !ok {
 		return
@@ -310,6 +413,7 @@ func (r *RpcClient) reconnect(serverInfo ServerInfo, onRequestFail bool) {
 	if onRequestFail && r.sendHealthCheck() {
 		logger.Infof("%s server check success, currentServer is %+v", r.name, r.currentConnection.getServerInfo())
 		atomic.StoreInt32((*int32)(&r.rpcClientStatus), (int32)(RUNNING))
+		r.notifyConnectionChange(CONNECTED)
 		return
 	}
 	var (
diff --git a/common/remote/rpc/rpc_request/rpc_request.go b/common/remote/rpc/rpc_request/rpc_request.go
index 041bba1..c1146c6 100644
--- a/common/remote/rpc/rpc_request/rpc_request.go
+++ b/common/remote/rpc/rpc_request/rpc_request.go
@@ -39,6 +39,9 @@ type IConfigRequest interface {
 }
 
 func (r *Request) PutAllHeaders(headers map[string]string) {
+	if r.Headers == nil {
+		r.Headers = make(map[string]string)
+	}
 	for k, v := range headers {
 		r.Headers[k] = v
 	}
diff --git a/common/remote/rpc/server_request_handler.go b/common/remote/rpc/server_request_handler.go
index 7d6384a..03e6cad 100644
--- a/common/remote/rpc/server_request_handler.go
+++ b/common/remote/rpc/server_request_handler.go
@@ -87,10 +87,12 @@ func (*NamingPushRequestHandler) Name() string {
 	return "NamingPushRequestHandler"
 }
 
-func (c *NamingPushRequestHandler) RequestReply(request rpc_request.IRequest, _ *RpcClient) rpc_response.IResponse {
+func (c *NamingPushRequestHandler) RequestReply(request rpc_request.IRequest, client *RpcClient) rpc_response.IResponse {
 	notifySubscriberRequest, ok := request.(*rpc_request.NotifySubscriberRequest)
 	if ok {
 		c.ServiceInfoHolder.ProcessService(&notifySubscriberRequest.ServiceInfo)
+		logger.Debugf("%s naming push response success ackId->%s", client.currentConnection.getConnectionId(),
+			request.GetRequestId())
 		return &rpc_response.NotifySubscriberResponse{
 			Response: &rpc_response.Response{ResultCode: constant.RESPONSE_CODE_SUCCESS, Success: true},
 		}
diff --git a/common/security/security_proxy.go b/common/security/security_proxy.go
index eb6d579..c175525 100644
--- a/common/security/security_proxy.go
+++ b/common/security/security_proxy.go
@@ -112,6 +112,14 @@ func (ac *AuthClient) Login() (bool, error) {
 	return false, throwable
 }
 
+func (ac *AuthClient) UpdateServerList(serverList []constant.ServerConfig) {
+	ac.serverCfgs = serverList
+}
+
+func (ac *AuthClient) GetServerList() []constant.ServerConfig {
+	return ac.serverCfgs
+}
+
 func (ac *AuthClient) login(server constant.ServerConfig) (bool, error) {
 	if ac.username != "" {
 		contextPath := server.ContextPath
diff --git a/go.mod b/go.mod
index 09d8efb..6eb2f96 100644
--- a/go.mod
+++ b/go.mod
@@ -40,12 +40,12 @@ require (
 	github.com/prometheus/procfs v0.7.3 // indirect
 	go.uber.org/atomic v1.7.0 // indirect
 	go.uber.org/multierr v1.6.0 // indirect
-	golang.org/x/crypto v0.17.0 // indirect
-	golang.org/x/net v0.17.0 // indirect
-	golang.org/x/sys v0.15.0 // indirect
+	golang.org/x/crypto v0.21.0 // indirect
+	golang.org/x/net v0.23.0 // indirect
+	golang.org/x/sys v0.18.0 // indirect
 	golang.org/x/text v0.14.0 // indirect
 	google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
-	google.golang.org/protobuf v1.30.0 // indirect
+	google.golang.org/protobuf v1.33.0 // indirect
 	gopkg.in/ini.v1 v1.66.2 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
 )
diff --git a/go.sum b/go.sum
index a161490..d31b968 100644
--- a/go.sum
+++ b/go.sum
@@ -249,8 +249,8 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
-golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
+golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
+golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -312,8 +312,8 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R
 golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
 golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
 golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
-golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
+golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
+golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -370,8 +370,8 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
-golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
+golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -511,8 +511,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
 google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
 google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
-google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
+google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=


Test patch:
diff --git a/clients/config_client/config_client_test.go b/clients/config_client/config_client_test.go
index fd8ede3..dc86c06 100644
--- a/clients/config_client/config_client_test.go
+++ b/clients/config_client/config_client_test.go
@@ -34,7 +34,7 @@ import (
 	"github.com/stretchr/testify/assert"
 )
 
-var serverConfigWithOptions = constant.NewServerConfig("mse-xxx.mse.aliyuncs.com", 8848)
+var serverConfigWithOptions = constant.NewServerConfig("127.0.0.1", 8848)
 
 var clientConfigWithOptions = constant.NewClientConfig(
 	constant.WithTimeoutMs(10*1000),
@@ -47,6 +47,18 @@ var clientConfigWithOptions = constant.NewClientConfig(
 	constant.WithRegionId("cn-hangzhou"),
 )
 
+var clientTLsConfigWithOptions = constant.NewClientConfig(
+	constant.WithTimeoutMs(10*1000),
+	constant.WithBeatInterval(2*1000),
+	constant.WithNotLoadCacheAtStart(true),
+
+	/*constant.WithTLS(constant.TLSConfig{
+		Enable:   true,
+		TrustAll: false,
+		CaFile:   "mse-nacos-ca.cer",
+	}),*/
+)
+
 var localConfigTest = vo.ConfigParam{
 	DataId:  "dataId",
 	Group:   "group",
@@ -63,12 +75,23 @@ func createConfigClientTest() *ConfigClient {
 	return client
 }
 
+func createConfigClientTestTls() *ConfigClient {
+	nc := nacos_client.NacosClient{}
+	_ = nc.SetServerConfig([]constant.ServerConfig{*serverConfigWithOptions})
+	_ = nc.SetClientConfig(*clientTLsConfigWithOptions)
+	_ = nc.SetHttpAgent(&http_agent.HttpAgent{})
+	client, _ := NewConfigClient(&nc)
+	client.configProxy = &MockConfigProxy{}
+	return client
+}
+
 func createConfigClientCommon() *ConfigClient {
 	nc := nacos_client.NacosClient{}
 	_ = nc.SetServerConfig([]constant.ServerConfig{*serverConfigWithOptions})
 	_ = nc.SetClientConfig(*clientConfigWithOptions)
 	_ = nc.SetHttpAgent(&http_agent.HttpAgent{})
 	client, _ := NewConfigClient(&nc)
+	client.configProxy = &MockConfigProxy{}
 	return client
 }
 
@@ -148,6 +171,24 @@ func Test_SearchConfig(t *testing.T) {
 	assert.NotEmpty(t, configPage)
 }
 
+func Test_GetConfigTls(t *testing.T) {
+	client := createConfigClientTestTls()
+	_, _ = client.PublishConfig(vo.ConfigParam{
+		DataId:  localConfigTest.DataId,
+		Group:   "DEFAULT_GROUP",
+		Content: "hello world"})
+	configPage, err := client.SearchConfig(vo.SearchConfigParam{
+		Search:   "accurate",
+		DataId:   localConfigTest.DataId,
+		Group:    "DEFAULT_GROUP",
+		PageNo:   1,
+		PageSize: 10,
+	})
+	assert.Nil(t, err)
+	assert.NotEmpty(t, configPage)
+
+}
+
 // only using by ak sk for cipher config of aliyun kms
 /*
 func TestPublishAndGetConfigByUsingLocalCache(t *testing.T) {
diff --git a/common/logger/logger_test.go b/common/logger/logger_test.go
index 0fc8715..033511a 100644
--- a/common/logger/logger_test.go
+++ b/common/logger/logger_test.go
@@ -40,18 +40,13 @@ func TestGetLogger(t *testing.T) {
 	// not yet init get default log
 	log := GetLogger()
 	config := Config{
-		Level: "degug",
+		Level: "debug",
 	}
 	_ = InitLogger(config)
 	// after init logger
 	log2 := GetLogger()
 	assert.NotEqual(t, log, log2)
 
-	// the secend init logger
-	config.Level = "info"
-	_ = InitLogger(config)
-	log3 := GetLogger()
-	assert.NotEqual(t, log2, log3)
 	reset()
 }
 
@@ -66,13 +61,6 @@ func TestSetLogger(t *testing.T) {
 	assert.NotEqual(t, log, log2)
 	assert.Equal(t, log1, log2)
 
-	config := Config{
-		Level: "degug",
-	}
-	_ = InitLogger(config)
-	// after init logger
-	log3 := GetLogger()
-	assert.NotEqual(t, log2, log3)
 	reset()
 }
 
diff --git a/common/nacos_server/nacos_server_test.go b/common/nacos_server/nacos_server_test.go
index f35f6b3..9d54142 100644
--- a/common/nacos_server/nacos_server_test.go
+++ b/common/nacos_server/nacos_server_test.go
@@ -156,3 +156,27 @@ func TestNacosServer_InjectSignForNamingHttp_WithoutServiceNameAndGroup(t *testi
 	_, has := param["signature"]
 	assert.True(t, has)
 }
+
+func TestNacosServer_UpdateServerListForSecurityLogin(t *testing.T) {
+	endpoint := "console.nacos.io:80"
+	clientConfig := constant.ClientConfig{
+		Username:            "nacos",
+		Password:            "nacos",
+		NamespaceId:         "namespace_1",
+		Endpoint:            endpoint,
+		EndpointContextPath: "nacos",
+		ClusterName:         "serverlist",
+		AppendToStdout:      true,
+	}
+	server, err := NewNacosServer(context.Background(),
+		nil,
+		clientConfig,
+		&http_agent.HttpAgent{},
+		1000,
+		endpoint,
+		nil)
+	if err != nil {
+		t.FailNow()
+	}
+	assert.Equal(t, server.GetServerList(), server.securityLogin.GetServerList())
+}