ASP.NET Core 微服务初探[1]:服务发现之Consul (3)

如何将不同的用户的流量分发到不同的服务器上面呢,早期的方法是使用DNS做负载,通过给客户端解析不同的IP地址,让客户端的流量直接到达各个服务器。但是这种方法有一个很大的缺点就是延时性问题,在做出调度策略改变以后,由于DNS各级节点的缓存并不会及时的在客户端生效,而且DNS负载的调度策略比较简单,无法满足业务需求,因此就出现了负载均衡器。

常见的负载均衡算法有如下几种:

随机算法:每次从服务列表中随机选取一个服务器。

轮询及加权轮询:按顺序依次调用服务列表中的服务器,也可以指定一个加权值,来增加某个服务器的调用次数。

最小连接:记录每个服务器的连接数,每次选取连接数最少的服务器。

哈希算法:分为普通哈希与一致性哈希等。

IP地址散列:通过调用端Ip地址的散列,将来自同一调用端的分组统一转发到相同服务器的算法。

URL散列:通过管理调用端请求URL信息的散列,将发送至相同URL的请求转发至同一服务器的算法。

本文中简单模拟前两种来介绍一下。

随机均衡

随机均衡是最为简单粗暴的方式,我们只需根据服务器数量生成一个随机数即可:

public class RandomLoadBalancer : ILoadBalancer { private readonly IServiceDiscoveryProvider _sdProvider; public RandomLoadBalancer(IServiceDiscoveryProvider sdProvider) { _sdProvider = sdProvider; } private Random _random = new Random(); public async Task<string> GetServiceAsync() { var services = await _sdProvider.GetServicesAsync(); return services[_random.Next(services.Count)]; } }

其中IServiceDiscoveryProvider是上文介绍的Consule服务提供者者,定义如下:

public interface IServiceDiscoveryProvider { Task<List<string>> GetServicesAsync(); }

而ILoadBalancer的定义如下:

public interface ILoadBalancer { Task<string> GetServiceAsync(); } 轮询均衡

再来看一下最简单的轮询实现:

public class RoundRobinLoadBalancer : ILoadBalancer { private readonly IServiceDiscoveryProvider _sdProvider; public RoundRobinLoadBalancer(IServiceDiscoveryProvider sdProvider) { _sdProvider = sdProvider; } private readonly object _lock = new object(); private int _index = 0; public async Task<string> GetServiceAsync() { var services = await _sdProvider.GetServicesAsync(); lock (_lock) { if (_index >= services.Count) { _index = 0; } return services[_index++]; } } }

如上,使用lock控制并发,每次请求,移动一下服务索引。

最后,便可以直接使用HttpClient来完成服务的调用了:

var client = new HttpClient(); ILoadBalancer balancer = new RoundRobinLoadBalancer(new PollingConsulServiceProvider()); // 使用轮询算法调用 for (int i = 0; i < 10; i++) { var service = await balancer.GetServiceAsync(); Console.WriteLine(DateTime.Now.ToString() + "-RoundRobin:" + await client.GetStringAsync("http://" + service + "/api/values") + " --> " + "Request from " + service); } // 使用随机算法调用 balancer = new RandomLoadBalancer(new PollingConsulServiceProvider()); for (int i = 0; i < 10; i++) { var service = await balancer.GetServiceAsync(); Console.WriteLine(DateTime.Now.ToString() + "-Random:" + await client.GetStringAsync("http://" + service + "/api/values") + " --> " + "Request from " + service); } 总结

本文从服务注册,到服务发现,再到负载均衡,演示了一个最简单的服务间调用的流程。看起来还不错,但是还有一个很严重的问题,就是当我们获取到服务列表时,服务都还是健康的,但是在我们发起请求中,服务突然挂了,这会导致调用端的异常。那么能不能在某一个服务调用失败时,自动切换到下一个服务进行调用呢?下一章就来介绍一下熔断降级,完美的解决了服务调用失败以及重试的问题。

参考资料

Using Consul for Service Discovery with ASP.NET Core

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpwysp.html