我们谈在性能调优时可能存在有很多不同的方面可以进行性能的优化,比如:良好的的编码习惯,最大限度的发掘服务器性能,减少下载流量等。但我们今天说的异步和分流是在一个更大粒度下进行性能优化,当然异步服务框架不仅仅是用来调优性能的、凡是需要异步、离线、延时操作、处理高成本操作的场景都可以考虑使用异步服务框架。
这个异步服务框架会用到一些核心的技术:WCF 、MSMQ、IOC等,简单介绍一下,WCF是用来在不同应用程序间进行通信,WCF是一个很好的SOA应用的技术;MSMQ是一个队列服务,它提供一套完整的异步离线解决方案,这里我们没有直接使用MSMQ,而是通过WCF的封装来应用,WCF的NetMsmqBinding很好的对MSMQ进行了包装应用。IOC容器,用来支持不同应用插件的开发和调用。
我们先来预览一下异步服务框架的几个特点,在后续的讲解中会有更加深刻的体会:
1、优化性能:分流高并发、高耗时、实时性不强的操作
2、易于扩展:通过部署更多的服务,以支持更多消息流
3、分组管理:合理分配消息流
4、插件模式:为不同的应用开发独立插件
一、接下来看一下基础系统框架图,框架中还会有很多不同的服务,但是为了为了表述更为清晰,这里就不一一列出。
#图中可以看到所用到的必要技术:WCF、MSMQ、IOC、分组管理
#简单的流程:客户端-->分组管理-->调用信息(选择节点)+内部标识参数—>WCF(MSMQ)-->接收服务-->选择插件应用-->执行业务逻辑
#分组管理:客户端—>SoureName-->分组管理-->分组下的服务节点列表-->选择对应的服务节点
我们说服务可部署成很多不同的服务节点,所以客户端在调用服务之前必须要知道自已应该调用的服务节点和通信协议,所以客户端会根据为自已的调用所分配置好的SourceName来从分组管理中获取到自已对应的服务组,并从服务组的节点列表中跟据优先级的不同选择性能负载较好的节点和协议以备调用。invoker_groups.xml
#MSMQ:客户端-->要处理的消息及调用标识-->客户端队列—>WCF(MSMQ)-->服务端队列-->处理……
客户端把消息插入客户端队列后,调用就完成了,这样的操作耗时非常短,剩下的其它操作就由WCF(MSMQ)和后端的服务来完成,所以响应时间非常之快,如果是分流一个耗时的高成本操作,通过这样的方式可以有效提高响应性能,避免线程阻塞。
如果由于网络故障不能与服务器连接,客户端队列也不会掉失,直到网络故障排除后可以自动恢复传输。
如果服务器端的服务升级停止了服务,服务端的队列也不会掉失,直到服务正常启动后自动恢复队列的处理。
服务端队列出队的操作在WCF的处理下可以控制并发数量,通过控制并发量可以有效控制单服务节点的外理能力。
#插件模式、动态调用:Source-->ServiceName,Version-->ICallService接口-->实际处理器-->处理……
Source对象中有两个重要的参数ServiceName和Version,用来决定调用哪个ICallService接口的实现
二、客户端用例子:通过简单的配置便可以调用异步服务框架中的服务。
1、引用组件:DMedia.Fetion.Framework.ServiceModel.dll, DMedia.Fetion.InvokeService.Contract.dll
2、添加配置:
<!-- localhost,online,functest –>
<add key="IServiceInvoker.RuntimeState" value="localhost" />
<add key="IServiceInvoker.ConfigurationFilePath" value="Configuration|*" />
其中:
RuntimeState 表示当前运行在哪种状态之下,localhost表示本机调用,online表示线上生产环境,functest 表示功能测试环境
ConfigurationFilePath 表示分组配置文件的存放路径,Configuration|* 表示优先选择应用程序根目录下的Configuration目录,如果目录下存在则就放在根目录下,如果想再自义存放的路径App_Data, 则可以写成App_Data|Configuration|*
3、调用例子:
#方法一: ServiceInvokerManager.Invoke(“sourceName”, “identity”);
#方法二:ServiceInvokerManager.CreateIServiceInvoker(“sourceName”).Invoke(
Source.FromConfiguration(“sourceName”).SetClientIP("127.0.0.1"),
“identity”);
#方法三:ServiceInvokerManager.CreateIServiceInvoker(“sourceName”)
.Invoke(() => Source.FromConfiguration(“sourceName”).SetClientIP("127.0.0.1"), “identity”);
#标准方法:
IServiceInvoker iServiceInvoker = ServiceInvokerManager.CreateIServiceInvoker(“sourceName”);
if (iServiceInvoker != null)
{
Source source = Source.FromConfiguration(“sourceName”).SetClientIP("127.0.0.1");
if (source != null)
{
iServiceInvoker.Invoke(source, "abc");
}
}
三、插件开发
1、实现ICallService接口
2、添加到容器ICallService.config
3、更新分组配置(invoker_groups.xml),给客户端调用分配服务结点
四、更多服务
1、ILogService内部日志
2、容错服务(重试队列和死信记录)
3、异步错误日志记录
4、异步性能计数
5、回调服务功能(外部接口封装)
6、……