Eureka结合网关实现多集群分片

本文介绍了如何通过Eureka Client源码调整和注册网关实现多集群分片,解决了EurekaServer集群承载实例数限制问题。通过注册网关路由、定时获取各集群注册列表并返回给客户端,确保每个客户端能获取所有服务实例信息。
摘要由CSDN通过智能技术生成

问题描述

目前EurekaClient客户端只能往一个EurekaServer集群进行注册发现。而一个EurekaServer集群受制于硬件配置的高低,所能承受的最大服务注册实例数一般在4000至8000个不等。当一群服务的实例数超过了一个EurekaServer集群所能承受的最大实例数时,EurekaServer集群就不能正常运行,会导致大量请求超时,影响所有服务的注册和发现。

解决思路

为了解决这个问题,可以引入一个注册网关,将这一群服务按照某种规则分别注册到不同的EurekaServer集群中,再由注册网关通过调用Eureka API获取所有集群中的注册列表,将这些注册列表全部返回给EurekaClient客户端,这样每一个客户端都能拿到所有EurekaServer集群里的服务实例的注册列表。

具体实现

逻辑图

在这里插入图片描述

实现步骤说明

1、 通过修改Eureka Client源码,在请求的注册中心URL里添加项目名;
2、 注册网关通过识别请求中的项目名,将注册的请求转发到对应的集群中;
3、 注册网关通过定时任务每3秒调用Eureka API,从所有的集群中获取全量的注册列表和增量的注册列表分别存入本地缓存;
4、 当客户端发送获取全量注册列表或者是获取增量注册列表请求时,注册网关将本地缓存中存放的所有集群的未解压的全量注册列表或增量注册列表信息封装处理后返回给客户端;
5、 客户端接收到从注册网关返回的全量或增量注册列表后,经过解压合并处理转换成Applications对象存入本地注册列表缓存。

Eureka Client源码调整

将从GitHub上下载的Eureka源码spring-cloud-netflix-2.2.0.RELEASE打开,修改里面的子模块spring-cloud-netflix-eureka-client。
找到类org.springframework.cloud.netflix.eureka.EurekaClientConfigBean.java,修改getEurekaServerServiceUrls方法,将配置文件中的project.name参数加入到eurekaServerUrl中,修改的示例如下:

@Override
public List<String> getEurekaServerServiceUrls(String myZone) {
   
    String serviceUrls = this.serviceUrl.get(myZone);
    if (serviceUrls == null || serviceUrls.isEmpty()) {
   
        serviceUrls = this.serviceUrl.get(DEFAULT_ZONE);
    }
    if (!StringUtils.isEmpty(serviceUrls)) {
   
        final String[] serviceUrlsSplit = StringUtils.commaDelimitedListToStringArray(serviceUrls);
        List<String> eurekaServiceUrls = new ArrayList<>(serviceUrlsSplit.length);
        for (String eurekaServiceUrl : serviceUrlsSplit) {
   
            if (!endsWithSlash(eurekaServiceUrl)) {
   
                eurekaServiceUrl += "/";
            }
            // ### 根据配置判断是否是需要连接注册网关 TOP ###
            String isEurekaServer = this.environment.getProperty("is.use.eureka.gateway", "true");
            if ("true".equalsIgnoreCase(isEurekaServer.toLowerCase())) {
   
                /*
                 * 微服务客户端连注册中心需要经过注册网关转发
                 * 连注册网关的URL=http://gatewayIp:port/{project.name}/eureka/
                 */
                String projectName = this.environment.getProperty("project.name", "default");
                String str = "/" + projectName + "/eureka/";
                eurekaServiceUrl = eurekaServiceUrl.trim().replace("/eureka/", str);
                System.out.println("EurekaGatewayUrl=" + eurekaServiceUrl);
            } else {
   
                System.out.println("EurekaServiceUrl=" + eurekaServiceUrl);
            }
            // ### END ###
            eurekaServiceUrls.add(eurekaServiceUrl);
        }
        return eurekaServiceUrls;
    }
    return new ArrayList<>();
}

注册网关添加路由配置

使用Spring Cloud Gateway做为注册网关,在注册网关中添加对客户端请求的路由设置,将项目APP-1发来的注册发现请求转发到eurekaServer1,将APP-2发来的注册发现请求转发到eurekaServer2,配置示例如下:

spring.cloud.gateway.routes.0.id = app-1
spring.cloud.gateway.routes.0.uri = lb://app-1
spring.cloud.gateway.routes.0.predicates.0 = Path=/**/APP-1/eureka/**
spring.cloud.gateway.routes.0.filters.0 = StripPrefix=3
spring.cloud.gateway.routes.0.filters.1 = EurekaResponse

spring.cloud.gateway.routes.1.id = app-2
spring.cloud.gateway.routes.1.uri = lb://app-2
spring.cloud.gateway.routes.1.predicates.0 = Path=/**/APP-2/eureka/**
spring.cloud.gateway.routes.1.filters.0 = StripPrefix=3
spring.cloud.gateway.routes.1.filters.1 = EurekaResponse

app-1.ribbon.listOfServers = http://eurekaServer1Ip:8001
app-2.ribbon.listOfServers = http://eurekaServer2Ip:8002

注册网关定时获取注册列表

注册网关通过定时任务,每3秒去拉取eurekaServer1和eurekaServer2两个集群的全量注册列表,存入本地缓存。

@Slf4j
@Component
@EnableScheduling
public class EurekaAppsTask implements SchedulingConfigurer {
   
    @Autowired
    private ConfigBean configBean;
    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
   
        scheduledTaskRegistrar.addTriggerTask(() -> eurekaAppsInfo(),
                triggerContext -> {
   
                    String cron = configBean.getEurekainstanceCron();
                    if (StringUtils.isEmpty(cron)) {
   
                        cron = "*/3 * * * * ?";
                    }
                    return new CronTrigger(cron).nextExecutionTime(triggerContext);
                });
    }

    // 全量拉取分片注册中心服务列表
    private void eurekaAppsInfo() {
   
        List<String> allSubDomainId = configBean.getAllSubDomainId();
        allSubDomainId.stream().filter(subDomainId -> !CollectionUtils.isEmpty(allSubDomainId))
                .forEach(subDomainId -> {
   
                    String oneDomainPath = configBean.getOneDomainPath(subDomainId);
                    if (StringUtils.isEmpty(oneDomainPath)) return;
                    String url = "http://" + oneDomainPath + "/eureka/apps";
                    long startTime = System.currentTimeMillis();
                    RestTemplate restTemplate = new RestTemplate();
                    HttpHeaders httpHeaders = new HttpHeaders();
                    httpHeaders.set("Accept-Encoding", "gzip");
                    HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(httpHeaders);
                    byte[] value = new byte[0];
                    try {
   
                        ResponseEntity<byte[]> exchange = restTemplate.exchange(url, HttpMethod.GET, entity, byte[].class);
                        value = exchange.getBody();
                        ServerData.allInstanceServersMap.put(subDomainId, value);
                    } catch (Exception e) {
   
                        log.error(e.getMessage(),e);
                    }
                    log.warn("获取分片 {} ,耗时:{} ms", url, System.currentTimeMillis() - startTime);
                });

    }
}

注册网关通过定时任务,每3秒去拉取eurekaServer1和eurekaServer2两个集群的增量注册列表,存入本地缓存。

@Slf4j
@Component
@EnableScheduling
public class EurekaDeltaAppsTask implements SchedulingConfigurer {
   
    @Autowired
    private ConfigBean configBean;
    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
   
        scheduledTaskRegistrar.addTriggerTask(() -> eurekaDeltaAppsInfo(),
                triggerContext -> {
   
                    String cron = configBean.getEurekainstanceCron();
                    if (StringUtils.isEmpty(cron)) {
   
                        cron = "*/3 * * * * ?";
                    }
                    return new CronTrigger(cron).nextExecutionTime(triggerContext);
                });
    }
    // 增量拉取分片注册中心服务列表
    private void eurekaDeltaAppsInfo() {
   
        List<String> allSubDomainId = configBea
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值