菜单 学习猿地 - LMONKEY

VIP

开通学习猿地VIP

尊享10项VIP特权 持续新增

知识通关挑战

打卡带练!告别无效练习

接私单赚外块

VIP优先接,累计金额超百万

学习猿地私房课免费学

大厂实战课仅对VIP开放

你的一对一导师

每月可免费咨询大牛30次

领取更多软件工程师实用特权

入驻
313
0

gRPC Client的负载均衡器

原创
05/13 14:22
阅读数 63049

一、gRPC是什么?

gRPC是一个高性能、通用的开源RPC框架,其由Google主要面向移动应用开发并基于HTTP/2协议标准而设计,基于ProtoBuf(Protocol Buffers)序列化协议开发,且支持众多开发语言。gRPC提供了一种简单的方法来精确地定义服务和为iOS、Android和后台支持服务自动生成 可靠性很强的客户端功能库。客户端充分利用高级流和链接功能,从而有助于节省带宽、降低的TCP链接次数、节省CPU使用、和电池寿命。

二、为什么使用gRPC?

有了 gRPC, 我们可以一次性的在一个 .proto 文件中定义服务并使用任何支持它的语言去实现客户端和服务器,反过来,它们可以在各种环境中,从Google的服务器到你自己的平板电脑- gRPC 帮你解决了不同语言间通信的复杂性以及环境的不同.使用 protocol buffers 还能获得其他好处,包括高效的序列号,简单的 IDL 以及容易进行接口更新。

三、出现启动其中一个服务挂了、中间服务挂了、服务重新启动这三种情况,如何保证客户端的正常访问?

1、haproxy

缺点:每次连接都会创建一个channel,并发高的话资源消耗大,这样性能也会有问题

2、客户端负载均衡器

优点:单例,资源消耗小,性能比较好

缺点:可能还存在点问题,代码有点乱

3、zk、consul

以后改进方案

4、如果大家有更好的方案,欢迎大家拍砖,谢谢

四、相关包的引用版本是多少?

1、Grpc.Core.0.15.0

2、Grpc.HealthCheck.0.15.0-beta

3、Google.Protobuf.3.0.0-beta3

五、核心代码如下:

获取工作中的服务通道

public static Channel GetWorkingChannel(string key)
    {
      Ensure.NotNullOrEmpty(key);
      CachedItem item = null;
      _cacheMap.TryGetValue(key, out item);
      Channel currentChosenChannel = null;
      if (_cacheMap.IsNotEmpty())
      {
        foreach (var channel in item.Channels.OrderBy(o => Guid.NewGuid()))
        {
          try
          {
            if (channel.State == ChannelState.Idle || channel.State == ChannelState.Ready)
            {
              channel.ConnectAsync(DateTime.Now.AddMilliseconds(100)).Wait();
              currentChosenChannel = channel;
              break;
            }
          }
          catch
          {
            channel.ShutdownAsync().Wait();
          }
        };
      }

      if (currentChosenChannel == null) InitWorkingChannelsByKey(key);
      return currentChosenChannel;
    }

  

进行健康检查

private static bool CheckIfConnectionIsWorking(Channel serverChannel)
    {
      if (serverChannel != null)
      {
        try
        {
          var client = new Health.HealthClient(serverChannel);
          var response = client.Check(new HealthCheckRequest { Service = "HealthCheck" });
          return response.Status == HealthCheckResponse.Types.ServingStatus.Serving;
        }
        catch (Exception ex)
        {
          serverChannel.ShutdownAsync().Wait();
          return false;
        }
      }
      return false;
    }

  

定时任务维护

 private static void ExecuteMaintenance(object state)
    {
      if (Interlocked.CompareExchange(ref _executing, 1, 0) != 0)
        return;
      try
      {
        if (_cacheMap.Count == 0)
        {
          StopMaintenance();
          if (_cacheMap.Count != 0)
            StartMaintenance();
        }
        else
        {
          DateTime oldThreshold = DateTime.UtcNow - _timeout;
          var expiredItems = _cacheMap.Where(i => i.Value.Updated < oldThreshold).Select(i => i.Key);
          for (int i = 0; i < expiredItems.Count(); i++)
          {
            var key = expiredItems.ElementAt(i);
            DisposeChannelsByKey(key);
            InitWorkingChannelsByKey(key);
          }
        }
      }
      finally
      {
        Interlocked.Exchange(ref _executing, 0);
      }
    }

  

gRPC Client源代码已上传git,本人比较懒没有完整上传解决方案,该有的都有了。

 

发表评论

0/200
313 点赞
0 评论
收藏