From c70ced8feee080ff63c5aae40bcc00a2748d7a4b Mon Sep 17 00:00:00 2001 From: winLsy <18332763730@163.com> Date: Thu, 8 Feb 2018 21:45:53 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=89=E5=85=A8=E4=B8=8B=E7=BA=BF=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=EF=BC=8C=E8=B0=83=E6=95=B4=E6=9C=8D=E5=8A=A1=E7=8A=B6?= =?UTF-8?q?=E6=80=81=E6=8E=A5=E5=8F=A3=E7=BC=96=E5=86=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/RestfulEurekaController.java | 278 ++++++------------ 1 file changed, 96 insertions(+), 182 deletions(-) diff --git a/ms/register-center1/src/main/java/com/micro/fast/eureka/server/controller/RestfulEurekaController.java b/ms/register-center1/src/main/java/com/micro/fast/eureka/server/controller/RestfulEurekaController.java index c20d0a8..ca229b6 100644 --- a/ms/register-center1/src/main/java/com/micro/fast/eureka/server/controller/RestfulEurekaController.java +++ b/ms/register-center1/src/main/java/com/micro/fast/eureka/server/controller/RestfulEurekaController.java @@ -2,33 +2,42 @@ package com.micro.fast.eureka.server.controller; import com.micro.fast.boot.starter.common.response.ServerResponse; import com.netflix.appinfo.AmazonInfo; -import com.netflix.appinfo.ApplicationInfoManager; import com.netflix.appinfo.DataCenterInfo; import com.netflix.appinfo.InstanceInfo; -import com.netflix.config.ConfigurationManager; +import com.netflix.appinfo.InstanceInfo.InstanceStatus; import com.netflix.discovery.shared.Application; import com.netflix.discovery.shared.Pair; import com.netflix.eureka.EurekaServerContext; import com.netflix.eureka.EurekaServerContextHolder; -import com.netflix.eureka.cluster.PeerEurekaNode; import com.netflix.eureka.registry.PeerAwareInstanceRegistry; -import com.netflix.eureka.registry.PeerAwareInstanceRegistryImpl; -import com.netflix.eureka.resources.StatusResource; -import com.netflix.eureka.util.StatusInfo; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.apache.commons.lang.StringUtils; -import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.*; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.net.URI; import java.util.*; /** * restful操作eureka的接口 - * + * 服务的注册 : + * 当eureka的客户端向eureka服务端注册的时候会提供自身的ip port info health等信息 + * 服务的续约 : + * Eureka客户会每隔30秒发送一次心跳来续约。 通过续约来告知Eureka Server该Eureka客户仍然存在,没有出现问题。 + * 正常情况下,如果Eureka Server在90秒没有收到Eureka客户的续约,它会将实例从其注册表中删除。 建议不要更改续约间隔。 + * 获取注册列表信息 : + * Eureka客户端从服务器获取注册表信息,并将其缓存在本地。客户端会使用该信息查找其他服务,从而进行远程调用。 + * 该注册列表信息定期(每30秒钟)更新一次。 + * 服务下线 : + * Eureka客户端在程序关闭时向Eureka服务器发送取消请求。 + * 服务剔除 : + * 在默认的情况下,当Eureka客户端连续90秒没有向Eureka服务器发送服务续约,即心跳,Eureka服务器会将该服务实例从服务注册列表删除. + * Eureka默认不会二次注册 : + * 当有服务的注册信息传递到Eureka的时候,eureka会判断isReplication是否是true.当isReplication为true时候eureka就不会将服务信息传递 + * 给其他注册中心 + * 如何安全热发布: + * 将服务状态调整为OUT_OF_SERVICE,经过几次心跳之后zuul会感知服务的状态,不在有新的请求进入下线的服务 + * 灰度发布: + * 通过动态修改服务的matedate信息来实现灰度发布,可以将新发布的机器设置为灰度机器。灰度机器是指接收少量指定请求的机器 * @author lsy */ @RestController @@ -36,65 +45,46 @@ import java.util.*; @Api(description = "注册中心的restful接口") public class RestfulEurekaController { - - @Value("${eureka.restful.path:/restful/eureka}") - private String restfulPath = "/restful/eureka"; - - /** - * 实例管理对象 - */ - private ApplicationInfoManager applicationInfoManager; - - public RestfulEurekaController(ApplicationInfoManager applicationInfoManager) { - this.applicationInfoManager = applicationInfoManager; - } - @GetMapping("/apps") @ApiOperation("获取所有的服务实例的简单信息") - public ServerResponse apps(HttpServletRequest request, HttpServletResponse response) { + public ServerResponse apps() { Map map = new HashMap<>(); //获取所有服务的信息 populateApps(map); return ServerResponse.successMsgData("获取所有实例成功", map); } - @GetMapping("/apps/{instanceId}") - @ApiOperation("根据域名获取某个实例的信息") - public ServerResponse getInstance(@PathVariable("instanceId") String instanceId) { - InstanceInfo instanceInfo = null; + @GetMapping("/apps/{id}") + @ApiOperation("根据id获取实例的信息,模糊查询") + public ServerResponse getInstance(@PathVariable("id") String instanceId) { + Set instanceInfos = new HashSet<>(10); if (StringUtils.isNotBlank(instanceId)){ List sortedApplications = getRegistry().getSortedApplications(); boolean isBreak = false; for (Application sortedApplication : sortedApplications) { List instances = sortedApplication.getInstances(); for (InstanceInfo instance : instances) { - String hostName = instance.getHostName(); - if (hostName.startsWith(instanceId)){ - instanceInfo = instance; - isBreak = true; - break; + if (instance.getId().contains(instanceId)){ + instanceInfos.add(instance); } } - if (isBreak){ - break; - } } }else { return ServerResponse.errorMsg("instanceId不能为空"); } - - return ServerResponse.successMsgData("根据主机名获取实例信息成功", instanceInfo); + return ServerResponse.successMsgData("根据主机名获取实例信息成功", instanceInfos); } - @GetMapping("/apps/{appId}") - @ApiOperation("根据appId查询实例,可能有多个") - public ServerResponse getInstancesByAppId(@PathVariable("appId") String appId) { + + @GetMapping("/apps/cluster/{appName}") + @ApiOperation("根据appId,也就是application.name查询实例,可能有多个") + public ServerResponse getInstancesByAppId(@PathVariable("appName") String appName) { Set instanceInfos = new HashSet<>(10); - if (StringUtils.isNotBlank(appId)){ + if (StringUtils.isNotBlank(appName)){ List sortedApplications = getRegistry().getSortedApplications(); for (Application sortedApplication : sortedApplications) { List instances = sortedApplication.getInstances(); for (InstanceInfo instance : instances) { - if (appId.equals(instance.getAppName())){ + if (StringUtils.equalsIgnoreCase(instance.getAppName(),appName)){ instanceInfos.add(instance); } } @@ -103,91 +93,82 @@ public class RestfulEurekaController { }else { return ServerResponse.errorMsg("instanceId不能为空"); } - return ServerResponse.successMsgData("根据主机名获取实例信息成功", instanceInfos); } - @GetMapping - @ResponseBody - public Map status(HttpServletRequest request, HttpServletResponse response) { - Map map = new HashMap<>(); - populateBase(request, map); - populateApps(map); - StatusInfo statusInfo; - try { - //获取当前注册中心的本身的相信信息 - statusInfo = new StatusResource().getStatusInfo(); - } catch (Exception e) { - //获取当前注册中心的本身的相信信息 - statusInfo = StatusInfo.Builder.newBuilder().isHealthy(false).build(); - } - map.put("statusInfo", statusInfo); - populateInstanceInfo(map, statusInfo); - filterReplicas(map, statusInfo); - return map; + @GetMapping("/apps/app/{appName}/{id}") + @ApiOperation("根据appName和id获取服务的信息") + public ServerResponse getApplication(@PathVariable("appName") String appName,@PathVariable("id") String id){ + PeerAwareInstanceRegistry registry = getRegistry(); + InstanceInfo instanceByAppAndId = registry.getInstanceByAppAndId(appName, id); + return ServerResponse.successData(instanceByAppAndId); } /** - * 获取最后注册的实例 - * @param request + * 主动下线服务,并传递到其他注册中心 + * 此接口主要用于下线异常终止的服务 + * @param appName + * @param id * @return */ - @GetMapping("/lastn") - public Map lastn(HttpServletRequest request) { - Map map = new HashMap<>(); - populateBase(request, map); - PeerAwareInstanceRegistryImpl registry = (PeerAwareInstanceRegistryImpl) getRegistry(); - ArrayList> lastNCanceled = new ArrayList<>(); - List> list = registry.getLastNCanceledInstances(); - for (Pair entry : list) { - lastNCanceled.add(registeredInstance(entry.second(), entry.first())); + @DeleteMapping("/{appName}/{id}/{isReplication}") + @ApiOperation("下线服务") + public ServerResponse unregister(@PathVariable("appName") String appName,@PathVariable("id") String id,@PathVariable("isReplication") Boolean isReplication){ + PeerAwareInstanceRegistry registry = getRegistry(); + // 当isReplication是true的时候表示这个实例的信息是从别的eureka复制过来的,eureka不会进行二次传递 + boolean cancel = registry.cancel(appName, id, isReplication); + if (cancel){ + return ServerResponse.successMsg("下线服务成功,服务会在下次心跳时注册"); } - map.put("lastNCanceled", lastNCanceled); - list = registry.getLastNRegisteredInstances(); - ArrayList> lastNRegistered = new ArrayList<>(); - for (Pair entry : list) { - lastNRegistered.add(registeredInstance(entry.second(), entry.first())); - } - map.put("lastNRegistered", lastNRegistered); - return map; - } - - private Map registeredInstance(String id, long date) { - HashMap map = new HashMap<>(); - map.put("id", id); - map.put("date", new Date(date)); - return map; - } - - protected void populateBase(HttpServletRequest request, Map model) { - populateHeader(model); - populateNavbar(request, model); + return ServerResponse.successMsg("下线服务失败"); } /** - * 添加注册中心基础信息 - * - * @param model + * 调整服务的状态,可以用于在无感知的情况下热部署服务 + * @param appName + * @param id + * @param status + * @return */ - private void populateHeader(Map model) { - model.put("currentTime", StatusResource.getCurrentTimeAsString()); - model.put("upTime", StatusInfo.getUpTime()); - model.put("environment", ConfigurationManager.getDeploymentContext() - .getDeploymentEnvironment()); - model.put("datacenter", ConfigurationManager.getDeploymentContext() - .getDeploymentDatacenter()); + @PutMapping("/{appName}/{id}/{status}/{isReplication}") + @ApiOperation("调整服务状态") + public ServerResponse updateStatus(@PathVariable("appName") String appName,@PathVariable("id")String id,@PathVariable("status")String status,@PathVariable("isReplication")Boolean isReplication){ PeerAwareInstanceRegistry registry = getRegistry(); - model.put("registry", registry); - model.put("isBelowRenewThresold", registry.isBelowRenewThresold() == 1); - DataCenterInfo info = applicationInfoManager.getInfo().getDataCenterInfo(); - if (info.getName() == DataCenterInfo.Name.Amazon) { - AmazonInfo amazonInfo = (AmazonInfo) info; - model.put("amazonInfo", amazonInfo); - model.put("amiId", amazonInfo.get(AmazonInfo.MetaDataKey.amiId)); - model.put("availabilityZone", - amazonInfo.get(AmazonInfo.MetaDataKey.availabilityZone)); - model.put("instanceId", amazonInfo.get(AmazonInfo.MetaDataKey.instanceId)); + switch (status){ + case "OUT_OF_SERVICE": + boolean b = registry.statusUpdate(appName, id, InstanceStatus.OUT_OF_SERVICE, String.valueOf(System.currentTimeMillis()), isReplication); + if (b){ + return ServerResponse.successMsg("下线服务成功"); + } + break; + case "DOWN": + boolean b1 = registry.statusUpdate(appName, id, InstanceStatus.DOWN, String.valueOf(System.currentTimeMillis()), isReplication); + if (b1){ + return ServerResponse.successMsg("设置服务为down成功"); + } + break; + case "UP" : + boolean b2 = registry.statusUpdate(appName, id, InstanceStatus.UP, String.valueOf(System.currentTimeMillis()), isReplication); + if (b2){ + return ServerResponse.successMsg("上线服务成功"); + } + break; + case "UNKNOWN" : + boolean b3 = registry.statusUpdate(appName, id, InstanceStatus.UNKNOWN, String.valueOf(System.currentTimeMillis()), isReplication); + if (b3){ + return ServerResponse.successMsg("设置服务状态为UNKNOWN"); + } + break; + case "STARTING" : + boolean b4 = registry.statusUpdate(appName, id, InstanceStatus.STARTING, String.valueOf(System.currentTimeMillis()), isReplication); + if (b4){ + return ServerResponse.successMsg("设置服务为正在启动中"); + } + break; + default: + return ServerResponse.errorMsg("请传入正确的状态"); } + return ServerResponse.errorMsg("修改状态失败"); } private PeerAwareInstanceRegistry getRegistry() { @@ -198,23 +179,8 @@ public class RestfulEurekaController { return EurekaServerContextHolder.getInstance().getServerContext(); } - private void populateNavbar(HttpServletRequest request, Map model) { - Map replicas = new LinkedHashMap<>(); - List list = getServerContext().getPeerEurekaNodes().getPeerNodesView(); - for (PeerEurekaNode node : list) { - try { - URI uri = new URI(node.getServiceUrl()); - String href = scrubBasicAuth(node.getServiceUrl()); - replicas.put(uri.getHost(), href); - } catch (Exception ex) { - // ignore? - } - } - model.put("replicas", replicas.entrySet()); - } - /** - * 填所有实例的简单信息 + * 填充所有实例的简单信息 * @param model */ private void populateApps(Map model) { @@ -289,57 +255,5 @@ public class RestfulEurekaController { } model.put("apps", apps); } - - /** - * 填充当前注册中心的信息 - * @param model - * @param statusInfo - */ - private void populateInstanceInfo(Map model, StatusInfo statusInfo) { - InstanceInfo instanceInfo = statusInfo.getInstanceInfo(); - Map instanceMap = new HashMap<>(); - instanceMap.put("ipAddr", instanceInfo.getIPAddr()); - instanceMap.put("status", instanceInfo.getStatus().toString()); - if (instanceInfo.getDataCenterInfo().getName() == DataCenterInfo.Name.Amazon) { - AmazonInfo info = (AmazonInfo) instanceInfo.getDataCenterInfo(); - instanceMap.put("availability-zone", - info.get(AmazonInfo.MetaDataKey.availabilityZone)); - instanceMap.put("public-ipv4", info.get(AmazonInfo.MetaDataKey.publicIpv4)); - instanceMap.put("instance-id", info.get(AmazonInfo.MetaDataKey.instanceId)); - instanceMap.put("public-hostname", - info.get(AmazonInfo.MetaDataKey.publicHostname)); - instanceMap.put("ami-id", info.get(AmazonInfo.MetaDataKey.amiId)); - instanceMap.put("instance-type", - info.get(AmazonInfo.MetaDataKey.instanceType)); - } - model.put("instanceInfo", instanceMap); - } - - protected void filterReplicas(Map model, StatusInfo statusInfo) { - Map applicationStats = statusInfo.getApplicationStats(); - if (applicationStats.get("registered-replicas").contains("@")) { - applicationStats.put("registered-replicas", scrubBasicAuth(applicationStats.get("registered-replicas"))); - } - if (applicationStats.get("unavailable-replicas").contains("@")) { - applicationStats.put("unavailable-replicas", scrubBasicAuth(applicationStats.get("unavailable-replicas"))); - } - if (applicationStats.get("available-replicas").contains("@")) { - applicationStats.put("available-replicas", scrubBasicAuth(applicationStats.get("available-replicas"))); - } - model.put("applicationStats", applicationStats); - } - - private String scrubBasicAuth(String urlList) { - String[] urls = urlList.split(","); - String filteredUrls = ""; - for (String u : urls) { - if (u.contains("@")) { - filteredUrls += u.substring(0, u.indexOf("//") + 2) + u.substring(u.indexOf("@") + 1, u.length()) + ","; - } else { - filteredUrls += u + ","; - } - } - return filteredUrls.substring(0, filteredUrls.length() - 1); - } }