wcf分布式构架集群案例解决方案
首先声明此文章是源自博客园:http://www.cnblogs.com/huangxincheng/archive/2011/11/13/2246934.html
加上个人总结..先整理如下:
在wcf集群中,高性能的构架中一种常用的手法就是在内存中维护一个叫做“索引”的内存数据库,在实战中利用“索引”这个概念做出“海量数据的”秒杀。
首先,先上架构图:
大体讲解下该系统流程;所谓的Search集群就是图中WCF模块,它分布于不同的服务器上,为了提供高效率的数据检索,我们分步骤进行:
1、我们将数据库中的数据通过程序加载到内存数据库中
2、通过各个服务器中的WCFSearch服务为IIS提供内存数据中的数据检索
3、为了管理不同服务器中的WCFSearch服务,我们利用了“心跳检测”,实现WCFSearch和IIS的搭桥工作
4、在IIS中获取数据索引,然后向本地数据库中提取数据,实现客户端数据提取。
下面重点分析这里面的“心跳检测”的实战手法:
第一步:项目准备,为了显示出该系统构架的优越性我们先新建立个数据库,上图:
类似电子商务中的用户和店铺的关系,一个用户可以开多个店:
我们向这两张表中插入数据,插入百万级别的数据,晒下SQL数据:
------------------------------------------------declare @a int --定义变量declare @m int declare @ShopName char(50) declare @ShopUrl nchar(50) declare @UserName nchar(50)declare @Password nchar(50) set @a=0 --初始值 set @m=0 set @ShopName='淘宝店'set @ShopUrl='www.baidu.com' set @UserName='小吴'set @Password='110' while @a<=1800000 ---循环插入User表180W数据begin insert into [User] (UserName,Passwrod) values (@UserName,@Password) declare @UserID int set @UserID=(select @@identity) while @m<=10 begin insert into dbo.Shop (UserID,ShopName,ShopUrl,User_UserID) values (@UserID,@ShopName,@ShopUrl,null)set @m=@m+1continue end set @m=0 --内循环重置为0set @a=@a+1 continueend --------------------------------------------------------- select * from Shop select * from [User] delete from Shopdelete from [User] truncate table Shop --重置Shop标识列dbcc checkident('[User]',reseed,1) ---重置标识列----------------------------------------------------------
至此,数据库已经准备完毕,我们开始建立项目。
第二步:先晒项目结构:
第三步:先解析LoadDBService项目,该项目实现的是数据库内容的加载,不废话,晒代码:
/** *心跳检测机制 *模拟数据库加载到内存中,形成内存中的数据库*/namespace xinTiaoTest{class Program {static void Main(string[] args) {//这里的Dicionary用来表示“一个注册用户用过了多少个店铺”,即UserID和ShopID的一对多关系 SerializableDictionary<int, List<int>> dic = new SerializableDictionary<int, List<int>>(); List<int> shopIDList = new List<int>();for (int shopID = 3000; shopID < 3050; shopID++) { shopIDList.Add(shopID); }int UserID = 15;//假设这里已经维护了UserID与shopID的关系 dic.Add(UserID, shopIDList); XmlSerializer xml = new XmlSerializer(dic.GetType()); var memoryStrean = new MemoryStream(); xml.Serialize(memoryStrean, dic);//将dic对象写入ID流 memoryStrean.Seek(0, SeekOrigin.Begin); //从0开始读取 //将Dicrionary持久化,相当于模拟保存在Mencache里面 File.AppendAllText("E://1.txt", Encoding.UTF8.GetString(memoryStrean.ToArray())); Console.WriteLine("将数据加载成功"); Console.Read(); } }}
为了序列化List列表,我们引入了该类的序列化:
///<summary>///13 /// 标题:支持 XML 序列化的 Dictionary ///</summary>///<typeparam name="TKey"></typeparam> ///16 ///<typeparam name="TValue"></typeparam> [XmlRoot("SerializableDictionary")]public class SerializableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, IXmlSerializable {public SerializableDictionary() : base() { }public SerializableDictionary(IDictionary<TKey, TValue> dictionary) : base(dictionary) { }public SerializableDictionary(IEqualityComparer<TKey> comparer) : base(comparer) { }public SerializableDictionary(int capacity) : base(capacity) { }public SerializableDictionary(int capacity, IEqualityComparer<TKey> comparer) : base(capacity, comparer) { }protected SerializableDictionary(SerializationInfo info, StreamingContext context) : base(info, context) { }public System.Xml.Schema.XmlSchema GetSchema() {return null; }///<summary> 54 /// 从对象的 XML 表示形式生成该对象 55 ///</summary>///56 ///<param name="reader"></param> public void ReadXml(System.Xml.XmlReader reader) { XmlSerializer keySerializer = new XmlSerializer(typeof(TKey)); XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));bool wasEmpty = reader.IsEmptyElement; reader.Read();if (wasEmpty)return;while (reader.NodeType != System.Xml.XmlNodeType.EndElement) { reader.ReadStartElement("item"); reader.ReadStartElement("key"); TKey key = (TKey)keySerializer.Deserialize(reader); reader.ReadEndElement(); reader.ReadStartElement("value"); TValue value = (TValue)valueSerializer.Deserialize(reader); reader.ReadEndElement();this.Add(key, value); reader.ReadEndElement(); reader.MoveToContent(); } reader.ReadEndElement(); }/**////<summary> 83 /// 将对象转换为其 XML 表示形式 ///84 ///</summary> 85 ///<param name="writer"></param> 86 public void WriteXml(System.Xml.XmlWriter writer) { XmlSerializer keySerializer = new XmlSerializer(typeof(TKey)); XmlSerializer valueSerializer = new XmlSerializer(typeof(TValue));foreach (TKey key in this.Keys) { writer.WriteStartElement("item"); writer.WriteStartElement("key"); keySerializer.Serialize(writer, key); writer.WriteEndElement(); writer.WriteStartElement("value"); TValue value = this[key]; valueSerializer.Serialize(writer, value); writer.WriteEndElement(); writer.WriteEndElement(); } } }}
这样我们就实现了数据库中索引保存为内存数据库中的,当然为了演示我们将其持久化,另存为txt文件。
第四步:新建WCFSearch,用于从内存数据中读取索引,为IIS提供服务,不废话,晒代码:
namespace SearhService{// 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的接口名“IIProduct”。 [ServiceContract]public interface IProduct { [OperationContract] List<int> GetShopListByUserID(int userID); [OperationContract]void TestSrarch(); }}
实现方法:
namespace SearhService{// 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的类名“IProduct”。 public class Product : IProduct { public List<int> GetShopListByUserID(int userID) {//模拟从Memcache中读取索引 SerializableDictionary<int, List<int>> dic = new SerializableDictionary<int, List<int>>();byte[] bytes = Encoding.UTF8.GetBytes(File.ReadAllText("E://1.txt", Encoding.UTF8));var memoryStream = new MemoryStream(); //新建缓存区域 memoryStream.Write(bytes, 0, bytes.Count()); //使用从缓冲区读取的数据将字节块写入当前流。 memoryStream.Seek(0, SeekOrigin.Begin); XmlSerializer xml = new XmlSerializer(dic.GetType());var obj = xml.Deserialize(memoryStream) as Dictionary<int, List<int>>; //反序列化生成对象 return obj[userID]; } public void TestSrarch() {throw new NotImplementedException(); } }}
发布服务:
namespace SearhService{public class SearchHost : ServiceHeartBeat.IAddressCallback { static DateTime startTime;public static void Main() { ServiceHost host = new ServiceHost(typeof(Product)); host.Open(); AddSearch(); Console.Read(); }private static void AddSearch() { startTime = DateTime.Now; Console.WriteLine("Search服务发送中.....\n\n*************************************************\n");try {var heartClient = new ServiceHeartBeat.AddressClient(new InstanceContext(new SearchHost()));string search = ConfigurationManager.AppSettings["search"]; //获取配置的本机service地址 heartClient.AddSearch(search); //添加到连接。 }catch (Exception err) { Console.WriteLine("Search服务发送失败:" + err.Message); } } //服务端回调函数 public void LiveAddress(string address) { Console.WriteLine("恭喜你,"+address+"已经被心跳成功接受"); Console.WriteLine("发送时间:"+startTime+"\n接收时间:"+DateTime.Now.ToString()); } }}
这里有几个点需要注意,在我们首先要引用“心跳服务”,然后将自己的发布的服务地址发送给"心跳服务“,在程序中也就是实现 ServiceHeartBeat.IAddressCallback接口,这是一个”心跳检测“中设置的一个回调接口,目的是实现告诉Search,我已经接受了你的服务,实现数据的推送....
下面是该服务的配置文件:
<?xml version="1.0"?><configuration> <!--设置本service的地址--> <appSettings> <add key="search" value="net.tcp://localhost:8732/Design_Time_Addresses/SearhService/IProduct/"/> </appSettings> <system.serviceModel> <!--添加服务引用生成的客户端的配置资料 --> <bindings> <netTcpBinding> <binding name="NetTcpBinding_IAddress" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" transactionFlow="false" transferMode="Buffered" transactionProtocol="OleTransactions" hostNameComparisonMode="StrongWildcard" listenBacklog="10" maxBufferPoolSize="524288" maxBufferSize="65536" maxConnections="10" maxReceivedMessageSize="65536"> <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/> <reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false"/> <security mode="Transport"> <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign"/> <message clientCredentialType="Windows"/> </security> </binding> </netTcpBinding> </bindings> <client> <endpoint address="net.tcp://localhost:8888/Heart" binding="netTcpBinding" bindingConfiguration="NetTcpBinding_IAddress" contract="ServiceHeartBeat.IAddress" name="NetTcpBinding_IAddress"> <identity> <dns value="localhost"/> </identity> </endpoint> </client> <!--End 添加服务引用生成的客户端的配置资料 --> <!--添加本机服务配置 --> <behaviors> <serviceBehaviors> <behavior name="IProductBehavior"> <serviceMetadata httpGetEnabled="false"/> <serviceDebug includeExceptionDetailInFaults="false"/> </behavior> </serviceBehaviors> </behaviors> <services> <service behaviorConfiguration="IProductBehavior" name="SearhService.Product"> <endpoint address="" binding="netTcpBinding" contract="SearhService.IProduct"> <identity> <dns value="localhost"/> </identity> </endpoint> <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange"/> <host> <baseAddresses> <add baseAddress="net.tcp://localhost:8732/Design_Time_Addresses/SearhService/IProduct/"/> </baseAddresses> </host> </service> </services> </system.serviceModel> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/> </startup></configuration>
这里面有个技巧是在我们在vs2010中新建服务时,添加的服务地址里面包含Design_Time_Addresses路径,这个是vs在安装的时候自己注册的一个安全配置,也就是说在这里面普通的的用户就能够发布服务..为了能发布任何服务,我们在运行vs2010的时候要选择“管理员权限”运行。
第五步:新建ClientService项目,该项目代表的是IIS端,实现的是从内存数据库中获取索引值,也就是连接Srerch,废话不多说,上代码:
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.ServiceModel; namespace ClientService{ [ServiceContract]public interface IServiceList { [OperationContract]void AddSearchList(List<string> search); }}
提供一个AddSearchList方法,目的是让“心跳检测”向IIS端发送Search的地址。
实现代码为:
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading; namespace ClientService{public class ServiceList : IServiceList {public static List<string> serarchilist = new List<string>();static object obj = new object();public static string Search {get { //如果心跳没及时返回地址,客户端就在等候,如果有的话,就随机获取其地址 while (serarchilist.Count == 0) { Thread.Sleep(1000); }return serarchilist[new Random().Next(0, serarchilist.Count)]; }set { } }public void AddSearchList(List<string> search) {lock (obj) { serarchilist = search; Console.WriteLine("心跳发来searche信息************************************"); Console.WriteLine("当前存活的search为:");foreach (var single in serarchilist) { Console.WriteLine(single); } } } }}
配置服务,发布服务
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.ServiceModel;using System.Configuration;using SearhService;using Common;namespace ClientService{class Program:ServiceHeartBeat.IAddressCallback {static void Main(string[] args) { ServiceHost host = new ServiceHost(typeof(ServiceList)); host.Opened += delegate { Console.WriteLine("IIS服务已经启动"); }; host.Open(); //向心跳添加链接,获取service。。 var client = new ServiceHeartBeat.AddressClient(new InstanceContext(new Program()));//获取配置文件中的获取IIS的地址 var iis = ConfigurationManager.AppSettings["iis"];//发送IIS地址给心跳 client.GetService(iis); //从集群中获取search地址来对search服务进行调用 var factory = new ChannelFactory<SearhService.IProduct>(new NetTcpBinding(SecurityMode.None), new EndpointAddress(ServiceList.Search));//根据userID获取了shopId的集合//比如说这里的ShopIDList是通过索引交并集获取分页的一些shopID var shopIDList = factory.CreateChannel().GetShopListByUserID(15); var strSql = string.Join(",", shopIDList); System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch(); //定义时间检测量 watch.Start(); SqlHelper.Query("select s.ShopID,u.UserName,s.ShopName from [User] as u ,Shop as s where s.ShopID in(" + strSql + ")"); watch.Stop();//停止检测 Console.WriteLine("通过wcf索引获取的ID>>>>>花费时间:" + watch.ElapsedMilliseconds); //普通的sql查询花费的时间 StringBuilder builder = new StringBuilder(); builder.Append("select * from "); builder.Append("(select ROW_NUMBER() over(order by s.ShopID) as NumberID, "); builder.Append(" s.ShopID, u.UserName, s.ShopName "); builder.Append("from Shop s left join [User] as u on u.UserID=s.UserID "); builder.Append("where s.UserID=15) as array "); builder.Append("where NumberID>300000 and NumberID<300050"); watch.Start(); SqlHelper.Query(builder.ToString()); watch.Stop(); Console.WriteLine("普通的sql分页 >>>花费时间:" + watch.ElapsedMilliseconds); Console.Read(); } public void LiveAddress(string address) { Console.WriteLine("心跳检测到了你的IIS地址为:" + address ); Console.WriteLine("\n接收时间:" + DateTime.Now.ToString()); } }}
同样的实现ServiceHeartBeat.IAddressCallback,“心跳检测”随时的告诉IIS,已经连接的SearchService,当然在里面在获得了SearchService的时候我们对其进行了连接,然后进行了索引的查询...下面的内容是为了比较这种方法的速度如何,稍后晒测试结果。
下面是该服务的配置文件:
<?xml version="1.0"?><configuration> <appSettings> <add key="iis" value="net.tcp://localhost:2345/ServiceList"/> </appSettings> <system.serviceModel> <client> <endpoint address="net.tcp://localhost:8888/Heart" binding="netTcpBinding" bindingConfiguration="NetTcpBinding_IAddress" contract="ServiceHeartBeat.IAddress" name="NetTcpBinding_IAddress"> <identity> <dns value="localhost" /> </identity> </endpoint> </client> <bindings> <netTcpBinding> <!--客户端验证模式为空--> <binding name="ClientBinding"> <security mode="None" /> </binding> <binding name="NetTcpBinding_IAddress" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" transactionFlow="false" transferMode="Buffered" transactionProtocol="OleTransactions" hostNameComparisonMode="StrongWildcard" listenBacklog="10" maxBufferPoolSize="524288" maxBufferSize="65536" maxConnections="10" maxReceivedMessageSize="65536"> <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" /> <reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false" /> <security mode="Transport"> <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" /> <message clientCredentialType="Windows" /> </security> </binding> </netTcpBinding> </bindings> <!--定义behaviors--> <behaviors> <serviceBehaviors> <behavior name="IProductBehavior"> <serviceMetadata httpGetEnabled="false"/> <serviceDebug includeExceptionDetailInFaults="true"/> </behavior> </serviceBehaviors> </behaviors> <services> <service name="ClientService.ServiceList"> <endpoint address="net.tcp://localhost:2345/ServiceList" binding="netTcpBinding" contract="ClientService.IServiceList" bindingConfiguration="ClientBinding"> <identity> <dns value="localhost" /> </identity> </endpoint> </service> </services> </system.serviceModel> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/> </startup></configuration>
这里面的几个简单的配置需提醒,像客户端验证模式一定要匹配,当然在该项目中我们做了简单的配置,在实际应用中我们会对其作进一步详细配置,以确保服务的流畅性。
第六步:这时候该我们的重头戏出场了..心跳检测的的项目,实现两者的互联,上代码:
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.ServiceModel; namespace HeartBeatService{ //callbackContract:这个就是Client实现回调接口,方便服务器通知客户端 [ServiceContract(CallbackContract = typeof(ILiveAddressCallback))]public interface IAddress {//此方法用于Search方法启动后,将Search地址插入此处 [OperationContract(IsOneWay=true)]void AddSearch(string address); //此方法用于IIS获取Search地址 [OperationContract(IsOneWay=true)]void GetService(string address); } }
两个方法,第一个实现Search地址的获取,第二个实现IIS的检测,上面加了一个回调接口:ILiveAddressCallback方法,实现的是客户端数据的应答。方法如下:
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.ServiceModel; namespace HeartBeatService{///<summary>10 /// 等客户端实现后,让客户端约束一下///,只能是这个LiveAddress方法11 ///</summary> public interface ILiveAddressCallback { [OperationContract(IsOneWay = true)]void LiveAddress(string address); }}
下面是心跳检测的核心代码,上代码:
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.ServiceModel;using System.Timers;using System.Configuration;using SearhService;using ClientService; namespace HeartBeatService{//InstanceContextMode:只要是管理上下文的实例,此处是single,也就是单体//ConcurrencyMode:主要是用来控制实例中的线程数,此处是Multiple,也就是多线程 [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)] public class Address : IAddress { static List<string> search = new List<string>();static object obj = new object(); //构造函数用来检测Search的个数 static Address() { Timer timer = new Timer(); timer.Interval = 6000; timer.Elapsed += (sender, e) => { Console.WriteLine("\n》》》》》》》》》》》》》》》》》》》》》》"); Console.WriteLine("当前存活的search为:");lock (obj) {//遍历当前存活的search foreach (var single in search) { ChannelFactory<IProduct> factory = null;try {//当search存活的话,心跳服务就要检测search是否死掉,也就是定时检测连接Search来检测 factory = new ChannelFactory<IProduct>(new NetTcpBinding(SecurityMode.None), new EndpointAddress(single)); factory.CreateChannel(); factory.Close(); Console.WriteLine(single); }catch (Exception err) { Console.WriteLine(err.Message); //如果抛出异常,则说明此search已经挂掉 search.Remove(single); factory.Abort(); Console.WriteLine("\n当期时间:" + DateTime.Now + ",存活的search有:" + search.Count() + "个"); } }//最后统计下存活的search有多少个 Console.WriteLine("\n当前时间:" + DateTime.Now + " ,存活的Search有:" + search.Count() + "个"); } }; timer.Start(); }public void AddSearch(string address) {lock (obj) {//是否包含相同的Search地址 if (!search.Contains(address)) { search.Add(address);//search添加成功后就要告诉来源处,此search已经被成功载入。 var client = OperationContext.Current.GetCallbackChannel<ILiveAddressCallback>(); client.LiveAddress(address); } } } public void GetService(string address) { Timer timer = new Timer(); timer.Interval = 1000; timer.Elapsed += (obj, sender) => {try {//这个是定时的检测IIS是否挂掉 var factory = new ChannelFactory<IServiceList>(new NetTcpBinding(SecurityMode.None),new EndpointAddress(address)); factory.Opened += delegate { Console.WriteLine("IIS("+address+")已经启动..正在发送searchSerive地址..."); }; factory.CreateChannel().AddSearchList(search); factory.Close(); timer.Interval = 20000; }catch (Exception ex) { Console.WriteLine(ex.Message); } }; timer.Start(); } } }
为确保不丢掉任何的Search服务,我们采用多线程,InstanceContextMode:只要是管理上下文的实例,此处是single,也就是单体 ConcurrencyMode:主要是用来控制实例中的线程数,此处是Multiple,也就是多线程。
1、构造函数的静态方法实现当前服务的检测和显示,采用Timer定时检测...
2、AddSearch方法实现Search的添加,并回复客户端
3、GetService方法实现的是检测IIS是否等待连接,并且将Search集合发送给它,同样是定时发送。
下面晒配置文件:
<?xml version="1.0"?><configuration> <system.web> <compilation debug="true"/> </system.web> <!-- 部署服务库项目时,必须将配置文件的内容添加到 主机的 app.config 文件中。System.Configuration 不支持库的配置文件。--> <system.serviceModel> <services> <service name="HeartBeatService.Address" behaviorConfiguration="myBehavior"> <endpoint address="net.tcp://localhost:8888/Heart" binding="netTcpBinding" contract="HeartBeatService.IAddress"> <identity> <dns value="localhost"/> </identity> </endpoint> <!--定义引用地址元数据的接受方式,此处基地址(baseAddress)定义的协议Http所以binding同样为mexHttpBinding方式--> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/> <host> <baseAddresses> <add baseAddress="http://localhost:9999/Heart"/> </baseAddresses> </host> </service> </services> <behaviors> <serviceBehaviors> <behavior name="myBehavior"> <!-- 为避免泄漏元数据信息, 请在部署前将以下值设置为 false 并删除上面的元数据终结点 --> <serviceMetadata httpGetEnabled="True"/> <!-- 要接收故障异常详细信息以进行调试, 请将以下值设置为 true。在部署前设置为 false 以避免泄漏异常信息--> <serviceDebug includeExceptionDetailInFaults="False"/> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel> <startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>
至此,我们已经成功顺利的搭建完心跳检测的流程,我们先运行下“心跳”项目,它将等待Search发送连接过来,并检查IIS时候等候状态...
然后我们再运行Search...向“心跳”抛出橄榄枝...
嘿嘿,两者已经顺利握手...下面咱把IIS启动,看看“心跳检测”是否能将这个SearchService发送给它:
同样成功,这说明我们的心跳服务还是能实时的为IIS提供连接地址的..
好,下面我们测试该框架性能如何,首先我们执行LoadDBService,将数据库加载到内存中...结果如下:
我们用该框架测试下速度和普通的查询方式进行比较:
先晒SQL语句,看两者差距性:
select * from (select ROW_NUMBER() over(order by s.ShopID) as NumberID, s.ShopID, u.UserName, s.ShopName from Shop s left join [User] u on u.UserID=s.UserID where s.UserID=150) as array where NumberID>0 and NumberID<50 -------------------分页查询-------------------------select s.ShopID,u.UserName,s.ShopName from [User] as u , Shop as s where s.ShopID in(100,200,3000,5000,4000,201) select * from shop select * from [user]
我们在IIS端进行加载检测:
晒运行结果:
提示了一个错误:
我们将此服务的连接时间该的长一点:
这个错误是因为和客户端验证模式不对,我们在这里面做了设置,将其设置为None,为了确保从内存数据库中读取完毕,我们将应答时间该的稍长点。我们下面晒结果:
这里看样子也快不了多少,那是因为我们在wcf里查询的条数设置和SQL里面的语法查询条数不同,我们将改一下,还有就是在此服务已有一个,并且内存数据库实现的方式是通过本地化文件操作,很显然是费时费力的工作,就性能均摊,可扩展性等方面,无疑该框架是利器...好了先解析到此..
转载于:https://www.cnblogs.com/zhijianliutang/archive/2011/11/22/2258844.html
wcf分布式构架集群案例解决方案相关推荐
- 分布式 WebSocket 集群解决方案
作者 | weixin_34194702 来源 | blog.csdn.net/weixin_34194702/article/details/88701309 问题起因 最近做项目时遇到了需要多用户 ...
- 分布式与集群的区别是什么?
分布式与集群的区别是什么? 关注者 1,561 被浏览 449,153 关注问题写回答 邀请回答 1 条评论 分享 举报 53 个回答 默认排序 大闲人柴毛毛 渴求Java开发!内推蚂蚁 ...
- 深入浅出Websocket(二)分布式Websocket集群
前言 最近在构建两个系统的实时通信部分,总结一下所学. 这是一个系列文章,暂时主要构思四个部分 深入浅出Websocket(一)Websocket协议 深入浅出Websocket(二)分布式Webso ...
- 分布式ActiveMQ集群--转载
原文地址:http://shensy.iteye.com/blog/1752529 回顾总结前一段时间学习的ActiveMQ分布式集群相关的知识,分享出来希望对看到的人有所帮助. 一.分布式Activ ...
- 保障IDC安全:分布式HIDS集群架构设计
背景 近年来,互联网上安全事件频发,企业信息安全越来越受到重视,而IDC服务器安全又是纵深防御体系中的重要一环.保障IDC安全,常用的是基于主机型入侵检测系统Host-based Intrusion ...
- 分布式精华问答 | 分布式与集群的区别是什么?
什么是分布式计算?所谓分布式计算是一门计算机科学,它研究如何把一个需要非常巨大的计算能力才能解决的问题分成许多小的部分,然后把这些部分分配给许多计算机进行处理,最后把这些计算结果综合起来得到最终的结果 ...
- 多台电脑集群运算_一个分布式服务器集群架构方案
深圳市添越智创科技有限公司 店铺链接:shop114963t53p883.1688.com 移动互联应用的快速发展和云计算.大数据应用的拓展和深化,数据中心已由传统的大型机.小型机逐步转移到x86服务 ...
- 分布式与集群(一):我眼中的分布式与集群
[前言] 很早之前听说过分布式和集群,刚开始接触的时候感觉特别的高大上,随着自己对相关知识的系统学习以及在项目中不断的应用,自己对它的理解也更加的深刻: 同时自己也在一直问自己,这种技术是在什么背景下 ...
- 19 分布式缓存集群的伸缩性设计
不同于应用服务器集群的伸缩性设计,分布 式缓存集群的伸缩性不能使用简单的负载均衡手段来实现. 和所有服务器都部署相同应用的应用服务器集群不同,分布式缓存服务器集群中不同服务器中缓存的数据各不相同,缓存 ...
最新文章
- Python 中少为人知的 10 个安全陷阱
- 利用LeNet识别十种动物和水果
- Dynamic Setting ImageUrl In DataPager
- 无BOM禁止转生产订单
- 在sts中springboot工程的maven解析异常处理
- 微信朋友圈删除后服务器还有吗,删了的朋友圈还可以找回来吗
- python在函数外调用变量
- ajax静态加载图片,JQuery实现Ajax加载图片的方法
- Oracle中对象权限与系统权限revoke
- Java添加水印+图片水印+文字水印
- Spring教程– Spring Core Framework教程
- StorAge存储库
- 博文视点图书市场快讯 第46期
- 软考c语言题库,【中级】软考题库每日一练|4.4
- js传递参数时类型错误
- 会使您势不可挡的程序员的行为
- 常用类库-java.lang.String
- win10重装系统(正版)(好用)(带激活方法)
- 如何打造极速F1赛事?乐视云用六路信号还原比赛现场
- Odoo与浪潮合资研发PS Cloud之如何在Odoo中进行搜索引擎优化(5)
热门文章
- Pair智能标注神器,全面升级,更加智能
- Dropout也能自动化了,谷歌Quoc Le等人利用强化学习自动找寻模型专用Dropout
- 谷歌Auto-DeepLab:自动搜索图像语义分割架构算法开源实现
- mysql客户端路由方式_20.3 在InnoDB 集群中 使用MySQL 路由
- 【Matplotlib】【Python】如何使用matplotlib绘制各种图形
- 数据结构期末复习之平衡二叉树
- mysql wb bbu_BBU
- 设计模式 建造者模式
- mysql安装后变10g_Oracle 10G安装中一些常见问题解决
- 信息安全工程师考试大纲