`

微服务管理平台如何防止开发人员的本地环境污染注册中心

阅读更多

微服务的代码由两部分构成,一部分是根据模型定义自动生成的,这部分代码不可修改,另外一部分代码是留给开发人员实现业务逻辑的,可以修改。

 

防止开发人员的本地环境污染注册中心最开始的解决方法是,在自动生成的代码中,强制指定了微服务运行的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;
    }
}

 

我的开源项目主页 

 

1
0
分享到:
评论

相关推荐

    基于微服务架构的分布式开发平台.pdf

    分布式开发平台则是基于微服务架构理念,配合Spring Cloud框架,将系统的各个功能模块封装成服务,实现服务的独立开发、部署和管理。平台通常包含几个关键层次: 1. 公共开发工具层:提供与二次开发相关的工具和...

    基于微服务打造共享开发平台.pdf

    在本文档中,主题是"基于微服务打造共享开发平台",并且明确提出了"智慧微服务"和"服务架构"这两个核心关键词。基于这些信息,我们可以得知文档中涉及的知识点主要围绕如何利用微服务架构思想来构建一个共享的、智慧...

    基于Spring Cloud框架的微服务开发平台.zip

    实现微服务治理,包括服务注册、发现、配置管理等 开发和部署基于Spring Cloud的微服务应用 目标 提供一个易于使用的微服务开发平台,降低开发门槛 统一兼容调试基础框架,确保组件的稳定性和一致性 支持多种...

    微服务精选:用户中心微服务设计理念.pdf

    用户中心设计理念是微服务架构中的一个重要组件,它负责管理用户的身份验证、授权和会话管理。在本文档中,我们将详细介绍用户中心设计理念的发展史、用户中心的令牌、多种场景下的认证解决方案、用户中心衍生的相关...

    基于微服务架构的统一应用开发平台_李春阳.pdf

    通过引入微服务构建和分布式服务注册等相关技术,平台实现了生成微服务工程的标准开发框架,解决传统单体架构应用庞大而带来的研发周期长,难以快速响应用户需求等问题,为业务系统的开发提供了有效支撑.

    hdw-dubbo 微服务化开发平台,具有统一授权、认证后台管理系统,其中包含具备用户管理、资源权限管理等多个模块,支持多业务系统并行开发,可以作为后端服务的开

    微服务化开发平台,具有统一授权、认证后台管理系统,其中包含具备用户管理、资源权限管理等多个模块,支持多业务系统并行开发,可以作为后端服务的开发脚手架。代码简洁,架构清晰,适合学习和直接项目中使用。 ...

    微服务开发各种注册中心对比

    在微服务架构中,注册中心是核心组件之一,它负责管理微服务实例的注册与发现,并提供了服务治理的能力。注册中心的选择直接影响到微服务架构的稳定性和可维护性。以下是对于当前主流微服务注册中心的详细知识点对比...

    流程与信息化管理中心-微服务治理平台规划

    微服务治理平台规划是现代...通过以上规划,微服务治理平台将能够有效地支持企业的软件开发、项目管理、CRM、BI、OA、ERP、EHR等核心业务系统,促进企业数字化转型的顺利进行,提高业务响应速度和系统整体的可靠性。

    java基于微服务的权限管理系统急速开发框架后端+前端.zip

    java基于微服务的权限管理系统急速开发框架后端+前端.zipjava基于微服务的权限管理系统急速开发框架后端+前端.zipjava基于微服务的权限管理系统急速开发框架后端+前端.zipjava基于微服务的权限管理系统急速开发框架...

    微服务开发手册.pdf

    总之,《微服务开发手册》提供了一套完整的微服务开发指导,包括选用的技术栈、接口设计原则、服务注册、配置管理以及代码组织等,帮助开发者构建高效、稳定的微服务体系。通过遵循这些规范,可以实现微服务间的顺畅...

    微服务框架搭建和开发

    微服务框架搭建和开发 在本资源中,我们将讨论微服务架构的搭建和设计,适合微服务的初学者。本资源将涵盖微服务框架的搭建、开发工具的安装和配置、Maven 的安装和配置、STS 插件的安装、Nexus 私服的安装等内容。...

    如何在微服务架构下构建高效的运维管理平台?

    2、面向微服务的运维平台架构;3、运维平台微服务进化。“微服务”与“巨石架构”两者并非对立,而是分别针对不同场景的解决方案。巨石架构指将所有“大脑”集中在一起,以CS架构为代表,将所有的逻辑放在唯一应用中...

    微服务架构核心组件:服务注册中心Eureka

    总的来说,通过Eureka,我们可以构建一个高可扩展、容错性强的微服务系统,每个服务都可以独立开发、部署和扩展,而服务间的通信则通过Eureka进行高效、可靠的管理。理解并掌握Eureka的工作原理和使用方法,对于实现...

    jrebel-开发人员如何使用微服务.pdf

    在探讨JRebel如何在开发人员使用微服务中发挥作用之前,我们首先需要了解微服务架构的背景以及Java开发中微服务的现状。微服务是一种软件架构风格,它将应用程序构建成由轻量级、松耦合的服务组成的集合,这些服务...

    微服务平台建设方案.docx

    通过 Spring Boot 的便捷开发方式,Spring Cloud 支持一键启动和部署服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等功能。 Spring Cloud 的核心价值在于它不是重新发明轮子,而是整合现有的成熟...

    从 0 开始的微服务架构

    序言 自从Martin Fowler对微服务作出定义之后,微服务便火遍大江南北, ...基于 Docker 的微服务平台进行开发和运行运维支撑,使用 Spring Cloud 进行业务系统开发,两者相互独立,并可被独立替换。

    基于Spring Cloud微服务开发平台,具有统一授权、认证后台管理系统,包含具备用户管理、资源权限管理、网关API管理等模块

    Cloud-Platform是国内首个基于Spring Cloud微服务化开发平台,具有统一授权、认证后台管理系统,其中包含具备用户管理、资源权限管理、网关API 管理等多个模块,支持多业务系统并行开发,可以作为后端服务的开发...

    微服务开发

    dubbo 微服务开发技术指导方案;dubbo 微服务开发技术指导方案

    微服务学习微服务学习微服务学习微服务学习1

    这个实战指南可能深入介绍了如何配置和使用Nacos作为微服务的注册中心,包括服务的注册与发现、配置管理以及健康检查等功能。通过Nacos,开发者可以更轻松地管理服务实例的生命周期和配置信息。 "spring cloud ...

Global site tag (gtag.js) - Google Analytics