Spring Cloud Actual Spring Cloud Gateway Canary Grayscale Release

Java
В этой статье будет реализована более глубокая реализация динамической маршрутизации.Идеи реализации следующие:
  • 1. Создайте проект обслуживания информации о маршрутизации (динамический маршрут), чтобы реализовать добавление, удаление, изменение и запрос информации о маршрутизации в mysql.
  • 2. Обеспечьте функцию публикации.После публикации информация о маршрутизации и информация о версии сохраняются в Redis, а остальной интерфейс предоставляется извне для получения информации о маршрутизации.
  • 3. Шлюз (шлюз-динамический-маршрут) запускает запланированную задачу, регулярно извлекает последнюю версию информации о маршрутизации, опубликованную в остальном интерфейсе, и сравнивает номера версий.Если номер версии шлюза не соответствует номеру версии в Остальной интерфейс, получить информацию о маршрутизации и обновить ее.
  • 4. Общая архитектура разработана следующим образом:
    在这里插入图片描述

Согласно вышеизложенным идеям реализуется код, ниже будут созданы два проекта, которые необходимо зарегистрировать на eureka.

  • динамический маршрут, проект маршрутизации
  • шлюз-динамический-маршрут, шлюз, информация о маршрутизации не настроена по умолчанию (не перенаправляется в службу-потребитель)
  • потребительская служба, потребительская служба, перенаправляет запросы в эту службу после настройки динамической маршрутизации.
2. Создайте динамический маршрут проекта обслуживания информации о маршрутизации, чтобы реализовать функции добавления, удаления, изменения, запроса и публикации информации о маршрутах. Информация сохраняется в mysql, а затем после публикации сохраняется в Redis. Когда данные маршрутизации предоставляются извне, информация о маршрутизации в Redis возвращается (используя Cache для ответа на запросы чтения задачи синхронизации шлюза)
  • Есть две таблицы, таблица информации о маршрутизации и таблица выпуска версии.Структура таблицы следующая:
    在这里插入图片描述
  • Реализация добавления, удаления, изменения и проверки не расширяется по одной из-за нехватки места.Вы можете просмотреть код проекта, который был загружен в облако кода.Следующие страницы размещены на проекте.Страницы относительно просто.
    在这里插入图片描述
    在这里插入图片描述
    Ниже приводится информация о версии и информация о маршрутизации, возвращаемая оставшимся интерфейсом.Сначала шлюз получает номер версии и сравнивает его с локальным номером версии.Если он несовместим, информация о маршрутизации вытягивается через этот интерфейс.
    在这里插入图片描述
    Получить поддерживаемую информацию о маршрутизации
    在这里插入图片描述
3. Основное внимание уделяется проекту шлюза, создайте проект динамического маршрута шлюза, установите номер версии по умолчанию равным 0 при запуске шлюза, извлекайте проект удаленной маршрутизации каждые 60 секунд через запланированное задание, чтобы предоставить номер последней версии, и сравните с номером версии шлюза. Если он несовместим, извлеките последнюю информацию о маршрутизации проекта удаленной маршрутизации, обновите ее до маршрутизации шлюза и в то же время перезапишите номер локальной версии последним номером версии.

Из-за большого количества кода блог в основном делится идеями реализации и публикует ключевой код, который был отправлен в облако кода, вы можете скачать проект, чтобы просмотреть весь код.

  • 1. Запустите запланированное задание, зарегистрируйтесь в erueka, добавьте RestTemplate Bean и получите доступ к проекту маршрутизации в виде балансировки нагрузки.
@EnableScheduling
@EnableDiscoveryClient
@SpringBootApplication
public class GatewayDynamicRouteApplication {

	public static void main(String[] args) {
		SpringApplication.run(GatewayDynamicRouteApplication.class, args);
	}
	
	@Bean
	@LoadBalanced
	public RestTemplate restTemplate(){
		return new RestTemplate();
	}
}
  • 2. Класс реализации запланированной задачи
/**
 * 定时任务,拉取路由信息
 * 路由信息由路由项目单独维护
 */
@Component
public class DynamicRouteScheduling {

    @Autowired private RestTemplate restTemplate;
    @Autowired private DynamicRouteService dynamicRouteService;//动态路由实现类,与前篇博客中的实现类代码是一样的

    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    private static final String dynamicRouteServerName = "dynamic-route-service";

    //发布路由信息的版本号
    private static Long versionId = 0L;

    //每60秒中执行一次
    //如果版本号不相等则获取最新路由信息并更新网关路由
    @Scheduled(cron = "*/60 * * * * ?")
    public void getDynamicRouteInfo(){
        try{
            System.out.println("拉取时间:" + dateFormat.format(new Date()));
            //先拉取版本信息,如果版本号不想等则更新路由
            Long resultVersionId = restTemplate.getForObject("http://"+ dynamicRouteServerName +"/version/lastVersion" , Long.class);
            System.out.println("路由版本信息:本地版本号:" + versionId + ",远程版本号:" + resultVersionId);
            if(resultVersionId != null && versionId != resultVersionId){
                System.out.println("开始拉取路由信息......");
                String resultRoutes = restTemplate.getForObject("http://"+ dynamicRouteServerName +"/gateway-routes/routes" , String.class);
                System.out.println("路由信息为:" + resultRoutes);
                if(!StringUtils.isEmpty(resultRoutes)){
                    List<GatewayRouteDefinition> list = JSON.parseArray(resultRoutes , GatewayRouteDefinition.class);
                    for(GatewayRouteDefinition definition : list){
                        //更新路由
                        RouteDefinition routeDefinition = assembleRouteDefinition(definition);
                        dynamicRouteService.update(routeDefinition);
                    }
                    versionId = resultVersionId;
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }


    //把前端传递的参数转换成路由对象
    private RouteDefinition assembleRouteDefinition(GatewayRouteDefinition gwdefinition) {
        RouteDefinition definition = new RouteDefinition();
        definition.setId(gwdefinition.getId());
        definition.setOrder(gwdefinition.getOrder());

        //设置断言
        List<PredicateDefinition> pdList=new ArrayList<>();
        List<GatewayPredicateDefinition> gatewayPredicateDefinitionList=gwdefinition.getPredicates();
        for (GatewayPredicateDefinition gpDefinition: gatewayPredicateDefinitionList) {
            PredicateDefinition predicate = new PredicateDefinition();
            predicate.setArgs(gpDefinition.getArgs());
            predicate.setName(gpDefinition.getName());
            pdList.add(predicate);
        }
        definition.setPredicates(pdList);

        //设置过滤器
        List<FilterDefinition> filters = new ArrayList();
        List<GatewayFilterDefinition> gatewayFilters = gwdefinition.getFilters();
        for(GatewayFilterDefinition filterDefinition : gatewayFilters){
            FilterDefinition filter = new FilterDefinition();
            filter.setName(filterDefinition.getName());
            filter.setArgs(filterDefinition.getArgs());
            filters.add(filter);
        }
        definition.setFilters(filters);

        URI uri = null;
        if(gwdefinition.getUri().startsWith("http")){
            uri = UriComponentsBuilder.fromHttpUrl(gwdefinition.getUri()).build().toUri();
        }else{
            uri = URI.create(gwdefinition.getUri());
        }
        definition.setUri(uri);
        return definition;
    }
}
  • 3. Шлюз предоставляет контроллер, который получает всю информацию о маршрутизации.
/**
 * 查询网关的路由信息
 */
@RestController
@RequestMapping("/route")
public class DynamicRouteController {

    @Autowired private RouteDefinitionLocator routeDefinitionLocator;

    //获取网关所有的路由信息
    @RequestMapping("/routes")
    public Flux<RouteDefinition> getRouteDefinitions(){
        return routeDefinitionLocator.getRouteDefinitions();
    }
}
  • 4. Запустите eureka, dynamic-route, gateway-dynamic-route, Consumer-Service.

  • 5. Добавьте новую часть информации о маршрутизации через проект динамического маршрута, uri маршрута — потребительская служба, и маршрут будет опубликован.
    在这里插入图片描述
    При публикации маршрута в Redis будут добавлены номер последней версии и информация о маршрутизации из таблицы версий. На следующем рисунке показана информация о маршрутизации, сохраненная в Redis. Шлюз регулярно сначала получает информацию о версии и информацию о маршрутизации из Redis.
    在这里插入图片描述

  • 6. Поскольку шлюз не настроен с информацией о маршрутизации, вся информация о маршрутизации может быть получена через localhost: 9999/route/routes, В настоящее время существует две информации о маршрутизации, которые являются информацией о маршрутизации по умолчанию, извлеченной из eureka шлюзом. , а не сконфигурированная информация о маршрутизации.
    在这里插入图片描述

  • 7. Подождав 60 секунд, шлюз извлекает номер последней версии проекта динамического маршрута через RestTemplate. Если обнаруживается несоответствие, он извлекает последнюю информацию о маршрутизации и обновляет ее до маршрутизации шлюза.
    在这里插入图片描述

  • 8. Получите доступ к сервису-потребителю через шлюз, убедитесь, что информация о маршрутизации обновлена ​​для шлюза, и посетите:http://localhost:9999/zy/hello?name=zy
    在这里插入图片描述

  • 9. Снова проверьте всю информацию о маршрутизации, вы можете видеть, что потребительская служба была настроена на маршрутизацию шлюза.
    在这里插入图片描述

  • 10. Повторно сравнивайте номера версий каждые 60 секунд. При выпуске нового номера версии будет извлечена сохраненная информация о маршрутизации. В противном случае шлюз не будет обновлять маршрут.
    在这里插入图片描述

  • 11. Измените информацию о маршрутизации, измените утверждение Path=/zy/** на Path=/consumer/** и опубликуйте его. Через 60 секунд консоль шлюза получит последнюю информацию о маршрутизации.
    在这里插入图片描述
    посетить в это времяhttp://localhost:9999/zy/hello?name=zyСообщается об ошибке, поскольку путь утверждения маршрута был изменен, и маршрут недоступен.
    在这里插入图片描述
    нужно пройтиhttp://localhost:9999/consumer/hello?name=zyдоступ, возврат в обычном режиме
    在这里插入图片描述
    Ну вот и закончена продвинутая реализация динамической маршрутизации.Из-за нехватки места все коды не выложены.Блог в основном знакомит с идеями реализации динамической маршрутизации.Код можно реализовать по своим привычкам.

Код загружен в облако кода:

Информация о версии проекта выглядит следующим образом:

- SpringBoot 2.0.6.RELEASE
- SpringCloud Finchley.SR2

Реализовать публикацию в оттенках серого

Добавьте 2 маршрутные данные, тот же «шаблон»: «/cm1/**», укажите на разные сервисы, доступ



http://localhost:9999/cm1/hello?name=alex

Страница появляется случайным образом: hello alexfrom default, hello alexfrom b, указывая на то, что при балансировке нагрузки осуществляется доступ к двум службам, а вес можно регулировать, регулируя вес.

Ссылка на эту статью:blog.CSDN.net/Тема 199110…



yml в json

        - id: admin-service
          uri: lb://admin-service
          predicates:
          - Path=/admin/**
          - Weight=service1, 90
          filters:
          - SwaggerHeaderFilter
          - StripPrefix=1
        - id: order-service
          uri: lb://order-service
          predicates:
          - Path=/order-s/**
          filters:
          - SwaggerHeaderFilter
          - StripPrefix=1
        - id: test-service
          uri: lb://test
          predicates:
          - Path=/demo/**
          filters:
          - SwaggerHeaderFilter
          - StripPrefix=1
 
 
 
[
  {
    "route_id": "admin-service",
    "route_definition": {
      "id": "admin-service",
      "predicates": [
        {
          "name": "Path",
          "args": {
            "_genkey_0": "/admin/**"
          }
        },
        {
          "name": "Weight",
          "args": {
            "_genkey_0": "service1",
            "_genkey_1": "90"
          }
        }
      ],
      "filters": [
        {
          "name": "SwaggerHeaderFilter",
          "args": {}
        },
        {
          "name": "StripPrefix",
          "args": {
            "_genkey_0": "1"
          }
        }
      ],
      "uri": "lb://admin-service",
      "order": 0
    },
    "order": 0
  },
  {
    "route_id": "order-service",
    "route_definition": {
      "id": "order-service",
      "predicates": [
        {
          "name": "Path",
          "args": {
            "_genkey_0": "/order-s/**"
          }
        }
      ],
      "filters": [
        {
          "name": "SwaggerHeaderFilter",
          "args": {}
        },
        {
          "name": "StripPrefix",
          "args": {
            "_genkey_0": "1"
          }
        }
      ],
      "uri": "lb://order-service",
      "order": 0
    },
    "order": 0
  },
  {
    "route_id": "test-service",
    "route_definition": {
      "id": "test-service",
      "predicates": [
        {
          "name": "Path",
          "args": {
            "_genkey_0": "/demo/**"
          }
        }
      ],
      "filters": [
        {
          "name": "SwaggerHeaderFilter",
          "args": {}
        },
        {
          "name": "StripPrefix",
          "args": {
            "_genkey_0": "1"
          }
        }
      ],
      "uri": "lb://test",
      "order": 0
    },
    "order": 0
  }
]