zoukankan      html  css  js  c++  java
  • Spring Cloud开发人员如何解决服务冲突和实例乱窜?(IP实现方案)

    file

    一、背景

    在我上一篇文章《Spring Cloud开发人员如何解决服务冲突和实例乱窜?》中提到使用服务的元数据来实现隔离和路由,有朋友问到能不能直接通过IP来实现?本文就和大家一起来讨论一下这个问题

     

    二、可行性分析

    要实现通过IP来隔离和路由的话有一个非常关键的点需要解决,就是怎样实现IP可辨识,意思就是如何区分那个IP服务器上的,那个IP开发人员本机

    file

    如上图所示其实我们还是能找到规律可以辨识的,所以这个是可以行的!

    • 开发人员本机IP - 其实就是客户端IP,也就是原始请求方的IP172.16.20.2
    • 服务器IP - 可以理解为服务器上的服务所在机器的IP(有点绕):172.16.20.1

     

    三、路由规则逻辑

    主要实现以下目标:

    1. 普通用户访问服务器上的页面时,请求的所有路由只调用服务器上的实例
    2. 开发A访问时,请求的所有路由优先调用开发A本机启动的实例,如果没有则调用服务器上的实例
    3. 开发B访问时同上,请求的所有路由优先调用开发B本机启动的实例,如果没有则调用服务器上的实例

    在找到IP的辨识规律后,推导出下面3个路由规则来实现上面的目标

    1. 优先匹配原始请求方的IP的服务实例
    2. 再者匹配上游服务所在机器IP的服务实例
    3. 上面2个逻辑都匹配不到的话使用轮询的方式找一个实例

     
    具体的自定义负载均衡的对象怎么写我这里就不详细描述了,可以参考我上一篇文章《Spring Cloud开发人员如何解决服务冲突和实例乱窜?

     

    四、获取原始请求方的IP

    获取原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添加到headerHTTP_X_FORWARDED_FOR里面传递给下游服务

    RequestContext ctx = RequestContext.getCurrentContext();
    HttpServletRequest request = ctx.getRequest();
    String sourceIp = getIpAddr(request);
    ctx.getZuulRequestHeaders().put("HTTP_X_FORWARDED_FOR", sourceIp);
    

     

    五、获取服务器所在机器的IP

    直接使用JDK自带的InetAddress就可以了

    String localIp = InetAddress.getLocalHost().getHostAddress()
    

     

    六、总结

    通过IP的方案来实现开发环境服务实例隔离和策略路由后,可以实现到开发完全无感知,既不需要配置元数据,也不需要自己去传version之类的参数了。
    但是这个方案其实也是有局限性

    1. 开发服务器必须是只用一台来部署所有的服务,因为如果上游服务和下游服务不在同一个IP上就失去了辨识能力了
    2. 因为网络环境比较复杂,不一定能获取到客户端的真实原IP
    3. 开发人员启动客户端/前端的机器与启动后台服务必须是同一台电脑上才行;例如如果是前端开发人员A启动的客户端,去调试后台开发人员B启动的服务就不行了,因为原IP与注册上去的服务实例IP匹配不上

     
    最后可能大家会问原IP怎样全链路传递下去?链路传递可以参考一下我的另外一篇文章《日志排查问题困难?分布式日志链路跟踪来帮你

     

    推荐阅读

     
    扫码关注有惊喜!

    file

  • 相关阅读:
    港股通不得不了解的汇率问题
    Red and Black(红与黑)BFS
    什么时候用DFS,什么时候用BFS?(DFS和BFS的特点和异同)
    (最详细解答) 问题 B: DFS or BFS?
    HDU 2181 哈密顿绕行世界问题 (dfs)
    codeup 算法笔记【递归入门】组合+判断素数
    DFS--基本入门模板 和 例题 (绝对入门) (最全)
    福州大学在线测评系统 FZU 1013 RP Game
    2018 ACM 国际大学生程序设计竞赛上海大都会赛重现赛 C Thinking Bear magic
    ACM 数论-博弈 (比赛用)
  • 原文地址:https://www.cnblogs.com/zlt2000/p/11474327.html
Copyright © 2011-2022 走看看