最进项目进行性能优化工作,主要是WCF方面的性能优化。
一丶说说我们项目的结构:
1. 安卓前台,通过创建HTTP请求调用WCF服务
参考文章:http://blog.csdn.net/cch5487614/article/details/6333077 (安卓怎么调用WCF方法)
2. WCF后台,主要是提供数据,以及做一些重要的业务逻辑处理
二丶传输格式
数据传输格式:后台处理安卓前台的请求,返回的对象要通过JSON转化之后才返回给前台
注意:JSON转化后的字符串长度一般在10000。
三丶WCF的配置文件
1 <system.serviceModel> 2 <services> 3 <service name="JsonService.Operations" behaviorConfiguration="Service"> 4 <endpoint address="" binding="basicHttpBinding" bindingConfiguration="httpBinding_Config" contract="IJsonOperation" > 5 </endpoint> 6 <host> 7 <baseAddresses> 8 <add baseAddress="http://192.168.23.8/Service/"/> 9 </baseAddresses> 10 </host> 11 </service> 12 </services> 13 <behaviors> 14 <serviceBehaviors> 15 <behavior name="Service"> 16 <serviceMetadata httpGetEnabled="true" /> 17 <serviceDebug includeExceptionDetailInFaults="true" /> 18 <serviceThrottling maxConcurrentCalls="8000" maxConcurrentInstances="8000" maxConcurrentSessions="8000"/> 19 </behavior> 20 </serviceBehaviors> 21 </behaviors> 22 <bindings> 23 <basicHttpBinding> 24 <binding name="httpBinding_Config" maxReceivedMessageSize="2147483647" useDefaultWebProxy="false" textEncoding="utf-8" maxBufferPoolSize="2147483647" maxBufferSize="2147483647" messageEncoding="Text" sendTimeout="00:10:00"> 25 <security mode="None"></security> 26 <readerQuotas maxArrayLength="2147483647" maxStringContentLength="2147483647"/> 27 </binding> 28 </basicHttpBinding> 29 <netNamedPipeBinding> 30 <binding name="PipeBinding" maxConnections="100" maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" sendTimeout="00:10:00"> 31 <security mode="None" ></security> 32 <readerQuotas maxArrayLength="2147483647" maxStringContentLength="2147483647"/> 33 </binding> 34 </netNamedPipeBinding> 35 </bindings> 36 </system.serviceModel>
WCF的实例模型和并发模型的设置:
1 [ServiceBehavior( InstanceContextMode = InstanceContextMode.Single,
UseSynchronizationContext = false,
ConcurrencyMode = ConcurrencyMode.Multiple,
IncludeExceptionDetailInFaults = true)]
注意:项目中每一个方法中的执行时间都不会超过一秒(项目中的代码优化已经做到很好了,一般情况下都没有问题)。
三丶尝试的解决方案
1. 字符串压缩
2. 调整限流设置 - serviceThrottling
3. 增大WCF并发时的线程数量
参考:http://www.cnblogs.com/shanyou/archive/2013/02/09/2909569.html
通过这样修改后感觉效果不是很明显。
四丶测试结果
同时开启500个线程去调用WCF服务方法,得到的数据是:
就调用一个方法,JSON转化的字符串长度为6500.
最后面是调用时间,单位为毫秒。
现象:调用的时间会一直在增加,最终的时间为200毫秒。
五丶疑问
1. 为什么调用时间一直在增加,我不是设置了并发模型了,怎么会这样?
2. JSON的大字符串传输有什么好的办法解决?
3. 有没有人有安卓调用WCF的性能优化经验?
最后希望大家给我点建议。
“调用的时间会一直在增加”可能是计算调用时间的代码有问题,建议检查一下
我觉得这样的应用场景,性能瓶颈不在WCF
这就是我的测试代码,dudu大哥这样写有问题不?
1 public partial class Form1 : Form 2 { 3 private JsonOperationClient client = null; 4 5 public Form1() 6 { 7 InitializeComponent(); 8 9 client = new JsonOperationClient(); 10 InvokeService(); 11 } 12 13 private void InvokeService() 14 { 15 ThreadPool.QueueUserWorkItem(p => 16 { 17 IList<string> clientNames = GetClientNames(); 18 foreach (string clientName in clientNames) 19 { 20 InvokeTestMethods(clientName); 21 } 22 }); 23 } 24 25 private void InvokeTestMethods(string clientName) 26 { 27 Thread thread = new Thread(p => 28 { 29 Stopwatch stopwatch = new Stopwatch(); 30 stopwatch.Start(); 31 string connectionName = clientName; 32 client.GetSystemMessageForList(clientName); 33 stopwatch.Stop(); 34 int threadID = Thread.CurrentThread.ManagedThreadId; 35 MyAction action = () => this.richDisplayMessage.Text += connectionName + " 连接成功 - " + stopwatch.ElapsedMilliseconds + ". ||ThreadID: " + threadID + Environment.NewLine; 36 this.BeginInvoke(action); 37 }); 38 thread.IsBackground = true; 39 thread.Start(); 40 } 41 }
@TimYang: 如何开启500个线程的?
@dudu:
ThreadPool.QueueUserWorkItem(p =>
{ IList<string> clientNames = GetClientNames(); foreach (string clientName in clientNames) //这边会循环500次 { InvokeTestMethods(clientName); //这个方法就是开启线程,调用WCF服务
} });
就是这样开启线程的。
@TimYang: 建议先简化一下代码,不进行多线程调用试试
@dudu:
dudu大哥,今天下午也试过了你开一个线程去调用方法。
调用的时间也是会增长的,但不会增长太多,最短时间为20毫秒,最长的为200毫秒。
是不是我WCF的配置文件有点问题呀?
@TimYang: 将WCF服务端操作代码注释掉,看看仅仅调WCF耗时多少
@dudu:
dudu大哥,昨天下午改了一下测试代码,
上一次的测试代码我的客户端实例一直是打开的。
1 private void InvokeTestMethods(string clientName) 2 { 3 Thread thread = new Thread(p => 4 { 5 Stopwatch stopwatch = new Stopwatch(); 6 stopwatch.Start(); 7 string connectionName = clientName; 8 JsonOperationClient testClient = new JsonOperationClient(); //线程每次调用都创建一个客户端实例 9 testClient.Open(); //打开 10 testClient.GetSystemMessageForList(clientName); 11 stopwatch.Stop(); 12 testClient.Close(); //关闭 13 int threadID = Thread.CurrentThread.ManagedThreadId; 14 MyAction action = () => this.richDisplayMessage.Text += connectionName + " 连接成功 - " + stopwatch.ElapsedMilliseconds + ". ||ThreadID: " + threadID + Environment.NewLine; 15 this.BeginInvoke(action); 16 }); 17 thread.IsBackground = true; 18 thread.Start(); 19 }
这样测试下来,发现比第一次的性能更好一点,有提高30%左右。
你说把服务端的操作代码都注释掉,我也试过了,直接返回string.empty.
500个客户端同时调用同一个方法,发现耗时都在10毫秒以下。
如果不注释操作代码,返回值的字符串长度是6万。
@TimYang: 性能瓶颈不在WCF,在你的服务端处理代码
@dudu:
服务端代码可以肯定执行速度很快,就是把数据返回给客户端的时候慢了很多。
我一开始想使用字符串压缩的方法,可是试了几次都没成功。
dudu大哥有什么建议吗?
@TimYang: 试试启用IIS的动态压缩
@dudu:
我的WCF服务是寄宿在Winform中的,这样配置有效吗?
@TimYang: 无效
@dudu:
还有什么建议吗?dudu哥
@TimYang: 没有建议了,我只在IIS中跑过WCF
问题最后是怎么解决的?
你现在遇到什么问题了?
我已经不做WCF很多年了
@TimYang: 现在我们项目用的是wcf,而且部署在阿里云上,那叫一个慢(本来是局域网程序,没有过多考虑性能问题,后来由于不可抗拒原因要放在阿里云上),所以就搜索了下这方面的问题,正好看到这个博问,出于好奇就问了下,谢谢回复。
我现在也不知道我们遇到的性能问题主要是什么原因引起的,别的同事正在研究,老板没让我参与,我在忙别的,而且对wcf不是很熟。不过我一旦有空的话也会研究下,可惜不太可能有空了.....