zuul改造,高可用故障转移,无eureka

2020-02-22 13:35

spring colud 版本:Dalston.SR5

zuul版本<zuul.version>1.3.0</zuul.version>

基于以上版本实践并测试。

1. zuul的配置 去掉eureka,手动设置服务列表

zuul:
    host:
        max-per-route-connections: 60000
        socket-timeout-millis: 60000
        connect-timeout-millis: 60000
    routes:
        service-name:
            path: /service-path/**
            serviceId: service-name

service-name:
    ribbon:
        listOfServers: 127.0.0.1:8092,127.0.0.1:9090
        ServerListRefreshInterval: 5000
        eureka:
            enabled: false
        NFLoadBalancerPingClassName: com.pkg.zuul.balancer.HttpStatusCodePing
        NFLoadBalancerRuleClassName: com.pkg.zuul.balancer.UpServerRoundRule
        HttpPingEndPoint: hello.json

2. 实现类HttpStatusCodePing

public class HttpStatusCodePing extends AbstractLoadBalancerPing {

private String endPoint = "info";

private final static CommonClientConfigKey endPointKey = new CommonClientConfigKey<Boolean>("HttpPingEndPoint"){};

public boolean isAlive(Server server) {

String urlStr = "http://" + server.getHostPort() + "/" + endPoint;

boolean isAlive = false;
HttpClient httpClient = new DefaultHttpClient();
HttpUriRequest getRequest = new HttpGet(urlStr);
try {
HttpResponse response = httpClient.execute(getRequest);
isAlive = (response.getStatusLine().getStatusCode() == 200); // 根据状态码和返回的内容来判定服务实例是否有效
} catch (Exception e) {
log.warn("server "+ server + "not alive.");
} finally {
// Release the connection.
getRequest.abort();
}
return isAlive;
}


@Override
public void initWithNiwsConfig(IClientConfig iClientConfig) {
this.endPoint = iClientConfig.getPropertyAsString(endPointKey,"info");
}
}

3. 实现类UpServerRoundRule,修改自RoundRobinRule。

public class UpServerRoundRule extends RoundRobinRule {

private AtomicInteger nextServerCyclicCounter;

public UpServerRoundRule() {
nextServerCyclicCounter = new AtomicInteger(0);
}

@Override
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
log.warn("no load balancer");
return null;
}

Server server = null;
int count = 0;
while (server == null && count++ < 10) {
List<Server> reachableServers = lb.getReachableServers();
int upCount = reachableServers.size();
if (upCount == 0) {
log.warn("No up servers available from load balancer: " + lb);
return null;
}

int nextServerIndex = incrementAndGetModulo(upCount);
server = reachableServers.get(nextServerIndex);

if (server == null) {
/* Transient. */
Thread.yield();
continue;
}

if (server.isAlive() && (server.isReadyToServe())) {
return (server);
}

// Next.
server = null;
}

if (count >= 10) {
log.warn("No available alive servers after 10 tries from load balancer: "
+ lb);
}
return server;
}

private int incrementAndGetModulo(int modulo) {
for (;;) {
int current = nextServerCyclicCounter.get();
int next = (current + 1) % modulo;
if (nextServerCyclicCounter.compareAndSet(current, next))
return next;
}
}
}


以上配置后实现的效果。

每5秒由zuul向所有服务器列表,请求配置的路径http请求,以返回码是否是200判断 是否存活,在zuul代理时,只会从启动的服务器里面进行循环负载。当一台服务器down后不会向其发送请求。

没有如上配置zuul默认使用的是ZoneAvoidanceRule,ping是直接返回true的方式。策略比较适合N台服务器。其会根据服务器的响应情况进行判断,没有retry的话用户的真实请求就404了。

以上配置比较适合2~3台,再多建议使用默认配置。