Thrift搭建分布式微服务(三)
第一篇 《连接配置》
第二篇 《连接池》
第三篇 标准通信
一、TCP的连接是无状态的,怎样知道我的请求被服务端接受并且正确执行了呢?
我的解决方案是使用自己定义的标准输入输出,Push操作和Delete操作都要返回Json的字符串,也就是说,每一个Thrift接口方法的输入参数和返回参数都是Json字符串。标准返回,Code表示状态码,Desc表示对执行结果的描述,如果Code表示服务端出错,Desc为错误信息。
public class StandResponse<T>
{
/// <summary>
/// 服务端成功调用:0
/// 服务端业务异常:-1
/// </summary>
public string Code { get; set; } public string Desc { get; set; } public T Data { get; set; }
}
二、一般情况,服务端和客户端服务器应在同一个内网,所以可以不用进行接口调用的身份验证,只需保证服务端不被外网访问即可。当然也可以简单的,采用对客户端调用时间戳加密,并把时间戳和密文发到服务端后,用相同的加密算法对时间戳加密,对密文进行比较来验证。
//标准请求,包括客户端服务器的IP及主机名,如果客户端是Web服务器,用户请求的URL和用户请求IP也会一并带到服务器端,用于做验证或请求限制。
public class StandRequest<T>
{
private string SIGN_KEY = ConfigurationManager.AppSettings["ThriftSignKey"] ?? "Thrift_Sign"; public string HostName { get; set; } public string IP { get; set; } public string RequestUrl { get; set; } public string UserRequestIP { get; set; } public string TimeStamp { get; set; } public string Sign { get; set; } public T Data { get; set; } public string SignTimestamp(string timeStamp)
{
MD5 md5 = new MD5CryptoServiceProvider();
byte[] array = md5.ComputeHash(Encoding.UTF8.GetBytes(timeStamp + SIGN_KEY));
return Convert.ToBase64String(array);
} //验证客户请求是否合法
public bool IsValid()
{
MD5 md5 = new MD5CryptoServiceProvider();
byte[] array = md5.ComputeHash(Encoding.UTF8.GetBytes(TimeStamp + SIGN_KEY));
string sign = Convert.ToBase64String(array);
return Sign.Equals(sign);
}
}
可通过在客户端和服务端,配置相同的ThriftSignKey来确保请求来自自己开发的客户端。其实在标准请求里还应该定义一个参数,就是当前请求的时间,这样到服务端时可以监控请求在传输时的时延。
三、使用了标准输入输出来传输数据,但每次让开发者去序列化标准输入输出进行这些重复性劳动也是不能忍的。以及让开发者去处理超时异常和服务端如果抛出未经处理的异常,客户端和服务端会失去连接,客户端抛TTransportException,每请求一次都让开发者来处理这些异常,让人难以接受。我再次想到使用反射,这样我可以在结果返回给开发者之前做一些处理。相当于拦截器,或者理解为面向切面的处理。
private string serviceName; private TTransport transport; private T instance; private bool disposed; public ThriftClient(string serviceName)
{
disposed = false;
this.serviceName = serviceName;
transport = ThriftFactory.BorrowInstance(serviceName);
TProtocol protocol = new TBinaryProtocol(transport);
//使用Invoker创建实例,InvokerEmitter抛异常“找不到公开实例构造方法”,可能是内部类获取的类名有点奇怪导致,例如“HelloWorldService.Client”。
//instance = (T)Invoker.CreateInstance<T>(protocol);
instance = (T)Activator.CreateInstance(typeof(T),protocol);
}
初始化得到一个服务的Client,也就是instance。
真正的访问服务端的方法被封装成一个使用标准输入输出的私有化方法,完成服务端和客户端通信的方法就只有Invoker.MethodInvoke一行,其余的都是对异常进行处理。
private StandResponse<P> Invoke<Q, P>(string methodName, StandRequest<Q> request)
{
StandResponse<P> res = null;
StandResponse<string> response = null;
try
{
string result = (string)Invoker.MethodInvoke(instance, methodName, SerializeHelper.JsonSerialize2(request));
response = SerializeHelper.JsonDeserialize2<StandResponse<string>>(result);
}
catch (IOException idEx)
{
throw new ThriftException(string.Format("请求超时。\r请求服务:{0}\r请求方法:{1}\r请求数据:{2}", serviceName, methodName, SerializeHelper.JsonSerialize2(request)));
}
catch (TTransportException transEx)
{
throw new ThriftException(string.Format("服务端未处理系统异常。\r请求服务:{0}\r请求方法:{1}\r请求数据:{2}", serviceName, methodName, SerializeHelper.JsonSerialize2(request)));
}
catch(Exception ex)
{
throw ex;
}
if (response != null && response.Code == "-1")
{
throw new ThriftException(string.Format("请求数据异常。\r请求服务:{0}\r请求方法:{1}\r请求数据:{2}", serviceName, methodName, SerializeHelper.JsonSerialize2(request)));
}
if (response != null && response.Code == "-2")
{
throw new ThriftException(string.Format("服务端系统异常。\r请求服务:{0}\r请求方法:{1}\r请求数据:{2}", serviceName, methodName, SerializeHelper.JsonSerialize2(request)));
}
if (response != null)
{
res = new StandResponse<P>()
{
Code = response.Code,
Desc = response.Desc,
Data = SerializeHelper.JsonDeserialize2<P>(response.Data)
};
}
return res;
}
然后再对这个私有的方法进一步封装,返回开发者看得懂的数据结构。
/// <summary>
/// 无返回接口调用
/// </summary>
/// <typeparam name="Q"></typeparam>
/// <typeparam name="P"></typeparam>
/// <param name="methodName"></param>
/// <param name="request"></param>
public void Invoke<Q>(string methodName, Q request)
{
Invoke<Q, string>(methodName, BuildRequest<Q>(request));
} /// <summary>
/// 无参接口调用,服务端一定是有请求参数的,这里的无参是指Service方法无参
/// </summary>
/// <typeparam name="P"></typeparam>
/// <param name="methodName"></param>
/// <returns></returns>
public P Invoke<P>(string methodName)
{
StandResponse<P> response = Invoke<string, P>(methodName, BuildRequest<string>(string.Empty));
if (response != null)
{
return response.Data;
}
return default(P);
} public P Invoke<Q, P>(string methodName, Q request)
{
StandResponse<P> response = Invoke<Q, P>(methodName, BuildRequest<Q>(request));
if (response != null)
{
return response.Data;
}
return default(P);
}
关于Tcp连接的归还释放,请自行下载源码来看。
下一篇会用一个Demo来示范怎样使用Thrift.Utility来快速暴露接口,让客户端和服务端通信。
Thrift微服务代码下载Thrift.Utility
Thrift搭建分布式微服务(三)的更多相关文章
- Thrift搭建分布式微服务(二)
第二篇 连接池 连接池配置,请前往Thrift搭建分布式微服务(一) 下面要介绍的其实不是单一的连接池,应该说是连接池集合.因为它要管理多个Tcp Socket连接节点,每个服务节点都有设置了自己 ...
- Thrift搭建分布式微服务1
Thrift搭建分布式微服务 一.Thrift是什么? 关于Thrift的基本介绍,参看张善友的文章Thrift简介. 二.为什么使用微服务? 在公司的高速发展过程中,随着业务的增长,子系统越来越多. ...
- Thrift搭建分布式微服务(四)
第一篇 <连接配置> 第二篇 <连接池> 第三篇 <标准通信> 第四篇 快速暴露接口 之前的文章,我们介绍了如何使用连接池管理Thrift节点,以及使用Thri ...
- Thrift搭建分布式微服务(一)
一.Thrift是什么? 关于Thrift的基本介绍,参看张善友的文章Thrift简介. 二.为什么使用微服务? 在公司的高速发展过程中,随着业务的增长,子系统越来越多.各系统间又不同程度的在某些逻辑 ...
- Kite: 一个分布式微服务框架(翻译)
原文链接:https://blog.gopheracademy.com/birthday-bash-2014/kite-microservice-library/ 此为中文翻译 用GO语言来编写web ...
- Dapeng框架-开源高性能分布式微服务框架
我们公司性质是新零售,公司也有专门的框架组.这群大牛自己开发了一整套分布式微服务框架.我们也在使用这套框架,有很多心得体会. 该框架既Dapeng也!开源github地址:https://github ...
- Train-Alypay-Cloud:分布式微服务中间件sofa 开发培训(第二次)
ylbtech-Train-Alypay-Cloud:分布式微服务中间件sofa 开发培训(第二次) 1.返回顶部 1. 这是本次培训的内容,望各位提前配好环境.工具.2.6-2.7 我们在环球金融8 ...
- Surging 分布式微服务框架使用入门
原文:Surging 分布式微服务框架使用入门 前言 本文非 Surging 官方教程,只是自己学习的总结.如有哪里不对,还望指正. 我对 surging 的看法 我目前所在的公司采用架构就是类似与S ...
- [转载]Surging 分布式微服务框架使用入门
前言 本文非 Surging 官方教程,只是自己学习的总结.如有哪里不对,还望指正. 我对 surging 的看法 我目前所在的公司采用架构就是类似与Surging的RPC框架,在.NET 4.0框架 ...
随机推荐
- Effective Java 12 Consider implementing Comparable
Sort array with sorted collection construction. public class WordList { public static void main(Stri ...
- python数据结构-列表-基本操作
- 什么是purge操作
要明白什么清空(purge)操作,你得明白什么是事务的多版本控制,即MVCC(multi-version concurrency control).Innodb为了实现MVCC, 需要在表空间内保存老 ...
- 10901 Missile
10901 Missile 时间限制:1000MS 内存限制:65535K提交次数:40 通过次数:7 Description Long, long ago, country A invented ...
- Begin to record my bologs....
after work for almost two years, I have realize the truth notes can help a lot for us. avoiding my l ...
- 利用模板在RM里部署VM
Refer to: https://www.azure.cn/documentation/articles/virtual-machines-windows-ps-template/ 过程中遇到的几个 ...
- JVM 类加载过程
类从加载到虚拟机到卸载,它的整个生命周期包括:加载(Loading),验证(Validation),准备(Preparation),解析(Resolution),初始化(Initialization) ...
- 随机序列生成算法---生成前N个整数的一组随机序列
问题描述: 给定输入N,生成从1开始的:1,2,3,4,......N 一组随机序列,序列中的数不能重复出现. 比如:N=5,合法的随机序列为{4,3,1,5,2} .{3,1,4,2,5}……非法的 ...
- 《TCP/IP详解 卷一》读书笔记-----第三章 IP
1.Network byte order:数据在网络中的传输是按照大端模式来的,即如果需要传递一个四个字节的int变量,先传递最高的字节,然后依次类推.因此无论主机存储数据用的是大端模式还是小端模式, ...
- floyd算法 青云的机房组网方案(简单)
青云的机房组网方案(简单) 青云现在要将 nn 个机房连成一个互相连通的网络.工程师小王设计出一个方案:通过在 nn 个机房之间铺设 n-1n−1 条双向的光纤,将所有的机房连接.可以假设数据在两个机 ...