In WCF cluster, a common technique in high-performance architecture is to maintain an in-memory database called “index”, and make use of the concept of “index” to make “massive data” in practice.

First, the shelf composition:

General explanation of the system process; The so-called Search cluster is the WCF module in the figure, which is distributed on different servers. In order to provide efficient data retrieval, we conduct it step by step:

1. We load the data in the database into the in-memory database through the program

2, through the WCFSearch service in each server for IIS to provide data retrieval in memory data

3. In order to manage WCFSearch service in different servers, we use “heartbeat detection” to bridge WCFSearch and IIS

4. Obtain data index in IIS, and then extract data from the local database to achieve client data extraction.

The following focuses on the analysis of the “heartbeat detection” of the actual combat techniques:

Step 1: Project preparation. In order to show the advantages of the system architecture, we first set up a new database. Figure above:

Similar to the relationship between users and stores in e-commerce, one user can open multiple stores:

We insert data into these two tables, insert millions of data, and expose SQL data:

------------------------------------------------
declare @a  int-- Define variable declare @mint

declare @ShopName char(50) 
declare @ShopUrl  nchar(50)


declare @UserName nchar(50)
declare @Password nchar(50)

set @a=0- the initial valueset @m=0

set @ShopName=Taobao Shop
set @ShopUrl='www.baidu.com'

set @UserName='xiao wu'
set @Password='110'

while  @a<=1800000-- Insert the User table cyclically180W Data begin INSERTinto [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+1
           continue
         end 
set @m=0-- Inner loop reset to0
set @a=@a+1 
continue
end

---------------------------------------------------------

select * from Shop

select * from [User]

delete  from Shop
delete from[User] TRUNCate table Shop -- reset Shop identity columndbcc checkident('[User]',reseed,1- reset the identity column -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --Copy the code

At this point, the database is ready and we can start building the project.

Step 2: Sun project structure:

LoadDBService (LoadDBService); LoadDBService (LoadDBService);

/** * Heartbeat detection mechanism * emulates database loading into memory, forming in-memory database */
namespace xinTiaoTest
{
    class Program
    {
        static void Main(string[] args)
        {
            // Dicionary is used to indicate "how many stores a registered user has used", i.e. the one-to-many relationship between UserID and 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;
            // Assume that the relationship between UserID and shopID is maintained
            dic.Add(UserID, shopIDList);

            XmlSerializer xml = new XmlSerializer(dic.GetType());

            var memoryStrean = new MemoryStream();

            xml.Serialize(memoryStrean, dic);// Write the dic object to the ID stream
            memoryStrean.Seek(0, SeekOrigin.Begin); // Start reading from 0

            // Persist Dicrionary, which is equivalent to storing the simulation in Mencache
            File.AppendAllText("E://1.txt", Encoding.UTF8.GetString(memoryStrean.ToArray()));

            Console.WriteLine("Data loaded successfully"); Console.Read(); }}}Copy the code

To serialize the List, we introduce the serialization of the class:

///<summary>
    ///13 ///Title: Dictionary that supports XML serialization
    ///</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 ///Generate the object from the XML representation of the object 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 ///Converts an object to its XML representation
        ///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(); }}}}Copy the code

In this way we have implemented the database to save the index in memory database, of course for the sake of demonstration we will persist it, save it as TXT file.

Step 4: Create WCFSearch, which is used to fetch indexes from memory data and provide services for IIS.

namespace SearhService
{
    // Note: You can change the interface name IIProduct in both the code and configuration file using the rename command on the Refactor menu.
    [ServiceContract]
    public interface IProduct{[OperationContract]
        List<int> GetShopListByUserID(int userID);
        [OperationContract]
        void TestSrarch(); }}Copy the code

Implementation method:

namespace SearhService
{
    // Note: Use the Rename command on the Refactor menu to change the class name "IProduct" in both the code and the configuration file.
    public class Product : IProduct
    {
        
        public List<int> GetShopListByUserID(int userID)
        {
           // simulate reading index from 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(); // Create a new cache area
            memoryStream.Write(bytes, 0, bytes.Count()); // Writes byte blocks to the current stream using data read from the buffer.
            memoryStream.Seek(0, SeekOrigin.Begin);

            XmlSerializer xml = new XmlSerializer(dic.GetType());
            var obj = xml.Deserialize(memoryStream) as Dictionary<int, List<int> >;// Deserialize the generated object

            return obj[userID];

        }

        public void TestSrarch()
        {
            throw newNotImplementedException(); }}}Copy the code

Publishing services:

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 service sending..... \n\n*************************************************\n");
            try
            {
                var heartClient = new ServiceHeartBeat.AddressClient(new InstanceContext(new SearchHost()));
                string search = ConfigurationManager.AppSettings["search"]; // Get the configured local service address

                heartClient.AddSearch(search);  // Add to the connection.
            }
            catch (Exception err)
            {
                Console.WriteLine("Search service failed to send:"+ err.Message); }}// Server-side callback function
        public void LiveAddress(string address)
        {
            Console.WriteLine("Congratulations,"+address+"Has been successfully accepted by the heartbeat.");
            Console.WriteLine("Delivery time:"+startTime+"\n Reception time:"+DateTime.Now.ToString()); }}}Copy the code

Here are a few points need to note that in we’ll be the first to refer to “the heart service”, and then will be released its own service address sent to the “heart services”, in the program is to achieve ServiceHeartBeat IAddressCallback interface, it is a “heartbeats” set a callback interface, The purpose is to realize tell Search, I have accepted your service, realize the data push…

Here is the configuration file for the service:

<? xml version="1.0"? > <configuration> <! --> <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 adds a service reference to the generated client configuration --> <! Add local service configurations --> <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>
Copy the code

One trick is that when we add a new service in VS2010, we add Design_Time_Addresses to the address of the service. This is a security configuration that VS registered at installation time, which means that ordinary users can publish the service… In order to be able to publish any services, we need to select “Administrator rights” when running VS2010.

Step 5: Create a ClientService project, which represents the IIS server. This project is implemented to fetch index values from the in-memory database, that is, to connect to 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); }}Copy the code

Provides an AddSearchList method that causes Heartbeat Detection to send the address of Search to IIS.

The implementation code is:

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(a);public static string Search
        {
            get
            {               
                    // If the heartbeat does not return the address in time, the client waits, and if it does, randomly fetches its address
                    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("Heartbeat from searche information * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *");
                Console.WriteLine("The current surviving search is:");
                foreach (var single in serarchilist)
                {
                    Console.WriteLine(single);
                }
            }
        }
    }
}
Copy the code

Configure and publish services

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 services have been started.");
            };
            host.Open();


            // Add a link to the heartbeat to get the service.
            var client = new ServiceHeartBeat.AddressClient(new InstanceContext(new Program()));
            // Get the IIS address in the configuration file
            var iis = ConfigurationManager.AppSettings["iis"];
            // Send the IIS address to the heartbeat
            client.GetService(iis);
       

            // Get the search address from the cluster to call the search service
            var factory = new ChannelFactory<SearhService.IProduct>(new NetTcpBinding(SecurityMode.None), new EndpointAddress(ServiceList.Search));
            // Get a set of shopids based on userID
            // For example, the ShopIDList is a set of shopids that get pages through the index union
            var shopIDList = factory.CreateChannel().GetShopListByUserID(15);



            var strSql = string.Join(",", shopIDList);

            System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch(); // Define the amount of time detected

            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();// Stop the test

            Console.WriteLine("ID obtained by WCF index >>>>> take time :" + watch.ElapsedMilliseconds);


            // The amount of time a normal SQL query takes
            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("Normal SQL paging >>> Takes time :" + watch.ElapsedMilliseconds);

            Console.Read();
        }

        public void LiveAddress(string address)
        {
            Console.WriteLine("Heartbeat detected your IIS address as:" + address );
            Console.WriteLine("\n Reception time:"+ DateTime.Now.ToString()); }}}Copy the code

The implementation of the same ServiceHeartBeat IAddressCallback, “heartbeats” tell IIS at any time, have connection SearchService, of course inside in the SearchService when we on the connection, then the index of the query… The following is to compare the speed of this method and post the results later.

Here is the configuration file for the service:

<? 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> <! -- Empty client validation mode --> <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> <! Define 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>
Copy the code

A few simple configurations above need to be reminded, such as the client authentication mode must match. Of course, we did a simple configuration in this project, but we will further configure it in practice to ensure the smoothness of the service.

Step 6: It’s time for our big show… Heartbeat detection of the project, to achieve the interconnection of the two, code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;


namespace HeartBeatService
{    
   
        //callbackContract: This is the Client implementation of the callback interface, convenient for the server to notify the Client
        [ServiceContract(CallbackContract = typeof(ILiveAddressCallback))]
        public  interface  IAddress
        {
            // This method is used to insert the Search address here after the Search method is started
            [OperationContract(IsOneWay=true)]
            void  AddSearch(string  address);

            // This method is used by IIS to get the Search address
            [OperationContract(IsOneWay=true)]
            void  GetService(string  address); }}Copy the code

Two methods, the first implementation of the Search address to obtain, the second implementation of IIS detection, above the addition of a callback interface: ILiveAddressCallback method, the realization of the client data response. The method is as follows:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;

namespace HeartBeatService
{
    ///<summary>10 ///After the client implements it, let the client constrain it
    ///, can only be this LiveAddress method 11///</summary>
    public interface ILiveAddressCallback{[OperationContract(IsOneWay = true)]
        void LiveAddress(string address); }}Copy the code

The following is the core code of heartbeat detection, the above code:

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: as long as it is an instance of the management context, in this case, single
    //ConcurrencyMode is used to control the number of threads in the instance
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]

    public class Address : IAddress
    {

        static List<string> search = new List<string> ();static object obj = new object(a);// The constructor detects the number of searches
        static Address()
        {
            Timer timer = new Timer();
            timer.Interval = 6000;
            timer.Elapsed += (sender, e) =>
                {
                    Console.WriteLine("\n》》》》》》》》》》》》》》》》》》》》》》");
                    Console.WriteLine("The current surviving search is:");
                    lock (obj)
                    {
                        // Traverses the current surviving search
                        foreach (var single in search)
                        {
                            ChannelFactory<IProduct> factory = null;
                            try
                            {
                                // When the search is alive, the heartbeat service checks whether the search is dead, that is, periodically checks the connection to 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);

                                // If an exception is thrown, the search has died
                                search.Remove(single);
                                factory.Abort();
                                Console.WriteLine("\n Current time:" + DateTime.Now + ", the surviving search has:" + search.Count() + "个"); }}// Count the number of viable searches
                        Console.WriteLine("\n Current time:" + DateTime.Now + ", the surviving Search has:" + search.Count() + "个"); }}; timer.Start(); }public void AddSearch(string address)
        {
            lock (obj)
            {
                // Whether to include the same Search address
                if(! search.Contains(address)) { search.Add(address);// Search is successfully added to tell the source that the search has been successfully loaded.
                    varclient = OperationContext.Current.GetCallbackChannel<ILiveAddressCallback>(); client.LiveAddress(address); }}}public void GetService(string address)
        {
            Timer timer = new Timer();
            timer.Interval = 1000;
            timer.Elapsed += (obj, sender) =>
            {
                try
                {
                    // This is a timer to check if IIS is down
                    var factory = new ChannelFactory<IServiceList>(new NetTcpBinding(SecurityMode.None),
                                                                   new EndpointAddress(address));
                    factory.Opened += delegate
                    {
                        Console.WriteLine("IIS("+address+") has started.. Sending searchSerive address...");
                    };
                    factory.CreateChannel().AddSearchList(search);
                    factory.Close();

                     timer.Interval = 20000; } catch (Exception ex) { Console.WriteLine(ex.Message); }}; timer.Start(); }}}Copy the code

InstanceContextMode: as long as the instance of the management context is single, ConcurrencyMode: mainly used to control the number of threads in the instance. Multiple, Multiple threads.

1, the static method of the constructor to achieve the detection and display of the current service, using Timer timing detection…

2. AddSearch method adds Search and replies to the client

3. The GetService method detects if IIS is waiting for a connection and sends it the Search collection, again timed.

The following configuration file is displayed:

<? xml version="1.0"? > <configuration> <system.web> <compilation debug="true"/> </system.web> <! When deploying a service library project, you must add the contents of the configuration file to the host's app.config file. System.Configuration does not support library Configuration files. --> <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> <! Set baseAddress to mexHttpBinding --> <endpoint address= set baseAddress to mexHttpBinding"mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:9999/Heart"/>
          </baseAddresses>
        </host>
      </service>
    </services>

    <behaviors>
      <serviceBehaviors>
        <behavior name="myBehavior"> <! To avoid leaking metadata information, set the following values tofalseDelete the metadata endpoint above --> <serviceMetadata httpGetEnabled="True"/ > <! -- To receive fault exception details for debugging, set the following value totrue. Set this parameter before deploymentfalseIn order to avoid leakage anomaly information - > < serviceDebug includeExceptionDetailInFaults ="False"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>

<startup><supportedRuntime version="v4.0" sku=". NETFramework, Version = v4.0. ""/></startup></configuration>
Copy the code

At this point, we have successfully set up the heartbeat detection process, let’s first run the “heartbeat” project, it will wait for Search to send a connection, and check the waiting status of IIS…

Then we run Search… Offer an olive branch to the heartbeats…

Heh heh, the two have successfully shake hands… Let’s start IIS and see if heartbeat Detection can send this SearchService to it:

Also successful, this shows that our heartbeat service can still provide a connection address to IIS in real time…

LoadDBService is used to load the database into memory. The results are as follows:



We use this framework to test the speed and ordinary query method comparison:

First exposed to the SQL statement, see the difference between the two:

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------------------- Paging query -------------------------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]
Copy the code

We perform load detection on IIS:

Drying and running results:

Error:

We should make the connection time of this service longer:

This error is due to the wrong client validation mode. We set it to None in here. To make sure that we have finished reading from the in-memory database, we will reply a little longer. Let’s show the results

: Here it’s not much faster, it is because we in the WCF query Settings and SQL query syntax of the number of the article number is different, we will change, and in the service for one, and memory database implementation way is through the localization file operations, obviously is laborious work, is between performance and scalability, etc., There is no doubt that the framework is a weapon… Okay, so much for the analysis…