微服务的代码由两部分构成,一部分是根据模型定义自动生成的,这部分代码不可修改,另外一部分代码是留给开发人员实现业务逻辑的,可以修改。
防止开发人员的本地环境污染注册中心最开始的解决方法是,在自动生成的代码中,强制指定了微服务运行的IP,模板文件applicationProperties.ftl中的相关片段如下:
eureka.instance.prefer-ip-address=true eureka.instance.ip-address=${serviceDeployServerIp}
当服务开发完毕,需要部署到测试环境的时候,需要执行一个发布服务审核流程,发布服务的操作会给服务打一个版本,在发布服务的时候,去掉了如上用于开发环境的强制指定的IP,发布服务脚本文件service_release.sh的部分相关片段如下:
if [[ $1 = '' ]] then echo "没有指定服务名称" exit fi cat gi-service/gi-service-$1/standard/src/main/resources/application.properties | awk '{if($0!~/eureka.instance.ip-address=/){print $0}}' > gi-service/gi-service-$1/standard/src/main/resources/application-release.properties mv gi-service/gi-service-$1/standard/src/main/resources/application-release.properties gi-service/gi-service-$1/standard/src/main/resources/application.properties
用这种解决方案,满足了我们很长一段时间的需求,开发人员自己在本地启动服务向注册中心注册服务并不会把自己的本地内网地址注册上去,注册的地址其实是云端的服务的运行地址,不会对网关以及跨服务调用产生影响。
然而,接下来事情发生了变化。
微服务不再是一直固定运行在一台机器上了,开始引入了机器资源池的概念,资源池中的机器用来运行微服务,每一个微服务在启动的时候会自动地从资源池中挑选一台机器来执行,也就是说,微服务不会有固定的运行IP,这样,上面的解决方案就失效了。
该怎么解决这个问题呢?
思路是,改造注册中心,只允许机器资源池中的机器进行服务的注册,其他的未知机器则只能做服务的查找而不能执行注册操作,这样,开发人员的本地服务就不会注册到注册中心中去了。
注册中心本身是一个web应用,服务的注册和查找也是通过http请求进行的,那么改造注册中心的方式可以使用一个过滤器,具体实现代码如下:
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Service; import javax.annotation.PostConstruct; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicLong; /** * 防止开发人员的本地环境污染注册中心 * @date 2018-09-11 * @author 杨尚川 */ @Service public class LimitRegisterFilter implements Filter { private static final Logger LOGGER = LoggerFactory.getLogger(LimitRegisterFilter.class); @Value("${allow.ips.url}") private String allowIpsUrl; @Value("${refresh.time.ms}") private long refreshTimeInMs; private String allowIps="127.0.0.1,0:0:0:0:0:0:0:1,"; private static AtomicLong accessCount = new AtomicLong(); private static AtomicLong registerCount = new AtomicLong(); private static AtomicLong rejectRegisterCount = new AtomicLong(); private static AtomicLong noNeedRegisterCount = new AtomicLong(); private static AtomicLong nullProjectNameAndServiceNameRegisterCount = new AtomicLong(); private static Map<String, Long> lastRegisterTimeMap = new ConcurrentHashMap<>(); @PostConstruct public void init(){ LOGGER.info("初始化过滤器, 获取允许的IP地址的路径: {}", allowIpsUrl); try { HttpURLConnection conn = (HttpURLConnection) new URL(allowIpsUrl).openConnection(); conn.setRequestMethod("GET"); conn.setDoOutput(true); StringBuilder result = new StringBuilder(); try (BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()))) { String line = null; while ((line = reader.readLine()) != null) { result.append(line).append("\n"); } } allowIps += result.toString(); }catch (Exception e){ LOGGER.error("获取允许的IP地址失败", e); } LOGGER.info("初始化过滤器, 允许的IP地址: {}", allowIps); } @Override public void init(FilterConfig filterConfig) throws ServletException { LOGGER.info("初始化过滤器"); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException { accessCount.incrementAndGet(); HttpServletRequest req = (HttpServletRequest)request; String uri = req.getRequestURI(); String method = req.getMethod(); String ip = request.getRemoteAddr(); LOGGER.debug("访问信息, ip: {}, method: {}, uri: {}", ip, method, uri); if (!"GET".equals(method.toUpperCase()) && (uri.contains("eureka/apps") || uri.contains("eureka/v2/apps"))) { LOGGER.debug("注册服务, ip: {}, method: {}, uri: {}", ip, method, uri); String[] attr = uri.split("/"); String projectNameAndServiceName = null; if(uri.contains("eureka/apps") && attr.length>3){ projectNameAndServiceName = attr[3]; } if(uri.contains("eureka/v2/apps") && attr.length>4){ projectNameAndServiceName = attr[4]; } registerCount.incrementAndGet(); if (allowIps == null || !allowIps.contains(ip)) { LOGGER.warn("不允许的IP注册: {}, 总的访问次数: {}, 注册次数: {}, 无需注册次数: {}, 拒绝注册次数: {}, 获取不到项目名称和服务名称数: {}", ip, accessCount.get(), registerCount.get(), noNeedRegisterCount.get(), rejectRegisterCount.get(), nullProjectNameAndServiceNameRegisterCount.get()); rejectRegisterCount.incrementAndGet(); return; } if(projectNameAndServiceName==null){ nullProjectNameAndServiceNameRegisterCount.incrementAndGet(); return; } String key = ip+"_"+projectNameAndServiceName+"_"+method; Long lastRegisterTime = lastRegisterTimeMap.get(key); if(lastRegisterTime != null){ if((System.currentTimeMillis()-lastRegisterTime) < refreshTimeInMs){ noNeedRegisterCount.incrementAndGet(); return; } } lastRegisterTimeMap.put(key, System.currentTimeMillis()); } filterChain.doFilter(request, response); } @Override public void destroy() { LOGGER.info("销毁过滤器"); } @Bean public FilterRegistrationBean filterRegistrationBean() { LimitRegisterFilter limitRegisterFilter = new LimitRegisterFilter(); limitRegisterFilter.allowIps = allowIps; limitRegisterFilter.refreshTimeInMs = refreshTimeInMs; LOGGER.info("注册过滤器ServerRequestAuthFilter, 允许的IP地址: {}", allowIps); FilterRegistrationBean registration = new FilterRegistrationBean(limitRegisterFilter); registration.addUrlPatterns("/*"); return registration; } }
相关推荐
基于微服务打造共享开发平台.pdf
本地调试只要跑需要的一个微服务进行调试,其他服务都使用一套测试环境上的微服务,节省本地电脑的性能,节约资源。如,需要调用UC,本地只需要启动UC就可以联调。不影响其他人员正常使用测试环境查看页面,默认都是...
通过引入微服务构建和分布式服务注册等相关技术,平台实现了生成微服务工程的标准开发框架,解决传统单体架构应用庞大而带来的研发周期长,难以快速响应用户需求等问题,为业务系统的开发提供了有效支撑.
微服务化开发平台,具有统一授权、认证后台管理系统,其中包含具备用户管理、资源权限管理等多个模块,支持多业务系统并行开发,可以作为后端服务的开发脚手架。代码简洁,架构清晰,适合学习和直接项目中使用。 ...
#资源达人分享计划#
Java springBlade微服务开发平台 是一个由商业级项目升级优化而来的微服务架构,采用Spring Boot 2.6 、Spring Clou,用前后端分离的模式,前端开源两个框架:Sword (基于 React、Ant Design)、Saber (基于 Vue、...
微服务开发各种注册中心对比
java基于微服务的权限管理系统急速开发框架后端+前端.zipjava基于微服务的权限管理系统急速开发框架后端+前端.zipjava基于微服务的权限管理系统急速开发框架后端+前端.zipjava基于微服务的权限管理系统急速开发框架...
2、面向微服务的运维平台架构;3、运维平台微服务进化。“微服务”与“巨石架构”两者并非对立,而是分别针对不同场景的解决方案。巨石架构指将所有“大脑”集中在一起,以CS架构为代表,将所有的逻辑放在唯一应用中...
内容概要:通过带着读者基于分布式、移动计算和微服务等技术,选择Spring Cloud 作为开发框架,在移动环境中组建云平台。设计数据库,开发各模块功能,实现移动安保系统, 提供实时数据采集、分析、存储等功能。具体...
序言 自从Martin Fowler对微服务作出定义之后,微服务便火遍大江南北, ...基于 Docker 的微服务平台进行开发和运行运维支撑,使用 Spring Cloud 进行业务系统开发,两者相互独立,并可被独立替换。
dubbo 微服务开发技术指导方案;dubbo 微服务开发技术指导方案
流程与信息化管理中心-微服务治理平台规划
consul微服务注册中心
功能: - 登录 / 注销 - 权限验证 - 页面权限 - 指令权限 - 二步登录 - 多环境发布 - dev sit stage prod ... - 动态侧边栏(支持...配套的后台 代码库springcloud, 是一个微服务开发集成平台,该项目基于 vue 和
Java微服务SaaS快速开发平台.rarJava微服务SaaS快速开发平台.rarJava微服务SaaS快速开发平台.rar
微服务后台通用管理系统源码.zip是以vue-element-admin 为基础开发的微服务开发平台的管理系统。配套的后台 代码库springcloud, 是一个微服务开发集成平台,该项目基于 vue 和 element。 它使用了最新的前端技术栈,...
Eureka服务端介质,搭建本地的微服务注册与发现中心,spring开发必备,启动命令java -jar eurekaserver01-0.0.1-SNAPSHOT.jar > eurekaserver01.log
基于微服务spring cloud核心组件注册中心(Eureka),架构图分析,分布式架构图,代码demo
2020年微服务云计算平台开发项目可行性研究报告.pdf2020年微服务云计算平台开发项目可行性研究报告.pdf