在我上一篇文章《 Spring Cloud开发人员如何解决服务冲突和实例乱窜? 》中提到使用服务的 元数据 来实现隔离和路由,有朋友问到能不能直接通过 IP 来实现?本文就和大家一起来讨论一下这个问题
要实现通过 IP 来隔离和路由的话有一个非常关键的点需要解决,就是怎样实现 IP可辨识 ,意思就是如何区分那个 IP 是 服务器 上的,那个 IP 是 开发人员本机 的
如上图所示其实我们还是能找到规律可以辨识的, 所以这个是可以行的!
客户端IP ,也就是 原始请求方的IP : 172.16.20.2 主要实现以下目标:
服务器上的实例 开发A本机启动的实例 ,如果没有则调用 服务器上的实例 开发B本机启动的实例 ,如果没有则调用 服务器上的实例 在找到 IP 的辨识规律后,推导出下面3个 路由规则 来实现上面的目标
原始请求方的IP 上游服务所在机器IP
具体的自定义负载均衡的对象怎么写我这里就不详细描述了,可以参考我上一篇文章《 Spring Cloud开发人员如何解决服务冲突和实例乱窜? 》
获取 原IP 的代码片段如下,只需要在网关上增加一个过滤器获取IP,然后添加到header里面一直传递下去就可以了
/**
* 获取Ip地址
*/
private String getIpAddr(HttpServletRequest request){
String ip = request.getHeader("X-Forwarded-For");
if (isEmptyIP(ip)) {
ip = request.getHeader("Proxy-Client-IP");
if (isEmptyIP(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
if (isEmptyIP(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
if (isEmptyIP(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
if (isEmptyIP(ip)) {
ip = request.getRemoteAddr();
if ("127.0.0.1".equals(ip) || "0:0:0:0:0:0:0:1".equals(ip)) {
// 根据网卡取本机配置的IP
try {
ip = InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
log.error("InetAddress.getLocalHost()-error", e);
}
}
}
}
}
}
} else if (ip.length() > 15) {
String[] ips = ip.split(",");
for (int index = 0; index < ips.length; index++) {
String strIp = ips[index];
if (!isEmptyIP(ip)) {
ip = strIp;
break;
}
}
}
return ip;
}
private boolean isEmptyIP(String ip) {
if (StrUtil.isEmpty(ip) || UNKNOWN_STR.equalsIgnoreCase(ip)) {
return true;
}
return false;
}
把原IP添加到header的 HTTP_X_FORWARDED_FOR 里面传递给下游服务
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
String sourceIp = getIpAddr(request);
ctx.getZuulRequestHeaders().put("HTTP_X_FORWARDED_FOR", sourceIp);
直接使用JDK自带的 InetAddress 就可以了
String localIp = InetAddress.getLocalHost().getHostAddress()
通过 IP 的方案来实现 开发环境 服务实例隔离和策略路由后,可以实现到 开发完全无感知 ,既不需要配置 元数据 ,也不需要自己去传 version 之类的参数了。
但是这个方案其实也是有 局限性 的
IP 上就失去了辨识能力了 原IP 前端开发人员A 启动的客户端,去调试 后台开发人员B 启动的服务就不行了,因为 原IP 与注册上去的 服务实例IP 匹配不上 最后可能大家会问 原IP 怎样全链路传递下去?链路传递可以参考一下我的另外一篇文章《 日志排查问题困难?分布式日志链路跟踪来帮你 》