微服务架构-SpringCloudAlibaba-098:Gateway高可用集群与动态网关

1 网关部署实现集群设计思路

课程内容:

  1. Gageway如何实现集群
  2. Gateway集群部署方案
  3. Gateway如何实现动态网关
  4. Gateway动态网关部署方案

如果网关宕机,会出现什么情况?如何解决?
导致整个微服务无法通讯。网关实现集群。
网关实现集群如何访问?
使用Nginx或者lvs虚拟vip。

2 基于Nginx部署GateWay集群环境

环境配置:
网关1:127.0.0.1:81
网关2:127.0.0.1:82
Nginx服务器:127.0.0.1:80

网关的请求头中放端口号

@Component
public class TokenGlobalFilter implements GlobalFilter {

    @Value("${server.port}")
    private String serverPort;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 如何获取参数
        String token = exchange.getRequest().getQueryParams().getFirst("token");
        if (StringUtils.isEmpty(token)) {
            ServerHttpResponse response = exchange.getResponse();
            response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
            String msg = "token not is null ";
            DataBuffer buffer = response.bufferFactory().wrap(msg.getBytes());
            return response.writeWith(Mono.just(buffer));
        }
        // 在请求头中存放serverPort
        ServerHttpRequest request = exchange.getRequest().mutate().header("serverPort", this.serverPort).build();
        // 直接转发到真实服务
        return chain.filter(exchange.mutate().request(request).build());
    }
}

会员服务接收网关请求

@RestController
public class MemberServiceImpl implements MemberService {

    @Value("${server.port}")
    private String serverPort;

    @Override
    public String getUser(Integer userId) {
        return "我是会员服务,端口号为:" + serverPort;
    }

    @Override
    public String member(HttpServletRequest request) {
        String serverPort = request.getHeader("serverPort");
        return "this is member,网关端口号为:" + serverPort;
    }
}

修改hosts文件(C:\Windows\System32\drivers\etc)
127.0.0.1 gw.mayikt.com
修改Nginx相关配置

http {
    upstream mayiktgwadds {
	server 127.0.0.1:81;
	server 127.0.0.1:82;
	}
    server {
        listen       80;
        server_name  gw.mayikt.com;
        location / {
            proxy_pass   http://mayiktgwadds/;
        }
    }
}

测试效果:
在这里插入图片描述

3 部署动态GateWay的思路

动态网关:任何配置都实现不用重启网关服务器就可以及时刷新网关配置。
实现思路:

  1. 分布式配置中心 不建议使用,需要定义json格式配置,阅读性差
  2. 基于数据库表结构设计 建议
    注意:配置中心实现维护性比较差,建议采用数据库形式设计。

4 基于数据库形式构建动态网关

基于数据库表形式设计
网关已经提供了api接口
1.直接新增
2.直接修改

思路:

  1. 默认加载时,当网关服务启动的时候,从数据库查询网关的配置,将数据库的内容读取到网关内存中。
  2. 网关配置更新时,更新数据库,调用网关api更新接口。

网关服务相关表

CREATE TABLE `gateway`.`mayikt_gateway` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `route_id` varchar(11) DEFAULT NULL,
  `route_name` varchar(255) DEFAULT NULL,
  `route_pattern` varchar(255) DEFAULT NULL,
  `route_type` varchar(255) DEFAULT NULL,
  `route_url` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;
INSERT INTO `gateway`.`mayikt_gateway`(`id`, `route_id`, `route_name`, `route_pattern`, `route_type`, `route_url`) VALUES (1, 'member', 'mayiktmember', '/member/**', '0', 'mayikt-member');
INSERT INTO `gateway`.`mayikt_gateway`(`id`, `route_id`, `route_name`, `route_pattern`, `route_type`, `route_url`) VALUES (2, 'mayikt', 'mayikt', '/mayikt/**', '1', 'http://www.mayikt.com');

5 代码实现创建动态网关实现

maven依赖

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.0.RELEASE</version>
</parent>
<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
        <version>2.0.0.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        <version>0.2.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>

    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>1.1.1</version>
    </dependency>
    <!-- mysql 依赖 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <!-- 阿里巴巴数据源 -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.0.14</version>
    </dependency>
</dependencies>

代码实现

@Data
public class GatewayEntity {
    private Long id;
    private String routeId;
    private String routeName;
    private String routePattern;
    private String routeType;
    private String routeUrl;
}
public interface MayiktGatewayMapper {

    @Select("SELECT ID AS ID, route_id as routeid, route_name as routeName,route_pattern as routePattern\n" +
            ",route_type as routeType,route_url as routeUrl\n" +
            " FROM mayikt_gateway\n")
    public List<GatewayEntity> gateWayAll();

    @Update("update mayikt_gateway set route_url=#{routeUrl} where route_id=#{routeId};")
    public Integer updateGateway(@Param("routeId") String routeId, @Param("routeUrl") String routeUrl);
}
@RestController
public class GatewayController {

    @Autowired
    private GatewayService gatewayService;

    @RequestMapping("/synGatewayConfig")
    public String synGatewayConfig(){
        return gatewayService.loadAllLoadRoute();
    }
}
@Service
public class GatewayService implements ApplicationEventPublisherAware {

    private ApplicationEventPublisher publisher;

    @Resource
    private RouteDefinitionWriter routeDefinitionWriter;
    @Resource
    private MayiktGatewayMapper mayiktGatewayMapper;

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.publisher = applicationEventPublisher;
    }

    public String loadAllLoadRoute() {
        List<GatewayEntity> gateWayEntities = mayiktGatewayMapper.gateWayAll();
        for (GatewayEntity gb :
                gateWayEntities) {
            loadRoute(gb);
        }
        return "success";
    }

    public String loadRoute(GatewayEntity gateWayEntity) {
        RouteDefinition definition = new RouteDefinition();
        Map<String, String> predicateParams = new HashMap<>(8);
        PredicateDefinition predicate = new PredicateDefinition();
        FilterDefinition filterDefinition = new FilterDefinition();
        Map<String, String> filterParams = new HashMap<>(8);
        URI uri = null;
        if ("0".equals(gateWayEntity.getRouteType())) {
            // 如果配置路由type为0的话 则从注册中心获取服务地址
            uri = UriComponentsBuilder.fromUriString("lb://" + gateWayEntity.getRouteUrl() + "/").build().toUri();
        } else {
            uri = UriComponentsBuilder.fromHttpUrl(gateWayEntity.getRouteUrl()).build().toUri();
        }

        // 定义的路由唯一的id
        definition.setId(gateWayEntity.getRouteId());
        predicate.setName("Path");
        //路由转发地址
        predicateParams.put("pattern", gateWayEntity.getRoutePattern());
        predicate.setArgs(predicateParams);

        // 名称是固定的, 路径去前缀
        filterDefinition.setName("StripPrefix");
        filterParams.put("_genkey_0", "1");
        filterDefinition.setArgs(filterParams);
        definition.setPredicates(Arrays.asList(predicate));
        definition.setFilters(Arrays.asList(filterDefinition));
        definition.setUri(uri);
        routeDefinitionWriter.save(Mono.just(definition)).subscribe();
        this.publisher.publishEvent(new RefreshRoutesEvent(this));
        return "success";
    }
}
@SpringBootApplication
@MapperScan("com.mayikt.mapper")
public class AppGateWay {
    public static void main(String[] args) {
        SpringApplication.run(AppGateWay.class);
    }
}

测试效果:
在这里插入图片描述

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值