java - Zuul 作为具有负载平衡的反向代理,动态更新服务器列表
问题描述
我已经将我的 Zuul 作为反向代理,动态更新保存在数据库中的所有路由,并且运行良好。
我想要实现的是还能够使用负载平衡(功能区)为刚刚更新的每个 zuul 路由动态设置“列表操作系统服务器”。
到目前为止我所拥有的:
public class DiscoveryRouteLocator extends SimpleRouteLocator implements RefreshableRouteLocator {
@Autowired
Logger logger;
private ZuulProperties properties;
private ZuulRouteRepository zuulRouteRepository;
public DiscoveryRouteLocator(String servletPath, ZuulProperties properties, ZuulRouteRepository zuulRouteRepository) {
super(servletPath, properties);
this.properties = properties;
this.zuulRouteRepository = zuulRouteRepository;
}
@Override
public void refresh() {
doRefresh();
}
@Override
protected Map<String, ZuulProperties.ZuulRoute> locateRoutes() {
LinkedHashMap<String, ZuulProperties.ZuulRoute> routesMap = new LinkedHashMap<String, ZuulProperties.ZuulRoute>();
// Load default routes
routesMap.putAll(super.locateRoutes());
// Custom load route information
routesMap.putAll(getRouteList());
// Adjust the correct route configuration
LinkedHashMap<String, ZuulProperties.ZuulRoute> values = new LinkedHashMap<>();
for (Map.Entry<String, ZuulProperties.ZuulRoute> entry : routesMap.entrySet()) {
String path = entry.getKey();
// Add slash if there isn't
if (!path.startsWith("/")) {
path = "/" + path;
}
if (StringUtils.hasText(this.properties.getPrefix())) {
path = this.properties.getPrefix() + path;
if (!path.startsWith("/")) {
path = "/" + path;
}
}
values.put(path, entry.getValue());
}
return values;
}
private LinkedHashMap<String, ZuulProperties.ZuulRoute> getRouteList() {
LinkedHashMap<String, ZuulProperties.ZuulRoute> zuulRoutes = new LinkedHashMap<>();
List<RotaZuulEntity> lista = zuulRouteRepository.findByEnabledOrderByServiceId(true);
for (RotaZuulEntity rota : lista) {
if (Strings.isNullOrEmpty(rota.getPath()) && Strings.isNullOrEmpty(rota.getUrl())) {
continue;
}
ZuulProperties.ZuulRoute zuulRoute = new ZuulProperties.ZuulRoute();
try {
final Set<String> sensitiveHeaderSet = Sets.newHashSet();
sensitiveHeaderSet.add(""); // doesn't restrict any headers at all
zuulRoute.setId(rota.getServiceId());
zuulRoute.setPath(rota.getPath());
zuulRoute.setServiceId(rota.getServiceId());
zuulRoute.setRetryable(rota.getRetryable());
zuulRoute.setStripPrefix(rota.getStripPrefix());
zuulRoute.setUrl(rota.getUrl());
zuulRoute.setSensitiveHeaders(sensitiveHeaderSet);
String sensitiveHeaders = rota.getSensitiveHeadersList();
if (!Strings.isNullOrEmpty(sensitiveHeaders)) {
List<String> sensitiveHeadersList = Arrays.asList(sensitiveHeaders.split(","));
if (sensitiveHeadersList != null) {
//sensitiveHeaderSet = Sets.newHashSet();
sensitiveHeaderSet.clear();
sensitiveHeadersList.forEach(sensitiveHeader -> sensitiveHeaderSet.add(sensitiveHeader));
zuulRoute.setSensitiveHeaders(sensitiveHeaderSet);
zuulRoute.setCustomSensitiveHeaders(true);
}
}
} catch (Exception e) {
logger.error("ERROR SETTING ROUTES CONFIG FROM DATABASE", e);
}
zuulRoutes.put(zuulRoute.getPath(), zuulRoute);
logger.info("custom route set: path={}, serviceId={}", zuulRoute.getPath(), zuulRoute.getServiceId());
}
return zuulRoutes;
}
}
我有一个实现 ApplicationListener 的服务来实际完成动态工作。
@Service
public class RefreshRouteService implements ApplicationListener<ApplicationEvent> {
@Autowired
private ZuulHandlerMapping zuulHandlerMapping;
@Autowired
private ApplicationEventPublisher publisher;
@Autowired
private DiscoveryRouteLocator dynamicRouteLocator;
private HeartbeatMonitor heartbeatMonitor = new HeartbeatMonitor();
// Dispatch event to refresh the routes
public void refreshRoute() {
RoutesRefreshedEvent routesRefreshedEvent = new RoutesRefreshedEvent(dynamicRouteLocator);
publisher.publishEvent(routesRefreshedEvent);
}
// To monitor and detect refresh events on routes
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ContextRefreshedEvent || event instanceof RefreshScopeRefreshedEvent || event instanceof RoutesRefreshedEvent) {
// Reload manually all routes, just by setting tye dirty property
zuulHandlerMapping.setDirty(true);
} else if (event instanceof HeartbeatEvent) {
// Apdated by the applcation itself
HeartbeatEvent heartbeatEvent = (HeartbeatEvent) event;
if (heartbeatMonitor.update(heartbeatEvent.getValue())) {
zuulHandlerMapping.setDirty(true);
}
}
}
}
在application.properties
我只有这四个服务的基本配置中,没有关于路由的任何内容放在这个配置文件中:
# Hystrix
hystrix.command.default.execution.isolation.strategy=THREAD
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=600000*4
hystrix.command.default.execution.isolation.thread.interruptOnTimeout=false
# Ribbon
ribbon.ReadTimeout: 600000
ribbon.ConnectTimeout: 600000
# Eureka
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
eureka.client.healthcheck.enabled=true
eureka.client.should-unregister-on-shutdown=true
eureka.instance.lease-renewal-interval-in-seconds=2
eureka.server.wait-time-in-ms-when-sync-empty=0
eureka.server.enable-self-preservation=false
eureka.server.expected-client-renewal-interval-seconds=3
eureka.server.eviction-interval-timer-in-ms=2000000
eureka.instance.registry.default-open-for-traffic-count=0
eureka.instance.lease-expiration-duration-in-seconds=5
# Zuul
zuul.host.max-per-route-connections=10000
zuul.host.max-total-connections=5000
zuul.semaphore.max-semaphores=500
zuul.ribbon.eager-load.enabled= true
zuul.retryable=true
zuul.host.time-to-live=10000
zuul.host.time-unit=MILLISECONDS
zuul.prefix=/proxy
zuul.set-content-length=true
zuul.sensitive-headers=
zuul.add-host-header=true
通常当我们使用 Zuul 作为反向代理并手动设置路由时,我们有一个listOfServers
Ribbon 属性,它定义了负载平衡应该持续关注的服务器。
serviceId.ribbon.listOfServers=IP_ADDRESS1:PORT,IP_ADDRESS2:PORT
我想知道是否有人可以帮助如何实现这种负载平衡,但动态地,就像我们对路由所做的那样。
谢谢
解决方案
推荐阅读
- c++ - C++ 正确使用 cout wcout ifstream 读取带有重音字符的文本文件
- python - 无法导入 utils.programs 但成功导入 utils - python3 导入错误
- react-router-dom - react-router-dom 在多个 / in url 上给出 404
- c++ - Magick++/NAPI 模块内存泄漏
- html - CSS:旋转 90 度导航并坚持到左上角
- reactjs - React - 应用程序自定义路由在发布模式下不起作用
- python - cv::VideoCapture::open VIDEOIO(CV_IMAGES): 引发 OpenCV 异常
- c++ - 使用 Bazel 为 ARM 32 交叉编译 TensorFlow 1.15 时出错
- clojure - 显示并行 Clojure 数组和范围值
- asp.net - 引用的表不在字典中