基於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匹配的路徑就能訪問了,每次修改數據庫的路由信息后,只要重新加載,就能夠實現動態網關服務。