Thrift搭建分布式微服务(二)
第二篇 连接池
连接池配置,请前往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搭建分布式微服务(二)的更多相关文章
- Thrift搭建分布式微服务1
Thrift搭建分布式微服务 一.Thrift是什么? 关于Thrift的基本介绍,参看张善友的文章Thrift简介. 二.为什么使用微服务? 在公司的高速发展过程中,随着业务的增长,子系统越来越多. ...
- Thrift搭建分布式微服务(一)
一.Thrift是什么? 关于Thrift的基本介绍,参看张善友的文章Thrift简介. 二.为什么使用微服务? 在公司的高速发展过程中,随着业务的增长,子系统越来越多.各系统间又不同程度的在某些逻辑 ...
- Thrift搭建分布式微服务(四)
第一篇 <连接配置> 第二篇 <连接池> 第三篇 <标准通信> 第四篇 快速暴露接口 之前的文章,我们介绍了如何使用连接池管理Thrift节点,以及使用Thri ...
- Thrift搭建分布式微服务(三)
第一篇 <连接配置> 第二篇 <连接池> 第三篇 标准通信 一.TCP的连接是无状态的,怎样知道我的请求被服务端接受并且正确执行了呢? 我的解决方案是使用自己定义的标准输入输出 ...
- Kite: 一个分布式微服务框架(翻译)
原文链接:https://blog.gopheracademy.com/birthday-bash-2014/kite-microservice-library/ 此为中文翻译 用GO语言来编写web ...
- Dapeng框架-开源高性能分布式微服务框架
我们公司性质是新零售,公司也有专门的框架组.这群大牛自己开发了一整套分布式微服务框架.我们也在使用这套框架,有很多心得体会. 该框架既Dapeng也!开源github地址:https://github ...
- Surging 分布式微服务框架使用入门
原文:Surging 分布式微服务框架使用入门 前言 本文非 Surging 官方教程,只是自己学习的总结.如有哪里不对,还望指正. 我对 surging 的看法 我目前所在的公司采用架构就是类似与S ...
- [转载]Surging 分布式微服务框架使用入门
前言 本文非 Surging 官方教程,只是自己学习的总结.如有哪里不对,还望指正. 我对 surging 的看法 我目前所在的公司采用架构就是类似与Surging的RPC框架,在.NET 4.0框架 ...
- 基于docker 如何部署surging分布式微服务引擎
1.前言 转眼间surging 开源已经有1年了,经过1年的打磨,surging已从最初在window 部署的分布式微服务框架,到现在的可以在docker部署利用rancher 进行服务编排的分布式微 ...
随机推荐
- 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 ...
- Hive安装(三)之奇怪的错误
启动hive命令报错 “Metastore contains multiple versions” 解决方案: 因为hive metastore存储在mysql中,所以登录mysql,use hive ...
- (五) openwrt打包过程
标签(空格分隔): Makefile 本周是成胖子每周一博第六周,更好地阅读体验,请点击这里 前言 前面我们已经讲了openwrt编译的大部分过程,包括大致的编译步骤,ipk的编译等.今天是我这个系列 ...
- 【iOS 初见】第一个简单的 iOS 应用
本实例来自 <iOS编程(第4版)>,介绍如何编写一个简单的 iOS 应用. 功能为:在视图中显示一个问题,用户点击视图下方的按钮,可以显示相应的答案,用户点击上方的按钮,则会显示一个新的 ...
- 记忆化搜索 codevs 2241 排序二叉树
codevs 2241 排序二叉树 ★ 输入文件:bstree.in 输出文件:bstree.out 简单对比时间限制:1 s 内存限制:128 MB [问题描述] 一个边长为n的正三 ...
- 怎样用ZBrush中的Curves和Insert笔刷创建四肢
之前的ZBrush教程给大家介绍了人体结构比例和肌肉走向,同时使用ZBrush®软件中的CuverTube笔刷为模型添加了颈部和手臂.使用InsertSphere笔刷添加腰部,本讲将继续使用Curv ...
- 实习小记-python 内置函数__eq__函数引发的探索
乱写__eq__会发生啥?请看代码.. >>> class A: ... def __eq__(self, other): # 不论发生什么,只要有==做比较,就返回True ... ...
- POJ 1151 / HDU 1542 Atlantis 线段树求矩形面积并
题意:给出矩形两对角点坐标,求矩形面积并. 解法:线段树+离散化. 每加入一个矩形,将两个y值加入yy数组以待离散化,将左边界cover值置为1,右边界置为2,离散后建立的线段树其实是以y值建的树,线 ...
- Android中Adapter之BaseAdapter使用
Android界面中有时候需要显示稍微复杂的界面时,就需要我们自定义一个adapter,而此adapter就要继承BaseAdapter,重新其中的方法. Android中Adapte ...
- JSP中文乱码问题《转》
之前总是碰到JSP页面乱码的问题,每次都是现在网上搜,然后胡乱改,改完也不明白原因. 这次正好作下总结,中文乱码就是因为编码不符,可能出现乱码有四个地方: 1 JSP编码乱码 2 HTML编码乱码 3 ...