API网关—Ocelot之负载均衡

  • 负载均衡
  • 请求缓存


负载均衡

分布式架构中,当后端同一个应用的实例较多,负载均衡是非常必要的,否则前端对后端API的请求,可能只命中其中的几个应用实例,这几个实例压力会很大,而其他实例一直处于空闲状态,达不到分布式架构中利用服务器资源换取性能的效果。

Ocelot网关提供了负载均衡功能,通过配置文件即可实现,下面是Ocelot负载均衡功能的demo。

  1. 启动CustomerService的两个实例,修改以下之前的演示api让其放回不同的结果
    启动实例1:
  2. ngnix负载均衡到网关 网关做负载均衡_负载均衡


  3. ngnix负载均衡到网关 网关做负载均衡_ngnix负载均衡到网关_02

  4. 启动实例2:
  5. ngnix负载均衡到网关 网关做负载均衡_负载均衡_03


  6. ngnix负载均衡到网关 网关做负载均衡_缓存_04

  7. 在nacos也可以看到注册上了CustomerService的两个实例
  8. ngnix负载均衡到网关 网关做负载均衡_微服务_05

  9. 在nacos也可以看到注册上了CustomerService的两个实例
  10. 修改Ocelot网关配置
    负载均衡主要配置LoadBalancerOptions节点,可以配置在Routes节点各个服务路由中,这将对单个服务起作用,也可以配置在GlobalConfiguration中,官方文档中说明GlobalConfiguration中的配置,将会覆盖Routes中各个路由的配置,但是17.0.1版本下经过测试发现并不起作用,在Routes节点有配置的情况下,必须针对每个服务进行配置,无法通过全局配置作用于所有的服务。
    这里我依旧沿用上一节的动态路由,在Routes节点没有内容的情况下,在GlobalConfiguration中配置LoadBalancerOptions是可以的。
"GlobalConfiguration": {
    "RequestIdKey": null,
    "ServiceDiscoveryProvider": {
      "Type": "Nacos",
      // 为了使用动态路由必须配置Host和Port,查看DownstreamRouteFinderMiddleware中的IDownstreamRouteProviderFactory获取时,
      // 只有存在Host和Port的时候,才会获取到DownstreamRouteCreator,才能从url中解析出ServiceName
      "Host": "0.0.0.0",
      "Port": 8500
    },
    "DownstreamScheme": "http",
    "LoadBalancerOptions": {
      "Type": "RoundRobin"
    }
  }

Ocelot负载均衡策略提供四种默认的方式
○ RoundRobin
○ LeastConnection
○ NoLoadBalance
○ CookieStickySessions

  1. 通过网关访问CustomerService的API
    启动Ocelot网关,测试负载均衡
  2. 扩展负载均衡策略
    如果觉得Ocelot提供的负载均衡策略不足以满足自己在工作的实际需求,Ocelot也支持自定义负载均衡策略。
    (1) 实现ILoadBalancer接口,实现自己的负载均衡策略逻辑
/// <summary>
/// 自定义负载均衡策略
/// </summary>
public class CustomerBalancer : ILoadBalancer
{
    private readonly Func<Task<List<Service>>> _services;
    private readonly object _lock = new object();

    private int _last;
    public CustomerBalancer(Func<Task<List<Service>>> services)
    {
        _services = services;
    }

    public async Task<Response<ServiceHostAndPort>> Lease(HttpContext httpContext)
    {
        var services = await _services();
        lock (_lock)
        {
            if (_last >= services.Count)
            {
                _last = 0;
            }

            var next = services[_last];
            _last++;
            return new OkResponse<ServiceHostAndPort>(next.HostAndPort);
        }
    }

    public void Release(ServiceHostAndPort hostAndPort)
    {
        
    }
}

这里是轮询策略的实现的实现,只是一个演示。

(2) 将自定义负载均衡策略加入Ocelot依赖中

Func<IServiceProvider, DownstreamRoute, IServiceDiscoveryProvider, CustomerBalancer> loadBalancerFactoryFunc = (serviceProvider, Route, serviceDiscoveryProvider) => new CustomerBalancer(serviceDiscoveryProvider.Get);
services.AddOcelot(Configuration)
    .AddNacosDiscovery()
    .AddCustomLoadBalancer(loadBalancerFactoryFunc);

(3) 配置文件中负载均衡策略改为我们自己的类型

"LoadBalancerOptions": {
      "Type": "CustomerBalancer"
 }

请求缓存

有些时候,为了提供API接口的访问速度,我们可能会将某些API接口的结果进行缓存,Ocelot网关也提供了这样的功能,通过FileCacheOptions配置对下游服务的URL进行缓存,目前只支持get方式,只要请求的URL不变,就会缓存。FileCacheOptions需要配置在Routes中的某个节点,在动态路由的情况下是不支持的。

"Routes": [
    {
      "UpstreamPathTemplate": "/Customer/{url}",
      "UpstreamHttpMethod": [ "Get", "Post" ],
      "DownstreamPathTemplate": "/{url}",
      "DownstreamScheme": "http",
      "UseServiceDiscovery": true,
      "ServiceName": "customerService",
      "LoadBalancerOptions": {
        "Type": "RoundRobin"
      },
      "FileCacheOptions": {
        "TtlSeconds": 5,
        "Region": "somename"
      }
    }
  ]

TtlSeconds是缓存时间,单位是秒,Region是缓存域,可以通过调用Ocelot的管理API来清除某个Region的缓存。

ngnix负载均衡到网关 网关做负载均衡_ngnix负载均衡到网关_06

微服务系列文章:
上一篇:API网关—Ocelot之服务发现 下一篇:API网关—Ocelot之限流熔断