github.com/polarismesh/polaris@v1.17.8/apiserver/eurekaserver/server.go (about)

     1  /**
     2   * Tencent is pleased to support the open source community by making Polaris available.
     3   *
     4   * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
     5   *
     6   * Licensed under the BSD 3-Clause License (the "License");
     7   * you may not use this file except in compliance with the License.
     8   * You may obtain a copy of the License at
     9   *
    10   * https://opensource.org/licenses/BSD-3-Clause
    11   *
    12   * Unless required by applicable law or agreed to in writing, software distributed
    13   * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
    14   * CONDITIONS OF ANY KIND, either express or implied. See the License for the
    15   * specific language governing permissions and limitations under the License.
    16   */
    17  
    18  package eurekaserver
    19  
    20  import (
    21  	"context"
    22  	"errors"
    23  	"fmt"
    24  	"net"
    25  	"net/http"
    26  	"strconv"
    27  	"strings"
    28  	"time"
    29  
    30  	"github.com/emicklei/go-restful/v3"
    31  	"go.uber.org/zap"
    32  
    33  	"github.com/polarismesh/polaris/apiserver"
    34  	"github.com/polarismesh/polaris/common/conn/keepalive"
    35  	connlimit "github.com/polarismesh/polaris/common/conn/limit"
    36  	"github.com/polarismesh/polaris/common/eventhub"
    37  	"github.com/polarismesh/polaris/common/metrics"
    38  	"github.com/polarismesh/polaris/common/secure"
    39  	"github.com/polarismesh/polaris/common/utils"
    40  	"github.com/polarismesh/polaris/plugin"
    41  	"github.com/polarismesh/polaris/service"
    42  	"github.com/polarismesh/polaris/service/healthcheck"
    43  )
    44  
    45  const (
    46  	SecureProtocol   = "HTTPS"
    47  	InsecureProtocol = "HTTP"
    48  
    49  	MetadataRegisterFrom        = "internal-register-from"
    50  	MetadataAppGroupName        = "internal-eureka-app-group"
    51  	MetadataCountryId           = "internal-eureka-country-id"
    52  	MetadataDataCenterInfoClazz = "internal-eureka-dci-clazz"
    53  	MetadataDataCenterInfoName  = "internal-eureka-dci-name"
    54  	MetadataHostName            = "internal-eureka-hostname"
    55  	MetadataRenewalInterval     = "internal-eureka-renewal-interval"
    56  	MetadataDuration            = "internal-eureka-duration"
    57  	MetadataHomePageUrl         = "internal-eureka-home-url"
    58  	MetadataStatusPageUrl       = "internal-eureka-status-url"
    59  	MetadataHealthCheckUrl      = "internal-eureka-health-url"
    60  	MetadataVipAddress          = "internal-eureka-vip"
    61  	MetadataSecureVipAddress    = "internal-eureka-secure-vip"
    62  	MetadataInsecurePort        = "internal-eureka-insecure-port"
    63  	MetadataInsecurePortEnabled = "internal-eureka-insecure-port-enabled"
    64  	MetadataSecurePort          = "internal-eureka-secure-port"
    65  	MetadataSecurePortEnabled   = "internal-eureka-secure-port-enabled"
    66  	MetadataReplicate           = "internal-eureka-replicate"
    67  	MetadataInstanceId          = "internal-eureka-instance-id"
    68  
    69  	InternalMetadataStatus           = "internal-eureka-status"
    70  	InternalMetadataOverriddenStatus = "internal-eureka-overriddenStatus"
    71  
    72  	ServerEureka = "eureka"
    73  
    74  	KeyRegion = "region"
    75  	keyZone   = "zone"
    76  	keyCampus = "campus"
    77  
    78  	StatusOutOfService = "OUT_OF_SERVICE"
    79  	StatusUp           = "UP"
    80  	StatusDown         = "DOWN"
    81  	StatusUnknown      = "UNKNOWN"
    82  
    83  	ActionAdded    = "ADDED"
    84  	ActionModified = "MODIFIED"
    85  	ActionDeleted  = "DELETED"
    86  
    87  	DefaultCountryIdInt            = 1
    88  	DefaultDciClazz                = "com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo"
    89  	DefaultDciName                 = "MyOwn"
    90  	DefaultRenewInterval           = 30
    91  	DefaultDuration                = 90
    92  	DefaultUnhealthyExpireInterval = 180
    93  
    94  	DefaultOwner        = "polaris"
    95  	DefaultSSLPort      = 443
    96  	DefaultInsecurePort = 8080
    97  
    98  	operationRegister           = "POST:/eureka/apps/{application}"
    99  	operationDeregister         = "DELETE:/eureka/apps/{application}/{instanceId}"
   100  	operationHeartbeat          = "PUT:/eureka/apps/{application}/{instanceId}"
   101  	operationAllInstances       = "GET:/eureka/apps"
   102  	operationDelta              = "GET:/eureka/apps/delta"
   103  	operationAllAppIDInstances  = "GET:/eureka/apps/{application}"
   104  	operationAppIDInstance      = "GET:/eureka/apps/{application}/{instanceId}"
   105  	operationStatusChange       = "PUT:/eureka/apps/{application}/{instanceId}/status"
   106  	operationDeleteStatusChange = "DELETE:/eureka/apps/{application}/{instanceId}/status"
   107  
   108  	pathPrefix   = "/eureka/apps"
   109  	statusSuffix = "/status"
   110  
   111  	statusCodeHeader = utils.PolarisCode
   112  
   113  	CustomKeyDciClass = "dataCenterInfoClass"
   114  	CustomKeyDciName  = "dataCenterInfoName"
   115  )
   116  
   117  var (
   118  	DefaultDataCenterInfo = &DataCenterInfo{
   119  		Clazz: DefaultDciClazz,
   120  		Name:  DefaultDciName,
   121  	}
   122  	DefaultCountryId = strconv.Itoa(DefaultCountryIdInt)
   123  
   124  	CustomEurekaParameters = make(map[string]string)
   125  )
   126  
   127  // EurekaServer is the Eureka server
   128  type EurekaServer struct {
   129  	server                 *http.Server
   130  	namingServer           service.DiscoverServer
   131  	originDiscoverSvr      service.DiscoverServer
   132  	healthCheckServer      *healthcheck.Server
   133  	connLimitConfig        *connlimit.Config
   134  	tlsInfo                *secure.TLSInfo
   135  	option                 map[string]interface{}
   136  	openAPI                map[string]apiserver.APIConfig
   137  	workers                *ApplicationsWorkers
   138  	listenPort             uint32
   139  	listenIP               string
   140  	exitCh                 chan struct{}
   141  	start                  bool
   142  	restart                bool
   143  	rateLimit              plugin.Ratelimit
   144  	statis                 plugin.Statis
   145  	namespace              string
   146  	refreshInterval        time.Duration
   147  	deltaExpireInterval    time.Duration
   148  	enableSelfPreservation bool
   149  	replicateWorkers       *ReplicateWorkers
   150  	eventHandlerHandler    *EurekaInstanceEventHandler
   151  
   152  	replicatePeers       map[string][]string
   153  	generateUniqueInstId bool
   154  	subCtxs              []*eventhub.SubscribtionContext
   155  
   156  	allowAsyncRegis bool
   157  }
   158  
   159  // GetPort 获取端口
   160  func (h *EurekaServer) GetPort() uint32 {
   161  	return h.listenPort
   162  }
   163  
   164  // GetProtocol 获取协议
   165  func (h *EurekaServer) GetProtocol() string {
   166  	return ServerEureka
   167  }
   168  
   169  // Initialize 初始化HTTP API服务器
   170  func (h *EurekaServer) Initialize(ctx context.Context, option map[string]interface{},
   171  	api map[string]apiserver.APIConfig) error {
   172  	if ipValue, ok := option[optionListenIP]; ok {
   173  		h.listenIP = ipValue.(string)
   174  	} else {
   175  		h.listenIP = DefaultListenIP
   176  	}
   177  	if portValue, ok := option[optionListenPort]; ok {
   178  		h.listenPort = uint32(portValue.(int))
   179  	} else {
   180  		h.listenPort = uint32(DefaultListenPort)
   181  	}
   182  	h.option = option
   183  	h.openAPI = api
   184  	h.subCtxs = make([]*eventhub.SubscribtionContext, 0, 4)
   185  	h.allowAsyncRegis = true
   186  
   187  	var namespace = DefaultNamespace
   188  	if namespaceValue, ok := option[optionNamespace]; ok {
   189  		theNamespace := namespaceValue.(string)
   190  		if len(theNamespace) > 0 {
   191  			namespace = theNamespace
   192  		}
   193  	}
   194  	h.namespace = namespace
   195  
   196  	if replicatePeersValue, ok := option[optionPeerNodesToReplicate]; ok {
   197  		replicatePeerObjs := replicatePeersValue.([]interface{})
   198  		h.replicatePeers = parsePeersToReplicate(h.namespace, replicatePeerObjs)
   199  		if len(h.replicatePeers) > 0 {
   200  			h.replicateWorkers = NewReplicateWorkers(ctx, h.replicatePeers)
   201  		}
   202  	}
   203  
   204  	var refreshInterval int
   205  	if value, ok := option[optionRefreshInterval]; ok {
   206  		refreshInterval = value.(int)
   207  	}
   208  	if refreshInterval <= 0 {
   209  		refreshInterval = DefaultRefreshInterval
   210  	}
   211  
   212  	var deltaExpireInterval int
   213  	if value, ok := option[optionDeltaExpireInterval]; ok {
   214  		deltaExpireInterval = value.(int)
   215  	}
   216  	if deltaExpireInterval <= 0 {
   217  		deltaExpireInterval = DefaultDetailExpireInterval
   218  	}
   219  
   220  	// 连接数限制的配置
   221  	if raw, _ := option[optionConnLimit].(map[interface{}]interface{}); raw != nil {
   222  		connLimitConfig, err := connlimit.ParseConnLimitConfig(raw)
   223  		if err != nil {
   224  			return err
   225  		}
   226  		h.connLimitConfig = connLimitConfig
   227  	}
   228  	if raw, _ := option[optionTLS].(map[interface{}]interface{}); raw != nil {
   229  		tlsConfig, err := secure.ParseTLSConfig(raw)
   230  		if err != nil {
   231  			return err
   232  		}
   233  		h.tlsInfo = &secure.TLSInfo{
   234  			CertFile:      tlsConfig.CertFile,
   235  			KeyFile:       tlsConfig.KeyFile,
   236  			TrustedCAFile: tlsConfig.TrustedCAFile,
   237  		}
   238  	}
   239  
   240  	h.refreshInterval = time.Duration(refreshInterval) * time.Second
   241  	h.deltaExpireInterval = time.Duration(deltaExpireInterval) * time.Second
   242  
   243  	var enableSelfPreservation bool
   244  	if value, ok := option[optionEnableSelfPreservation]; ok {
   245  		enableSelfPreservation = value.(bool)
   246  	} else {
   247  		enableSelfPreservation = DefaultEnableSelfPreservation
   248  	}
   249  	h.enableSelfPreservation = enableSelfPreservation
   250  
   251  	if value, ok := option[optionGenerateUniqueInstId]; ok {
   252  		h.generateUniqueInstId, _ = value.(bool)
   253  	} else {
   254  		h.generateUniqueInstId = false
   255  	}
   256  
   257  	if raw, _ := option[optionCustomValues].(map[interface{}]interface{}); raw != nil {
   258  		for k, v := range raw {
   259  			CustomEurekaParameters[k.(string)] = fmt.Sprintf("%v", v)
   260  		}
   261  	}
   262  
   263  	eurekalog.Infof("[EUREKA] custom eureka parameters: %v", CustomEurekaParameters)
   264  	return nil
   265  }
   266  
   267  func parsePeersToReplicate(defaultNamespace string, replicatePeerObjs []interface{}) map[string][]string {
   268  	ret := make(map[string][]string)
   269  	if len(replicatePeerObjs) == 0 {
   270  		return ret
   271  	}
   272  
   273  	for _, replicatePeerObj := range replicatePeerObjs {
   274  		replicatePeerStr, ok := replicatePeerObj.(string)
   275  		if ok {
   276  			if replicatePeerStr == utils.LocalHost {
   277  				// If the url represents this host, do not replicate to yourself.
   278  				continue
   279  			}
   280  			peers, exist := ret[defaultNamespace]
   281  			if !exist {
   282  				peers = []string{replicatePeerStr}
   283  			} else {
   284  				peers = append(peers, replicatePeerStr)
   285  			}
   286  			ret[defaultNamespace] = peers
   287  
   288  		} else if namespaceReplicatePeerMap, ok := replicatePeerObj.(map[interface{}]interface{}); ok {
   289  			for k, v := range namespaceReplicatePeerMap {
   290  				namespace := k.(string)
   291  				peerObjs := v.([]interface{})
   292  				for _, peer := range peerObjs {
   293  					peerStr, success := peer.(string)
   294  
   295  					if success {
   296  						if peerStr == utils.LocalHost {
   297  							// If the url represents this host, do not replicate to yourself.
   298  							continue
   299  						}
   300  						peers, exist := ret[namespace]
   301  						if !exist {
   302  							peers = []string{peerStr}
   303  						} else {
   304  							peers = append(peers, peerStr)
   305  						}
   306  						ret[namespace] = peers
   307  					}
   308  				}
   309  			}
   310  
   311  		}
   312  
   313  	}
   314  	return ret
   315  }
   316  
   317  // Run 启动HTTP API服务器
   318  func (h *EurekaServer) Run(errCh chan error) {
   319  	eurekalog.Infof("start EurekaServer")
   320  	h.exitCh = make(chan struct{})
   321  	h.start = true
   322  	defer func() {
   323  		close(h.exitCh)
   324  		h.start = false
   325  	}()
   326  	var err error
   327  	// 引入功能模块和插件
   328  	h.namingServer, err = service.GetServer()
   329  	if err != nil {
   330  		eurekalog.Errorf("%v", err)
   331  		errCh <- err
   332  		return
   333  	}
   334  	h.originDiscoverSvr, err = service.GetOriginServer()
   335  	if err != nil {
   336  		eurekalog.Errorf("%v", err)
   337  		errCh <- err
   338  		return
   339  	}
   340  	h.healthCheckServer, err = healthcheck.GetServer()
   341  	if err != nil {
   342  		eurekalog.Errorf("%v", err)
   343  		errCh <- err
   344  		return
   345  	}
   346  	if len(h.replicatePeers) > 0 {
   347  		h.eventHandlerHandler = &EurekaInstanceEventHandler{
   348  			BaseInstanceEventHandler: service.NewBaseInstanceEventHandler(h.namingServer), svr: h}
   349  		subCtx, err := eventhub.Subscribe(eventhub.InstanceEventTopic, h.eventHandlerHandler)
   350  		if err != nil {
   351  			errCh <- err
   352  			return
   353  		}
   354  		h.subCtxs = append(h.subCtxs, subCtx)
   355  	}
   356  	h.registerInstanceChain()
   357  	h.workers = NewApplicationsWorkers(h.refreshInterval, h.deltaExpireInterval, h.enableSelfPreservation,
   358  		h.namingServer, h.healthCheckServer, h.namespace)
   359  	h.statis = plugin.GetStatis()
   360  	// 初始化http server
   361  	address := fmt.Sprintf("%v:%v", h.listenIP, h.listenPort)
   362  
   363  	wsContainer, err := h.createRestfulContainer()
   364  	if err != nil {
   365  		errCh <- err
   366  		return
   367  	}
   368  
   369  	server := http.Server{Addr: address, Handler: wsContainer, WriteTimeout: 2 * time.Minute}
   370  
   371  	ln, err := net.Listen("tcp", address)
   372  	if err != nil {
   373  		eurekalog.Errorf("net listen(%s) err: %s", address, err.Error())
   374  		errCh <- err
   375  		return
   376  	}
   377  	ln = keepalive.NewTcpKeepAliveListener(3*time.Minute, ln.(*net.TCPListener))
   378  	// 开启最大连接数限制
   379  	if h.connLimitConfig != nil && h.connLimitConfig.OpenConnLimit {
   380  		eurekalog.Infof("http server use max connection limit per ip: %d, http max limit: %d",
   381  			h.connLimitConfig.MaxConnPerHost, h.connLimitConfig.MaxConnLimit)
   382  		ln, err = connlimit.NewListener(ln, h.GetProtocol(), h.connLimitConfig)
   383  		if err != nil {
   384  			eurekalog.Errorf("conn limit init err: %s", err.Error())
   385  			errCh <- err
   386  			return
   387  		}
   388  	}
   389  	h.server = &server
   390  
   391  	// 开始对外服务
   392  	if h.tlsInfo.IsEmpty() {
   393  		err = server.Serve(ln)
   394  	} else {
   395  		err = server.ServeTLS(ln, h.tlsInfo.CertFile, h.tlsInfo.KeyFile)
   396  	}
   397  	if err != nil && err != http.ErrServerClosed {
   398  		eurekalog.Errorf("%+v", err)
   399  		if !h.restart {
   400  			eurekalog.Infof("not in restart progress, broadcast error")
   401  			errCh <- err
   402  		}
   403  		return
   404  	}
   405  	eurekalog.Infof("EurekaServer stop")
   406  }
   407  
   408  // 创建handler
   409  func (h *EurekaServer) createRestfulContainer() (*restful.Container, error) {
   410  	wsContainer := restful.NewContainer()
   411  	wsContainer.Filter(h.process)
   412  	wsContainer.Add(h.GetEurekaV2Server())
   413  	wsContainer.Add(h.GetEurekaV1Server())
   414  	wsContainer.Add(h.GetEurekaServer())
   415  	wsContainer.RecoverHandler(h.recoverFunc)
   416  	return wsContainer, nil
   417  }
   418  
   419  func (h *EurekaServer) recoverFunc(i interface{}, w http.ResponseWriter) {
   420  	eurekalog.Errorf("panic %+v", i)
   421  	w.WriteHeader(http.StatusInternalServerError)
   422  	w.Header().Add(restful.HEADER_ContentType, restful.MIME_JSON)
   423  }
   424  
   425  // process 在接收和回复时统一处理请求
   426  func (h *EurekaServer) process(req *restful.Request, rsp *restful.Response, chain *restful.FilterChain) {
   427  	func() {
   428  		if err := h.preprocess(req, rsp); err != nil {
   429  			return
   430  		}
   431  
   432  		chain.ProcessFilter(req, rsp)
   433  	}()
   434  
   435  	h.postproccess(req, rsp)
   436  }
   437  
   438  func isImportantRequest(req *restful.Request) bool {
   439  	if req.Request.Method == "POST" || req.Request.Method == "DELETE" {
   440  		return true
   441  	}
   442  	urlStr := req.Request.URL.String()
   443  	if req.Request.Method == "PUT" && strings.Contains(urlStr, "/status") {
   444  		return true
   445  	}
   446  	return false
   447  }
   448  
   449  /**
   450   * @brief 请求预处理
   451   */
   452  func (h *EurekaServer) preprocess(req *restful.Request, rsp *restful.Response) error {
   453  	// 设置开始时间
   454  	req.SetAttribute("start-time", time.Now())
   455  
   456  	if isImportantRequest(req) {
   457  		// 打印请求
   458  		accesslog.Info("receive request",
   459  			zap.String("client-address", req.Request.RemoteAddr),
   460  			zap.String("user-agent", req.HeaderParameter("User-Agent")),
   461  			zap.String("method", req.Request.Method),
   462  			zap.String("url", req.Request.URL.String()),
   463  		)
   464  	}
   465  	// 限流
   466  	if err := h.enterRateLimit(req, rsp); err != nil {
   467  		return err
   468  	}
   469  
   470  	return nil
   471  }
   472  
   473  // 访问限制
   474  func (h *EurekaServer) enterRateLimit(req *restful.Request, rsp *restful.Response) error {
   475  	// 检查限流插件是否开启
   476  	if h.rateLimit == nil {
   477  		return nil
   478  	}
   479  	// IP级限流
   480  	// 先获取当前请求的address
   481  	address := req.Request.RemoteAddr
   482  	segments := strings.Split(address, ":")
   483  	if len(segments) != 2 {
   484  		return nil
   485  	}
   486  	if ok := h.rateLimit.Allow(plugin.IPRatelimit, segments[0]); !ok {
   487  		accesslog.Error("ip ratelimit is not allow", zap.String("client", address))
   488  		RateLimitResponse(rsp)
   489  		return errors.New("ip ratelimit is not allow")
   490  	}
   491  
   492  	// 接口级限流
   493  	apiName := fmt.Sprintf("%s:%s", req.Request.Method,
   494  		strings.TrimSuffix(req.Request.URL.Path, "/"))
   495  	if ok := h.rateLimit.Allow(plugin.APIRatelimit, apiName); !ok {
   496  		accesslog.Error("api ratelimit is not allow", zap.String("client", address), zap.String("api", apiName))
   497  		RateLimitResponse(rsp)
   498  		return errors.New("api ratelimit is not allow")
   499  	}
   500  
   501  	return nil
   502  }
   503  
   504  // RateLimitResponse http答复简单封装
   505  func RateLimitResponse(rsp *restful.Response) {
   506  	rsp.WriteHeader(http.StatusTooManyRequests)
   507  	rsp.Header().Add(restful.HEADER_ContentType, restful.MIME_JSON)
   508  }
   509  
   510  /**
   511   * @brief 请求后处理:统计
   512   */
   513  func (h *EurekaServer) postproccess(req *restful.Request, rsp *restful.Response) {
   514  	now := time.Now()
   515  	// 接口调用统计
   516  	path := req.Request.URL.Path
   517  	if path != "/" {
   518  		// 去掉最后一个"/"
   519  		path = strings.TrimSuffix(path, "/")
   520  	}
   521  	startTime := req.Attribute("start-time").(time.Time)
   522  
   523  	recordApiCall := true
   524  	code, ok := req.Attribute(statusCodeHeader).(uint32)
   525  	if !ok {
   526  		code = uint32(rsp.StatusCode())
   527  		recordApiCall = code != http.StatusNotFound
   528  	}
   529  	diff := now.Sub(startTime)
   530  	// 打印耗时超过1s的请求
   531  	if diff > time.Second {
   532  		accesslog.Info("handling time > 1s",
   533  			zap.String("client-address", req.Request.RemoteAddr),
   534  			zap.String("user-agent", req.HeaderParameter("User-Agent")),
   535  			zap.String("method", req.Request.Method),
   536  			zap.String("url", req.Request.URL.String()),
   537  			zap.Duration("handling-time", diff),
   538  		)
   539  	}
   540  	method := getEurekaApi(req.Request.Method, path)
   541  
   542  	if recordApiCall {
   543  		h.statis.ReportCallMetrics(metrics.CallMetric{
   544  			API:      method,
   545  			Protocol: "HTTP",
   546  			Code:     int(code),
   547  			Duration: diff,
   548  		})
   549  	}
   550  }
   551  
   552  // getEurekaApi 聚合 eureka 接口,不暴露服务名和实例 id
   553  func getEurekaApi(method, path string) string {
   554  	if path == "" {
   555  		return ""
   556  	}
   557  	if !strings.HasPrefix(path, pathPrefix) {
   558  		return path
   559  	}
   560  
   561  	pathSlashCount := strings.Count(path, "/")
   562  
   563  	switch method {
   564  	case http.MethodPost:
   565  		if pathSlashCount == 3 {
   566  			// POST:/eureka/apps/{application}
   567  			return operationRegister
   568  		}
   569  	case http.MethodGet:
   570  		if path == "/eureka/apps/delta" {
   571  			return operationDelta
   572  		}
   573  		if pathSlashCount == 3 {
   574  			// GET:/eureka/apps/{application}
   575  			return operationAllAppIDInstances
   576  		} else if pathSlashCount == 4 {
   577  			// GET:/eureka/apps/{application}/{instanceid}
   578  			return operationAppIDInstance
   579  		}
   580  	case http.MethodDelete:
   581  		if pathSlashCount == 4 {
   582  			// DELETE:/eureka/apps/{application}/{instanceid}
   583  			return operationDeregister
   584  		} else if strings.HasSuffix(path, statusSuffix) && pathSlashCount == 5 {
   585  			// DELETE:/eureka/apps/{application}/{instanceid}/status
   586  			return operationDeleteStatusChange
   587  		}
   588  	case http.MethodPut:
   589  		if pathSlashCount == 4 {
   590  			// PUT:/eureka/apps/{application}/{instanceid}
   591  			return operationHeartbeat
   592  		} else if strings.HasSuffix(path, statusSuffix) && pathSlashCount == 5 {
   593  			// PUT:/eureka/apps/{application}/{instanceid}/status
   594  			return operationStatusChange
   595  		}
   596  	}
   597  
   598  	// GET:/eureka/apps 和其他无法识别的接口直接返回
   599  	return method + ":" + path
   600  }
   601  
   602  // Stop 结束eurekaServer的运行
   603  func (h *EurekaServer) Stop() {
   604  	// 释放connLimit的数据,如果没有开启,也需要执行一下
   605  	// 目的:防止restart的时候,connLimit冲突
   606  	connlimit.RemoveLimitListener(h.GetProtocol())
   607  	if h.server != nil {
   608  		_ = h.server.Close()
   609  	}
   610  	h.workers.Stop()
   611  }
   612  
   613  // Restart 重启eurekaServer
   614  func (h *EurekaServer) Restart(
   615  	option map[string]interface{}, api map[string]apiserver.APIConfig, errCh chan error) error {
   616  	eurekalog.Infof("restart httpserver new config: %+v", option)
   617  	// 备份一下option
   618  	backupOption := h.option
   619  	// 备份一下api
   620  	backupAPI := h.openAPI
   621  
   622  	// 设置restart标记,防止stop的时候把错误抛出
   623  	h.restart = true
   624  	// 关闭httpserver
   625  	h.Stop()
   626  	// 等待httpserver退出
   627  	if h.start {
   628  		<-h.exitCh
   629  	}
   630  
   631  	eurekalog.Infof("old httpserver has stopped, begin restart httpserver")
   632  
   633  	if err := h.Initialize(context.Background(), option, api); err != nil {
   634  		h.restart = false
   635  		if initErr := h.Initialize(context.Background(), backupOption, backupAPI); initErr != nil {
   636  			eurekalog.Errorf("start httpserver with backup cfg err: %s", initErr.Error())
   637  			return initErr
   638  		}
   639  		go h.Run(errCh)
   640  
   641  		eurekalog.Errorf("restart httpserver initialize err: %s", err.Error())
   642  		return err
   643  	}
   644  
   645  	eurekalog.Infof("init httpserver successfully, restart it")
   646  	h.restart = false
   647  	go h.Run(errCh)
   648  	return nil
   649  }