Grpc的一个简单的负载均衡类库

来源:互联网 发布:10月份经济数据2017 编辑:程序博客网 时间:2024/05/16 17:32

首先先列下Grpc的教程,然后目前Grpc的C#的版本为1.0 prev版,反正就是还有坑的阶段,实际会出内存错误导致程序崩溃(内存错误你懂得,unsafe代码异常捕获都没用),这里就当是尝鲜版试验使用了下,然后就简单的写了个类,具体代码如下

GrpcChannelTargetsSection,用来配置服务器地址的类

    public class GrpcChannelTargetsSection : ConfigurationSection    {        public static GrpcChannelTargetsSection Current        {            get { return (GrpcChannelTargetsSection)ConfigurationManager.GetSection("grpcChannelTargets"); }        }        /// <summary>        /// 连接超时时间(单位毫秒)        /// </summary>        [ConfigurationProperty("connectTimeout", DefaultValue = 500)]        public int ConnectTimeout        {            get { return Convert.ToInt32(this["connectTimeout"]); }            set { this["connectTimeout"] = value; }        }        [ConfigurationProperty("", IsDefaultCollection = true)]        public KeyValueConfigurationCollection Targets        {            get            {                return (KeyValueConfigurationCollection)base[""];            }        }        readonly IDictionary<string, IEnumerable<string>> _dic = new Dictionary<string, IEnumerable<string>>();        protected override void PostDeserialize()        {            if (this.Targets == null || this.Targets.Count == 0)            {                throw new ArgumentException("No target can be found!");            }            foreach (var key in this.Targets.AllKeys)            {                var target = this.Targets[key].Value.Split(',').Where(str => !string.IsNullOrWhiteSpace(str));                if (!target.Any())                {                    throw new ArgumentException("Argument error,the target of " + key + " is empty");                }                this._dic.Add(key, target);            }            base.PostDeserialize();        }        public IEnumerable<string> GetTarget(string key)        {            if (this._dic.ContainsKey(key))            {                return this._dic[key];            }            return null;        }    }
ChannelHelper,根据配置获取可用Channel的赋值类
    using global::Grpc.Core;    public class ChannelHelper    {        public static Channel GetFirstChannel(ChannelCredentials credentials = null, IEnumerable<ChannelOption> options = null)        {            return GetChannel(GrpcChannelTargetsSection.Current.Targets.AllKeys[0], credentials, options);        }        /// <summary>        /// 获取Grpc Channel        /// </summary>        /// <param name="key">配置中的Key值</param>        /// <param name="credentials"></param>        /// <param name="options"></param>        /// <returns></returns>        public static Channel GetChannel(string key, ChannelCredentials credentials = null, IEnumerable<ChannelOption> options = null)        {            var targets = GrpcChannelTargetsSection.Current.GetTarget(key);            if (targets == null)            {                throw new KeyNotFoundException("Can not find target with key '" + key + "'");            }            Channel channel = null;            if (credentials == null)            {                credentials = ChannelCredentials.Insecure;            }            foreach (var target in targets.OrderBy(x => Guid.NewGuid()))            {                try                {                    channel = new Channel(target, credentials, options);                    channel.ConnectAsync(DateTime.UtcNow.AddMilliseconds(GrpcChannelTargetsSection.Current.ConnectTimeout)).Wait();                    if (channel.State != ChannelState.Shutdown                        && channel.State != ChannelState.TransientFailure)                    {                        break;                    }                }                catch (Exception ex)                {                    //如果不关闭,貌似虽然超时跳出了,但Connect还会一直进行连接尝试                    //因为能在控制台输出界面能一直看到连接错误信息                    if (channel != null)                    {                        var tmpChannel = channel;                        Task.Factory.StartNew((c) =>                        {                            var tmp = c as Channel;                            if (tmp != null)                            {//虽然关闭的方法名写的是Async,但实际还要等待N秒                                tmp.ShutdownAsync().Wait();                            }                        }, tmpChannel);                        channel = null;                    }                }            }            return channel;        }    }
实际使用时需在config中增加如下配置

1、在configSections中增加下级配置,注意后面的type需改成实际项目的命名空间

<section name="grpcChannelTargets" type="Demo.Grpc.GrpcChannelTargetsSection, Demo" />

2、增加configSections同级配置

  <grpcChannelTargets connectTimeout="1000"><!--connectTimeout 为连接超时设置,单位为毫秒,用于判断获取到的服务地址是否可用-->    <!--每个add对应一项Grpc服务器,若该项服务配置了多台服务器,那么value部分通过,分隔,程序会随机抽取一项返回-->    <add key="GrpcServer_1" value="192.168.5.113:90,192.168.5.114:90" />    <add key="GrpcServer_2" value="192.168.5.113:92" />    <add key="GrpcServer_3" value="192.168.5.113:94,192.168.5.114:94,192.168.5.115:94" />  </grpcChannelTargets>
使用代码如下
var channle = ChannelHelper.GetFirstChannel();//取配置的第一项服务channle = ChannelHelper.GetChannel("GrpcServer_1");//按配置的Key获取对应的服务

0 0
原创粉丝点击