基于Nginx部署GateWay集群
网关集群可以通过Nginx与lvs实现,这里基于Nginx,实现比较简单。为nginx添加如下配置即可
upstream gateways {
server 127.0.0.1:81;
server 127.0.0.1:82;
}
server {
listen 80;
server_name localhost;
logs/host.access.log main;
...
location / {
proxy_pass http://gateways/;
}
...
}
动态网关
任何配置不用重启网关服务器都可以实现及时刷新网关配置。
实现方式:
- 分布式配置中心,不推荐
- 数据库,推荐,阅读性好
根据路由的相关配置,我们设计数据库表结构
CREATE TABLE `gateway_route` (
`id` int(11) primary key,
`route_id` varchar(255) DEFAULT NULL,#路由id
`route_name` varchar(255) DEFAULT NULL,
`route_pattern` varchar(255) DEFAULT NULL,#路径匹配规则
`route_type` varchar(255) DEFAULT NULL,#跳转类型,0时从注册中心获取地址,1直接跳转网络地址
`route_uri` varchar(255) DEFAULT NULL #与route_type相对应的地址
)
插入如下的路由信息,member-service是注册中心上的服务,可替换成自己的
根据数据库设计实体类
public class GateWayEntity {
private Long id;
private String routeId;
private String routeName;
private String routeType;
private String routeUri;
private String routePattern;
...
}
因为要从数据库获取路由信息,这里使用mybatis来访问数据库,接口如下
@Mapper
public interface GatewayRouteMapper {
//获取全部路由
List<GateWayEntity> getAllRoutes();
}
对应xml如下
<resultMap id="GateWay" type="com.github.zyq.entity.GateWayEntity">
<id column="id" property="id" ></id>
<result column="route_id" property="routeId"></result>
<result column="route_name" property="routeName"></result>
<result column="route_type" property="routeType"></result>
<result column="route_uri" property="routeUri"></result>
<result column="route_pattern" property="routePattern"></result>
</resultMap>
<select id="getAllRoutes" resultMap="GateWay">
select id,route_id,route_name,route_type,route_uri,route_pattern
from gateway_route
</select>
重点便是加载路由信息了,创建一个类实现ApplicationEventPublisherAware接口
@Service
public class GatewayService implements ApplicationEventPublisherAware {
private ApplicationEventPublisher publisher;
@Autowired
private RouteDefinitionWriter routeDefinitionWriter;
@Autowired
private GatewayRouteMapper gatewayRouteMapper;
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.publisher = applicationEventPublisher;
}
//从数据库获取全部路由,在将每个路由加载
public void getAllRoutes() {
List<GateWayEntity> routes = gatewayRouteMapper.getAllRoutes();
for (GateWayEntity route : routes) {
loadRoute(route);
}
}
//根据实体类加载路由
public String loadRoute(GateWayEntity gateWayEntity) {
//路由相关的配置
RouteDefinition routeDefinition = new RouteDefinition();
PredicateDefinition predicateDefinition = new PredicateDefinition();
FilterDefinition filterDefinition = new FilterDefinition();
Map<String,String> predicateParams = new HashMap<>(8);
URI uri = null;
//根据路由类型来决定如何跳转
if ("0".equals(gateWayEntity.getRouteType())) {
uri = UriComponentsBuilder.fromUriString("lb://"+gateWayEntity.getRouteUri()+"/").build().toUri();
} else {
uri = UriComponentsBuilder.fromHttpUrl(gateWayEntity.getRouteUri()).build().toUri();
}
//路由唯一id
routeDefinition.setId(gateWayEntity.getRouteId());
predicateDefinition.setName("Path");
//路由转发地址
predicateParams.put("pattern",gateWayEntity.getRoutePattern());
predicateDefinition.setArgs(predicateParams);
routeDefinition.setPredicates(Arrays.asList(predicateDefinition));
routeDefinition.setUri(uri);
routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();
this.publisher.publishEvent(new RefreshRoutesEvent(this));
return "seccess";
}
每次路由更改时,只要访问一下数据库,将路由信息加载即可。书写一个controller,调用一下service的getAllRoutes方法加载路由。
@RestController
public class GateWayController {
@Autowired
private GatewayService gatewayService;
@GetMapping("/load")
public String loadRoutes() {
gatewayService.getAllRoutes();
return "success";
}
}
访问一下/load路径加载路由信息,在route_pattern匹配的路径就能访问了,每次修改数据库的路由信息后,只要重新加载,就能够实现动态网关服务。