我有一个3个前端应用程序和3个后端应用程序,假设1个虚拟机同时托管前端和后端应用程序,如下图所示,每个前端应用程序使用发现连接到后端由Zookeeper驱动的客户端。
现在,我想创建网络亲缘关系或区域,以使FE1连接到BE1(如果可用),如果BE1断开则连接到BE2 / BE3。可以在spring-cloud-zookeeper中实现吗?
尽管可以使用eureka来完成,但是我更喜欢使用zookeeper。
编辑
好吧,在eureka中,我们可以设置区域字段,并且功能区可以基于从eureka中为每个服务器检索的区域字段在客户端中进行区域亲缘关系。问题是在Zookeeper中,尽管功能区使用相同的zonepreference过滤器,但是由于Zookeeper没有通过区域信息,因此它始终为UNKNOWN
,因此未应用区域过滤。
作为解决方法,我尝试的是在注册服务时将区域信息作为元数据传递,如下所示。
spring:
application:
name: kp-zk-server
cloud:
zookeeper:
discovery:
metadata:
zone: default
现在,客户端中将创建功能区配置,如下所示从元数据中检索区域信息作为过滤器。
@Configuration
public class DefaultRibbonConfig {
@Value("${archaius.deployment.zone:default}")
private String zone;
private Predicate<Server> filter = server -> {
if (server instanceof ZookeeperServer) {
ZookeeperServer zkServer = (ZookeeperServer) server;
String str = zkServer.getInstance().getPayload().getMetadata().get("zone");
return zone.equals(str);
}
return true;
};
@Bean
public ServerListFilter<Server> ribbonServerListFilter(IClientConfig config) {
return new ServerListFilter<Server>() {
@Override
public List<Server> getFilteredListOfServers(List<Server> servers) {
List<Server> selected = servers.stream().filter(filter).collect(Collectors.toList());
return selected.isEmpty() ? servers : selected;
}
};
}
}
boostrap.yml
archaius:
deployment:
zone: Zone1
spring:
application:
name: kp-zk-consumer
cloud:
zookeeper:
dependency:
enabled: true
resttemplate:
enabled: false
discovery:
enabled: true
default-health-endpoint: /actuator/health
dependencies:
kWebClient:
path: /kp-zk-server
loadBalancerType: ROUND_ROBIN
required: true
#ribbon:
# NIWSServerListFilterClassName: io.github.kprasad99.zk.KZoneAffinityServerFilter
问题
现在的问题是我的自定义过滤器类未启用/使用,如果我使用@RibbonClients
@RibbonClients(defaultConfiguration = DefaultRibbonConfig.class)
但是,如果我使用ribbon.NIWSServerListFilterClassName
声明未应用过滤器,但是在这种情况下,我无法设置区域属性,需要对区域属性进行硬编码。
任何建议都值得赞赏。
答案 0 :(得分:0)
据我所知,开箱即用Zookeeper是不可能的。
但是,您可以通过使用import { FILTER_CARDS, FETCH_CARDS } from '../X/Y';
const initialState = { myPayload: [], filteredPayload: [] };
export default function (state = initialState, action) {
const { type, myPayload = [], value } = action;
const handler = {
[FETCH_CARDS]: {
...state,
myPayload,
},
[FILTER_CARDS]: {
...state,
filteredPayload: state.myPayload.filter(({ name }) => name.toLowerCase().match(value)),
},
};
return handler[type] || state;
}
和自定义[FILTER_CARDS]: {
...state,
filteredPayload: (state.myPayload.type == ('student' || 'teacher')
? (state.myPayload.filter(({ name }) => name.toLowerCase().match(value)),
state.myPayload.filter(({ age }) => age.toLowerCase().match(value)),
state.myPayload.filter(({ height }) => height.toLowerCase().match(value)))
: (state.myPayload.filter(({ name }) => name.toLowerCase().match(value)),
state.myPayload.filter(({ country }) => country.toLowerCase().match(value)),
state.assetsPayload.filter(({ state }) => state.toLowerCase().match(value)))),
},
来实现相同的结果,该自定义扩展spring-cloud-loadbalancer
并根据已设置的给定元数据过滤实例,或者返回发现的完整列表实例(如果没有一个符合标准)为您提供一些备用。
这是一个通用解决方案,即使您正在同一数据中心中运行,也可以解决您的问题。
希望这会有所帮助!