第二篇 连接池

    连接池配置,请前往Thrift搭建分布式微服务(一)

    下面要介绍的其实不是单一的连接池,应该说是连接池集合。因为它要管理多个Tcp Socket连接节点,每个服务节点都有设置了自己的最大激活连接数、最大空闲连接数、最小空闲连接数、等待连接时间。

     internal class ServiceTransportPool
{
public ServiceConfig ServiceConfig { get; set; } public ConcurrentStack<TTransport> TransportPool { get; set; } public AutoResetEvent ResetEvent { get; set; } public int ActivedTransportCount { get; set; }
     
     internal object sync_obeject = new object();
}

  

一个ServiceTransportPool类对应一个服务配置,一个服务配置对应一个服务节点。连接池集合应具有下列成员:

     internal class ThriftFactory
{
private static volatile List<ServiceTransportPool> transport_pools; private static object sync_obj = new object(); private static IThriftFactoryMonitor monitor = new ThriftFactoryMonitor();
}

transport_pools实现了对服务节点的管理,monitor 用来监控连接池的状态,如上一篇所讲,等待连接超时怎么通知连接池管理者,就用monitor来实现。这里monitor有个默认的实现,后面再讲。

初始化连接池集合:

         static ThriftFactory()
{
if (transport_pools == null || transport_pools.Count == )
{
lock (sync_obj)
{
if (transport_pools == null || transport_pools.Count == )
{
var services = ConfigHelper.GetServiceConfigs();
transport_pools = new List<ServiceTransportPool>(services.Count);
foreach (var service in services)
{
ServiceTransportPool stp = new ServiceTransportPool()
{
ServiceConfig = service,
TransportPool = new ConcurrentStack<TTransport>(),
ResetEvent = new AutoResetEvent(false),
ActivedTransportCount =
};
transport_pools.Add(stp);
}
}
}
}
}

   如何向连接池借出一个Socket连接:

         public static TTransport BorrowInstance(string serviceName)
{
var transpool = (from tp in transport_pools where tp.ServiceConfig.Name.ToUpper() == serviceName.ToUpper() select tp).FirstOrDefault();
if (transpool == null)
{
throw new ThriftException(string.Format("There Is No Service Named \"{0}\"", serviceName));
} TTransport transport;
lock (transpool.sync_obeject)
{
if (transpool.TransportPool.Count() == )
{
if (transpool.ActivedTransportCount == transpool.ServiceConfig.MaxActive)
{
bool result = transpool.ResetEvent.WaitOne(transpool.ServiceConfig.WaitingTimeout);
if (!result)
{
monitor.TimeoutNotify(transpool.ServiceConfig.Name, transpool.ServiceConfig.WaitingTimeout);
}
}
else
{
transpool.TransportPool.Push(CreateTransport(transpool.ServiceConfig));
}
} if (!transpool.TransportPool.TryPop(out transport))
{
throw new ThriftException("Connection Pool Exception");
} transpool.ActivedTransportCount++; if (transpool.TransportPool.Count() < transpool.ServiceConfig.MinIdle && transpool.ActivedTransportCount < transpool.ServiceConfig.MaxActive)
{
transpool.TransportPool.Push(CreateTransport(transpool.ServiceConfig));
}
}
if (!transport.IsOpen)
{
transport.Open();
}
Monitor();
return transport;
}

当实际激活的连接数达到服务节点配置的最大激活连接数,获取Socket连接的请求就将处于等待状态,超过等待时间设置,使用监视器方法monitor.TimeoutNotify()去通知管理者。连接池空闲的连接小于最小空闲连接数设置,每次请求连接都会建立一个新的连接放到池子里。

归还连接:

         public static void ReturnInstance(string serviceName,TTransport transport)
{
var transpool = (from tp in transport_pools where tp.ServiceConfig.Name.ToUpper() == serviceName.ToUpper() select tp).FirstOrDefault();
if (transpool == null)
{
throw new ThriftException("Connection Pool Exception");
}
if (transpool.TransportPool.Count() == transpool.ServiceConfig.MaxIdle)
{
transport.Flush();
if (transport.IsOpen)
{
transport.Close();
}
transport.Dispose();
}
else
{
lock (transpool.sync_obeject)
{
if (transport.IsOpen)
{
transport.Close();
}
transpool.TransportPool.Push(transport);
transpool.ActivedTransportCount--;
transpool.ResetEvent.Set();
}
}
Monitor();
}

当连接池最大空闲连接达到了服务节点设置的最大空闲连接数时,归还的连接将被销毁。借出连接和归还连接两段代码里都有一个Monitor()方法,此方法监控连接池连接的使用情况:

        /// <summary>
/// 监控连接池状态
/// </summary>
private static void Monitor()
{
List<Tuple<string, int, int>> tuples = new List<Tuple<string, int, int>>(transport_pools.Count);
foreach(var transpool in transport_pools)
{
Tuple<string, int, int> tuple = new Tuple<string, int, int>(transpool.ServiceConfig.Name, transpool.TransportPool.Count(), transpool.ActivedTransportCount);
tuples.Add(tuple);
}
monitor.Monitor(tuples);
}

此方法将每个服务连接池的空闲连接数、和激活的连接数传给前面提到的监视器。在连接等待超时和拿到连接池的运行参数时,最终进行什么动作还是由开发者去实现的。继承下面的接口,开发者可以自定义监视器。

     public interface IThriftFactoryMonitor
{
/// <summary>
/// 监控连接池运行状态
/// </summary>
/// <param name="tuple">元组集合,第一个元素表示服务名称、第二个元素表示空闲连接数量、第三个元素表示激活连接数量</param>
void Monitor(List<Tuple<string,int,int>> tuples); /// <summary>
/// 等待连接超时
/// </summary>
void TimeoutNotify(string serviceName,int timeOut);
}

默认的监视器只是将连接池的运行状态记录到控制台:

     /// <summary>
/// 默认连接池状态监控类
/// </summary>
public class ThriftFactoryMonitor : IThriftFactoryMonitor
{
public virtual void Monitor(List<Tuple<string, int, int>> tuples)
{
foreach (var t in tuples)
{
Console.WriteLine(string.Format("{0}连接池,空闲连接数量:{1},激活连接数量:{2}", t.Item1, t.Item2, t.Item3));
}
} public virtual void TimeoutNotify(string serviceName, int timeOut)
{
Console.WriteLine(string.Format("{0}连接池等待连接超时{1}", serviceName, timeOut));
}
}

    开发者自己实现的监视器,如何能被连接池使用,其实在一开始的连接池初始化里,还有一段使用反射来初始化开发者定义的监视器的代码。开发者只需在上一篇介绍的Thrift.config里配置MonitorType,其他的就交给框架处理:

         static ThriftFactory()
{
......
if(!string.IsNullOrWhiteSpace(ConfigHelper.ThriftConfig.MonitorType))
{
monitor = Invoker.CreateInstance(Type.GetType(ConfigHelper.ThriftConfig.MonitorType)) as IThriftFactoryMonitor;
if (monitor == null)
{
throw new ThriftException(string.Format("There Is No Monitor Implement Which Type Is \"{0}\"", ConfigHelper.ThriftConfig.MonitorType));
}
}
}

   通过连接池与服务节点建立了Socket连接,下一篇将介绍客户端如何使用建立的Socket连接与服务端通信。

Thrift微服务代码下载Thrift.Utility

  

Thrift搭建分布式微服务(二)的更多相关文章

  1. Thrift搭建分布式微服务1

    Thrift搭建分布式微服务 一.Thrift是什么? 关于Thrift的基本介绍,参看张善友的文章Thrift简介. 二.为什么使用微服务? 在公司的高速发展过程中,随着业务的增长,子系统越来越多. ...

  2. Thrift搭建分布式微服务(一)

    一.Thrift是什么? 关于Thrift的基本介绍,参看张善友的文章Thrift简介. 二.为什么使用微服务? 在公司的高速发展过程中,随着业务的增长,子系统越来越多.各系统间又不同程度的在某些逻辑 ...

  3. Thrift搭建分布式微服务(四)

      第一篇 <连接配置> 第二篇 <连接池> 第三篇 <标准通信> 第四篇 快速暴露接口 之前的文章,我们介绍了如何使用连接池管理Thrift节点,以及使用Thri ...

  4. Thrift搭建分布式微服务(三)

    第一篇 <连接配置> 第二篇 <连接池> 第三篇 标准通信 一.TCP的连接是无状态的,怎样知道我的请求被服务端接受并且正确执行了呢? 我的解决方案是使用自己定义的标准输入输出 ...

  5. Kite: 一个分布式微服务框架(翻译)

    原文链接:https://blog.gopheracademy.com/birthday-bash-2014/kite-microservice-library/ 此为中文翻译 用GO语言来编写web ...

  6. Dapeng框架-开源高性能分布式微服务框架

    我们公司性质是新零售,公司也有专门的框架组.这群大牛自己开发了一整套分布式微服务框架.我们也在使用这套框架,有很多心得体会. 该框架既Dapeng也!开源github地址:https://github ...

  7. Surging 分布式微服务框架使用入门

    原文:Surging 分布式微服务框架使用入门 前言 本文非 Surging 官方教程,只是自己学习的总结.如有哪里不对,还望指正. 我对 surging 的看法 我目前所在的公司采用架构就是类似与S ...

  8. [转载]Surging 分布式微服务框架使用入门

    前言 本文非 Surging 官方教程,只是自己学习的总结.如有哪里不对,还望指正. 我对 surging 的看法 我目前所在的公司采用架构就是类似与Surging的RPC框架,在.NET 4.0框架 ...

  9. 基于docker 如何部署surging分布式微服务引擎

    1.前言 转眼间surging 开源已经有1年了,经过1年的打磨,surging已从最初在window 部署的分布式微服务框架,到现在的可以在docker部署利用rancher 进行服务编排的分布式微 ...

随机推荐

  1. Effective Java 54 Use native methods judiciously

    Java Native Interface(JNI) allows Java applications to call native methods, which are special method ...

  2. shell的查找与替换

    shell中做查找,grep是注定逃不开的. cat file | grep austin 就是在文档中查找Austin所在行. grep和正则表达式匹配之后,查找功能变得异常强大. 这个时候,要保证 ...

  3. 计算几何--求凸包模板--Graham算法--poj 1113

    Wall Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 28157   Accepted: 9401 Description ...

  4. matlab ASCII 格式导入

    matlab ASCII 格式导入 可以用fprintf函数,来代替save函数啊比如现在我有一个变量a=[0.1223 345.4544]如果我想保存它的话,可以用下面的程序:fid = fopen ...

  5. VMware Workstation不可恢复的错误:(vmui)

    虚拟机中部署项目,由于项目的日志是gbk的,就把虚拟机中linux编码改成gbk了,结果问题来了,日志显示中文正常了,但是虚拟机运行一下就出错了,注意虚拟机出错,并没导致linux也挂掉,只是linu ...

  6. 边工作边刷题:70天一遍leetcode: day 89

    Word Break I/II 现在看都是小case题了,一遍过了.注意这题不是np complete,dp解的time complexity可以是O(n^2) or O(nm) (取决于inner ...

  7. Notepad++中NppExec的使用之一:基本用法

    一直用NPP,很长时间了,最近才学习它的各种插件,这篇文章是根据NppExec的用户指南写的.很多地方是翻译的,但不全是翻译,同时也有些东西没有翻译. 一.何为NppExec 简单的说,这个插件可以让 ...

  8. Resharper团队协作之TODO

    TODO 需求 首先我想跟大家分享一下我们团队的代码检查流程. 1. 项目经理随时会检查成员的代码,如果发现有不符合规范的代码,会在注释里面加todo.比如,假设leo的代码不符合规范,那么项目经理就 ...

  9. java 12-1 StringBuffer类

    线程安全(多线程讲解) 安全 -- 同步 -- 数据是安全的--效率低一些 不安全 -- 不同步 -- 数据不安全--效率高一些 安全和效率问题是永远困扰我们的问题. 安全:医院的网站,银行网站 效率 ...

  10. java9-7 成员内部类的修饰符

    1. 成员内部类的修饰符: private 为了保证数据的安全性 static 为了方便访问数据 注意:静态内部类访问的外部类数据必须用静态修饰. 案例:我有一个人(人有身体,身体内有心脏.) cla ...