写点什么

分布式不来点网关都说不过去

作者:zxhtom
  • 2022 年 7 月 06 日
  • 本文字数:3311 字

    阅读完需:约 11 分钟





通过路由代理角度、解读集中常见的路由代理方式

常见方式

nginx+lua

  • nginx 是一种高性能 HTTP 反向代理服务器。在我们之前的项目中我们使用 nginx 主要有两种用途: 方向代理+静态资源服务器管理

  • 点我下载哦

  • 下载完成之后 nginx 的启动也很是方便,笔者这里演示的是 windows 版本的。你可以直接点击应用程序也可以直接通过命令行模式启动./nginx或者nginx。看具体系统


服务代理

  • 正常情况下的代理是使用发哦 HTTP 下的 Server 来配置的。比如我们下面需要简单代理下我们某个服务http://192.168.44.131:9200 .。我们想要的效果就是通过本地 localhost 就可以访问到这个服务提供的接口了。


server {        listen 9200;        server_name localhost;        location / {            proxy_pass   http://192.168.44.131:9200;            #root   html;            #index  index.html index.htm;        }    }
复制代码


  • 当然配置结束后我们需要进行nginx -s reload进行重启 nginx 才能重新加载配置。这个时候我们访问localhost:9200/zxhtom/start实际上就是被代理到http://192.168.44.131:9200/zxhtom/start这个接口上。

静态资源代理

  • 上面我们说了除了服务代理之外。nginx 还可以作为静态资源服务器使用。


server{        listen 90;        server_name localhost;        location / {            root D:\study\PageOffice_4.6.0.3_Java;            index index.html;        }    }
复制代码


  • 同样是使用了 HTTP 下的 SERVER 。 这段代码表示将本地D:\study\PageOffice_4.6.0.3_Java这个文件夹作为本地 90 端口的入口。我们通过localhost:90/index.html就能访问到本地的D:\study\PageOffice_4.6.0.3_Java\index.html文件了。

负载均衡

upstream redis {            hash $remote_addr consistent;            # $binary_remote_addr;            server 192.168.44.131:6379 weight=5 max_fails=3 fail_timeout=30s;      server 192.168.44.132:6379 weight=1 max_fails=3 fail_timeout=30s;        }        server {            listen 6379;#redis服务器监听端口            proxy_connect_timeout 10s;            proxy_timeout 300s;#设置客户端和代理服务之间的超时时间,如果5分钟内没操作将自动断开。            proxy_pass redis;        }
复制代码


  • 有的时候我们服务并不仅仅是单节点服务。如果是分布式的话我们需要对服务进行负载均衡策略。这个时候我们就无法仅仅代理服务了。需要我们添加负载策略。我们通过upstream 来定义服务,并对服务进行策略定义。最后我们在 server 中直接时候用upstream的服务名就可以了。其中的 weight 就是对集群中服务轮询的权重设置。

常用命令

重启: nginx.exe -s reload 关闭:nginx.exe -s stop 检测配置合法性:nginx.exe -t

zuul

  • zuul 是 netflix 开源项目,关于 zuul 的深入浅出我在之前的文章中解析的应该算是很全面了。点我看zuul章节

  • 通过 zuul 我们可以实现动态路由、认证授权、动态过滤器、最终要的是可以自定义还可以结合 hystix 进行服务熔断

  • zuul 还可以实现灰度发布这个可以解决我们的停机发布问题。想想如果你的系统是 24 小时不能停机的那么 zuul 实现灰度发布

灰度扩展


  • 上述我们通过请求中指定的参数实现了路由的转发实现原理是借助了 eureka 的 metadata 的参数属性路由的。

  • 但是我们在平时应该遇到过有些软件对不同地区进行不同对待。

  • 比如说支付宝蚂蚁森林不同城市有不同的策略

  • 比如说某软件邀请你参与内侧版本使用

  • 上述都统称为灰度发布,原理也很简单实际上就是有多个实例,zuul 根据请求的特征转发到不同的实例上。不同城市就是根据地区来路由,邀请内侧就是通过个人用户信息来路由。他们的实现都离不开我们上面描述的Ribbon.Predicate 。想要对灰度发布进行扩展我们就离不开Predicate

Predicate

  • 该类的作用就是进行断言,是 google 提出的思想。具体有关 google轻轻点我

  • 在 ribbon 专题中,我们简单的通过源码阅读的方式了解了 ribbon 是如何进行负载均衡以及内部负载均衡的策略的。有兴趣的可以点击主页查找。

  • 今天我们来看看 ribbon 在负载均衡之前是如何在获取服务列表之后进行过滤的。


//根据输入返回断言  true  or  false@GwtCompatiblepublic interface Predicate<T> {  //针对输入内容进行断言,该方法有且不仅有如下要求: 1、不会造成任何数据污染 2、在T的equals中相等在apply中是相同效果  boolean apply(@Nullable T input);  //返回两个Predicate是否相同。一般情况Predicate实现是不需要重写equals的 。 如果实现可以根据自己需求表明predicate是否相同。什么叫做相同就是两个predicate对象apply的结果相同即为对象相同  @Override  boolean equals(@Nullable Object object);}
复制代码


  • 下面我们通过 Predicate 来实现下简单数据过滤。当然有的人会说为什么不用 java8 stream 过滤呢。这里只是为了为 Ribbon 中服务过滤铺路。至于 ribbon 为什么不使用流操作呢?个人角色 google 的 Predicate 在解耦上更加的方便吧。


  @Test    public void pt() {        List<User> userList = new ArrayList<>();        for (int i = 0; i < 100; i++) {            userList.add(new User(Long.valueOf(i+1), "张三"+(i+1)));        }
Predicate<User> predicate = new Predicate<User>() { @Override public boolean apply(User user) { return user.getId() % 2 == 0; } }; ArrayList<User> users = Lists.newArrayList(Iterables.filter(userList, predicate)); System.out.println(users); }
复制代码

AbstractServerPredicate

前提回要

  • 上面我们的类结构图中可以看出AbstractServerPredicatePredicate 的实现类。这个类也是 Ribbon 在获取服务列表的关键角色。因为后面都是基于这个类进行功能扩展的。


jmnarloch 初识

  • 这是我在 RIbbon 中的内容。我们可以知道 Ribbon 最终是在BaseLoadBalancer 中进行负载均衡的。其内部的 rule 默认是new RoundRobinRule() ,因为我们引入了io-jmnarloch 。先看看内部的类结构



  • io-jmnarloch 内部不是很复杂,至少 Ribbon、feign 这些比起来他真的是简单到家了。内部一个四个 package


注册负载 Rule


  • 我们可以看到在 support 包中的RibbonDiscoveryRuleAutoConfiguration 中配置了 rule 包下定义好的 Ribbon 的负载均衡类 Rule。



  • 断电打到BaseLoadBalancer 中我们可以看到 rule 就是我们rule.MetadataAwareRule 这个类。这里和 ribbon 章节说的好像有出入,我们在 ribbon 章节说需要自定义 rule 的时候需要在@RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration = MySelfRule.class) 这种方式。

  • 其实在配置DiscoveryEnabledRule 的时候在注册的时候有 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) 表示作用域

MetadataAwareRule 如何过滤服务


  • 通过MetadataAwareRule 结合代码我们可以了解到最终是 PredicateBaseRule#choose 在选择服务列表




  • 这个 predicate 就是我们 choose 中 getPredicate()方法获取的。所以在 ribbon 进行选择服务之前会通过MetadataAwarePredicate 进行过滤服务。

  • 获取到过滤器对象后,我们就会执行chooseRoundRibbinAfterFiltering .

回到 AbstractServerPredicate


  • 上文说到最终会通过 Predicate 去执行 chooseRoundRobinAfterFiltering。 还记得一开始 predicate 的结构图了吗。MetadataAwarePredicate最终继承AbstractServerPredicate 。 而AbstractServerPredicate # chooseRoundRobinAfterFiltering 是依赖 getEligibleServers`来获取合适的服务列表的。

  • AbstractServerPredicate 实现了好多 chooseXXX 的方法。因为 ribbon 默认是轮询方式所以在 BaseLoadBalance 中是选择 Round 对应的方法。这些我们都可以自己去修改方式。这里不赘述

  • Eligible 译为合适的。getEligibleServers 翻译过来是获取合适的服务列表。



  • 我们很明显的可以看到最终过滤的逻辑落在了 apply 方法上。



  • 这就是我们上述通过metadata-map:lancher 配置我们的服务信息。

  • 下面是AbstractServerPredicate 精简后样子。主要就是getEligibleServers 这个方法。


子类

  • 在上面AbstractServerPredicate 结构图中我们可以看到除了DiscoveryEnabledPredicate 这个子类外,还有四个子类。



发布于: 刚刚阅读数: 3
用户头像

zxhtom

关注

还未添加个人签名 2019.08.19 加入

还未添加个人简介

评论

发布
暂无评论
分布式不来点网关都说不过去_7月月更_zxhtom_InfoQ写作社区