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框架 ...
随机推荐
- 关于Javascript中的复制
在做项目时有一个需求,是需要复制内容到剪切板,因为有众多浏览器,所以要兼容性很重要 1.最简单的copy,只能在IE下使用 使用clipboardData方法 <script type=&quo ...
- 什么是purge操作
要明白什么清空(purge)操作,你得明白什么是事务的多版本控制,即MVCC(multi-version concurrency control).Innodb为了实现MVCC, 需要在表空间内保存老 ...
- POI教程之第二讲:创建一个时间格式的单元格,处理不同内容格式的单元格,遍历工作簿的行和列并获取单元格内容,文本提取
第二讲 1.创建一个时间格式的单元格 Workbook wb=new HSSFWorkbook(); // 定义一个新的工作簿 Sheet sheet=wb.createSheet("第一个 ...
- Linux 本地文件或文件夹上传服务器
Linux 本地文件或文件夹上传服务器 一.权限设置 本地文件或文件夹上传服务器,你首先需要获取到root权限: 二.上传方式 上传方式有两种 : 1.通过 FTP 客户端上传文件或文件夹: 2.通过 ...
- Class to connect postgres with python in psycopg2
For we need to connect the postgres db in project very frequently, so write the follows class: impor ...
- PHP使用CURL实现对带有验证码的网站进行模拟登录的方法
网上的很多模拟登录程序,大都是通过服务程序apache之类的运行,获取到验证码之后显示在网页上,然后填上再POST出去,这样虽然看起来很友 好,但是既然模拟登录,登录后所干的事情就不一定是短时间完成的 ...
- 基于Retrotfit2.1+Material Design+ijkplayer开发的一个APP(新闻,gif 动图,视频播放)
此项目主要目的还是为了练习框架的使用,仅供学习用途. 数据来源 新闻 直接用的聚合数据提供的接口:https://www.juhe.cn/docs/api/id/235gif动图 通过jsoup爬的某 ...
- zookeeper中Watcher和Notifications
问题导读:1.zookeeper观察者什么时候调用?2.传统远程轮询服务存在什么问题?3.zk中回调服务的机制是什么?4.zk中watcher为什么不永久注册?5.什么是znode? 在阅读之前首先明 ...
- Coax Transformers[转载]
Coax Transformers How to determine the needed Z for a wanted Quarter Wave Lines tranformation ratio ...
- Bellman-Ford算法判负环
算法思想:如果没有负权回路,dis数组应该会在n-1次松弛之后结束. 算法复杂度:O(n*m).比Dijkstra算法复杂度要高. 代码: bool Bellman_Ford(int s) { int ...