第二篇 连接池

    连接池配置,请前往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 32 Use EnumSet instead of bit fields

    Bit fields is used for passing around sets of constants. Such as // Bit field enumeration constants ...

  2. Hive安装(三)之奇怪的错误

    启动hive命令报错 “Metastore contains multiple versions” 解决方案: 因为hive metastore存储在mysql中,所以登录mysql,use hive ...

  3. (五) openwrt打包过程

    标签(空格分隔): Makefile 本周是成胖子每周一博第六周,更好地阅读体验,请点击这里 前言 前面我们已经讲了openwrt编译的大部分过程,包括大致的编译步骤,ipk的编译等.今天是我这个系列 ...

  4. 【iOS 初见】第一个简单的 iOS 应用

    本实例来自 <iOS编程(第4版)>,介绍如何编写一个简单的 iOS 应用. 功能为:在视图中显示一个问题,用户点击视图下方的按钮,可以显示相应的答案,用户点击上方的按钮,则会显示一个新的 ...

  5. 记忆化搜索 codevs 2241 排序二叉树

    codevs 2241 排序二叉树 ★   输入文件:bstree.in   输出文件:bstree.out   简单对比时间限制:1 s   内存限制:128 MB [问题描述] 一个边长为n的正三 ...

  6. 怎样用ZBrush中的Curves和Insert笔刷创建四肢

     之前的ZBrush教程给大家介绍了人体结构比例和肌肉走向,同时使用ZBrush®软件中的CuverTube笔刷为模型添加了颈部和手臂.使用InsertSphere笔刷添加腰部,本讲将继续使用Curv ...

  7. 实习小记-python 内置函数__eq__函数引发的探索

    乱写__eq__会发生啥?请看代码.. >>> class A: ... def __eq__(self, other): # 不论发生什么,只要有==做比较,就返回True ... ...

  8. POJ 1151 / HDU 1542 Atlantis 线段树求矩形面积并

    题意:给出矩形两对角点坐标,求矩形面积并. 解法:线段树+离散化. 每加入一个矩形,将两个y值加入yy数组以待离散化,将左边界cover值置为1,右边界置为2,离散后建立的线段树其实是以y值建的树,线 ...

  9. Android中Adapter之BaseAdapter使用

    Android界面中有时候需要显示稍微复杂的界面时,就需要我们自定义一个adapter,而此adapter就要继承BaseAdapter,重新其中的方法.         Android中Adapte ...

  10. JSP中文乱码问题《转》

    之前总是碰到JSP页面乱码的问题,每次都是现在网上搜,然后胡乱改,改完也不明白原因. 这次正好作下总结,中文乱码就是因为编码不符,可能出现乱码有四个地方: 1 JSP编码乱码 2 HTML编码乱码 3 ...