原文地址

Level of Difficulty 1 2 3

SUMMARY

Performance is an important concern for any application, but becomes critical when the app is a Web Service accessed by thousands of clients simultaneously. One hardware approach to distributing Web Services requests evenly is a Web farm consisting of multiple servers. Once on a Web farm, Web Service performance can be improved by using ADO.NET DataSet objects to cache frequently accessed data, reducing round-trips to the database. Here the author describes data caching in a Web farm environment and discusses how to avoid the cross-server synchronization problems inherent in this approach.

  Contents

Improving Performance with Data Caching
Sharing Data with Other Servers
Creating the Refresh Web Methods
Calling the Refresh Methods
Adding New Servers
Conclusion

Performance and scalability are critical to Web Services. You must ensure not only that your Web Service always performs well, but that it will continue to do so as the user load increases. A Web Service that is lightning fast with 50 users does little good if it fails when it has to handle 500 users.

There are many ways to improve Web Service performance. One of the more common ways is to use data caching by storing DataSet objects in either a Session or Application object. This technique improves performance by accessing data in RAM, thus eliminating round-trips to the database. A DataSet object stored in the Session or Application cache provides much better data access performance than having each Web Service request pull its own data from the database.

Moving your Web Service to a Web farm can also improve performance by distributing the workload over several servers. A Web farm also provides redundancy, ensuring that your Web Service is always available even if one of your Web servers goes down. However, moving to a Web farm rules out the use of Application data caching because the Application object is unique to each Web server. Since each Web server has its own copy of the DataSet cached in memory, data will become out of sync when data on one of the Web servers is updated independently of the others. Since you have no control over which server in a Web farm receives a request, the Web Service consumer might receive different results from two consecutive Web Service calls hitting two different Web servers, as shown in Figure 1.

Figure 1 Out of Sync Data Using a Web Farm

ASP.NET has built-in techniques that are designed to allow Web sites to share Session state information. Unfortunately, this often comes at the expense of performance. Session state data can be stored in a SQL Server™ database, but this eliminates the performance benefit of using cached data since round-trips to the database are required to read the state information. State information can also be stored on a shared server running the ASP.NET state service, but this introduces a single point of failure: if the shared state server goes down, all Web servers that depend on it are rendered inactive. This eliminates the redundancy created by establishing a Web farm. Furthermore, if the data in question is being shared by all users, it makes sense to store it in the Application object rather than duplicate it in multiple Session objects.

I have described a scenario in which I want to cache data in the Application object without losing any of the performance and redundancy benefits of my Web farm or jeopardizing the integrity of my data. In this article I will describe a set of techniques that can be used to improve XML Web Service performance using application data caching in a Web farm, without sacrificing scalability or redundancy.

Improving Performance with Data Caching

Imagine a company that offers credit card authorization to customers through an XML Web Service named AuthorizeCC, developed using Visual Basic® .NET. Customers of the Web Service build their own Web site around the functionality provided by the Web Service. The company that developed the Web Service also uses it on its own Web site. Due to the nature of the functionality provided, it is critical that the Web Service is optimized for speed and is available 24×7. If the XML Web Service is unavailable, even for a short period of time, both the company and all of its customers stand to lose lots of revenue.

In order to maximize Web Service performance and provide redundancy, the company has created a small Web farm consisting of two servers, named Server1 and Server2. Both servers offer only the AuthorizeCC Web Service and are load balanced in order to provide better performance. It is critical that at least one of the Web servers is always available so that consumers always have access to the Web Service. The company plans to expand its customer base quite rapidly, which will require adding additional servers to the farm in the near future.

The AuthorizeCC Web Service contains several Web methods. Each Web Service consumer is authenticated with a user name and password combination during each Web method call. I want to cache the basic information about each of the customers since it will be used in every Web method call and will change infrequently. Customers can, however, update their password or other information at any time using another method provided by the Web Service. Any changes made to customer information must be used for all subsequent calls to any method in the AuthorizeCC service.

Several of the customers who use the Web Service employ Web farms, which makes caching my customer data in the Session object inappropriate. Since a single customer may be using many Web servers in a farm to access my XML Web Service, that customer would create many Session objects on my Web server that cache exactly the same DataSet object, leading to a lot of wasted resources. Furthermore, Session objects won't allow me to update all cached information immediately upon a change made by the customer. If a customer updates his information in one Session object, I have no way to tell the other Session objects to update their own data. I will therefore use the Application object to cache a DataSet object with information about all customers.

The code in Figure 2 creates a private subroutine named GetCachedData. This routine creates the necessary SQLConnection, SQLCommand, and SQLDataAdapter objects to fill a temporary DataSet object. I fill two tables in the DataSet, one for Customer information and one for InvalidCardNumbers. The temporary DataSet object is then placed in the Application object's dictionary with the key "CachedData".

  Figure 2 Retrieve and Cache a DataSet

Copy Code

Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs)
If Application("CachedData") Is Nothing Then GetCachedData
End SubPublic Sub GetCachedData()Dim conn As New System.Data.SqlClient.SqlConnection() 'Connection to 'database
Dim ds As New DataSet()                               'The new datasetconn.ConnectionString = "server=localhost;database=MSDN1;uid=sa;pwd="
conn.Open()'Get the data
FillTable("SELECT * FROM Customer", "Customer", ds, conn)'Get the InvalidCardNumbers data
FillTable("SELECT * FROM InvalidCard", "InvalidCard", ds, conn)'Get the Server Names
FillTable("SELECT ServerName FROM ServerName", "ServerName", ds, conn)'Store all objects in the Application cache
Application.Item("CachedData") = ds
End SubPrivate Function FillTable(ByVal SQL As String, ByVal TableName As _String, ByRef ds As DataSet, _ ByVal conn As SqlClient.SqlConnection)
Dim da As SqlDataAdapter
Tryda = New SqlDataAdapter("SELECT ServerName FROM ServerName", conn)da.MissingSchemaAction = MissingSchemaAction.AddWithKeyda.Fill(ds, TableName)
Catch ex As Exception
'Handle exception here
End Try
End Function

Note that I only want to create and fill the temporary DataSet when it does not already exist in the Application object, so I have placed the code to do this within an If...Then construct that checks to see if the current value of Application.Item("CachedData") is nothing. When an object is stored in the Application object with the key "CachedData", the DataSet will not be recreated. There are two situations when this will occur: when the application is run for the first time and when the Application cache has been cleared due to inactivity. You can control how many minutes the application will wait without any activity happening before clearing out the Application cache by specifying a value in the Application configuration settings for the Web site.

Finally, I need this functionality to be executed prior to every method call which will need to use the cached data. Rather than placing a call to GetCachedData in each method call, I've made the call just once in the Start event handler for my Session object. This technique executes the code during the creation of every session. After the data is stored in the Application object, the only code that is executed is the very fast If...Then statement. This performance hit is usually deemed acceptable to ensure that the code is called before every method that does access the cached data.

This code could be optimized slightly by moving it to the Start event handler for the Application object. In this case, the code would not be run at all, except when the Application object has not been initialized or has timed out. This does incur an additional risk. If the DataSet object stored in the Application object is deleted or corrupted and a Web method call is made before the application times out, the code will raise an exception trying to access the nonexistent DataSet. I could write code to catch these exceptions everywhere I access the DataSet, but I opted for simplicity by ensuring that the DataSet exists before every Web method call.

The AuthorizeCC Web Service contains several Web methods that allow consumers to authorize credit cards, verify customers, and update their own information. The service must make judicious use of data caching techniques in order to provide the best performance. Each Web Service request must identify the customer making the request in order to determine the appropriate fee to charge the customer. Determining the correct data to cache is a balancing act, however. Any data cached in an Application object consumes precious memory resources and negatively impacts performance. You must ensure that the negative impact caused by the amount of data cached in memory is outweighed by the performance increase gained by reducing the total number of database calls.

For the AuthorizeCC Web Service, it makes sense to cache information about the customers who will be using the service. Customer ID and password will be cached since these will be verified in every method call. Additionally, since the most frequently used Web method will likely be AuthorizeTransaction, I will cache information on transaction dollar limits for each customer. This will be checked during each AuthorizeTransaction call to ensure that the pending transaction does not exceed the dollar limit for the customer. Finally, I have a database table filled with invalid credit card numbers that will be checked before authorizing any transaction. This will be cached as well to ensure that no invalid credit cards are authorized. By simply caching the most basic data that will be frequently used, I eliminate all database reads from the most common Web methods.

Figure 3 Data Storage

Data such as extended customer information and sales history will not be cached due to the sheer volume of data present and their infrequent use. The Web methods will be hardcoded with the knowledge of where each type of data is stored, as shown in Figure 3, either in the database or in the Application cached DataSet, but it would be fairly trivial to make this information dynamic.

Sharing Data with Other Servers

Now that I have data cached in the Application object and the Web methods are using the cached data, saving round-trips to the database, I'll turn my attention to building a Web farm. If I add a second Web server offering the Web Service, I also introduce the possibility of data becoming out of sync. As Web method requests begin to come into the servers, each one pulls the appropriate data from the database, creates its own DataSet, and stores the DataSet in the Application object. Web methods on both machines then pull data from their own Application object and fulfill requests.

This works well until an employee at one of the companies that uses the Web Service logs into the AuthorizeCC Administration Web site and increases the maximum dollar amount that the company allows for transactions. The administration Web site calls the appropriate Web Service and the request is answered by the first Web server in my farm. The service now needs to update the value in both the database and in the cached DataSet.

The code needed to update the DataSet stored in memory can be constructed in multiple ways. The simplest technique would be to simply execute direct SQL statements against the database using the ExecuteNonQuery method of the SQLCommand object. After the database is properly updated, you can call the GetCachedData subroutine to pull the entire DataSet from the database again. This technique is straightforward and works very solidly, but does not offer the best performance. To improve performance, you should manually update the DataSet object. You can do this by finding the DataRow in question and setting the value of the appropriate item in the DataRow's Item array, as shown in Figure 4.

  Figure 4 Update Database and Cached DataSet

Copy Code

Private Sub UpdateTransactionLimit(ByVal ID As Integer, _ByVal NewTransLimit As Single)
'Update the database
Dim SQL As String
SQL = "UPDATE Customer SET TransactionLimit=" & NewTransLimit & _" WHERE ID=" & ID.ToString()
Dim conn As New System.Data.SqlClient.SqlConnection()
Dim cmd As New System.Data.SqlClient.SqlCommand(SQL)conn.ConnectionString = "server=localhost;database=MSDN1;uid=sa;pwd="
conn.Open()
cmd.Connection = conn
cmd.ExecuteNonQuery()'Update the dataset as well
Dim dr As DataRow
dr = CType(Application.Item("CachedData"), DataSet).Tables("Customer").Rows.Find(ID)
dr.Item("TransactionLimit") = NewTransLimit
End Sub

If you choose to update the DataSet object yourself, you still have to update the database to ensure that the changes are persisted. This can be accomplished using the same direct SQL statements I've discussed previously and included in Figure 4. In this scenario, you have still improved performance by eliminating the need to pull known data values from the database.

An alternative is to use the SQLDataAdapter to allow ADO.NET to push the changes made in the DataSet back to the database. This performs similarly to writing your own direct SQL statements because the SQLDataAdapter uses SQLCommand objects with appropriate SQL update statements set in the CommandText property.

The benefit of using a SQLDataAdapter is twofold. First, it makes it much easier to change multiple column, row, or table values in the DataSet without having to worry about updating the database with each individual value changed in the DataSet. You can make sweeping changes in the DataSet and then simply call the Update method of the SQLDataAdapter and let it figure out what has changed and needs to be updated in the database. The second benefit of the SQLDataAdapter comes when it's used in conjunction with the SQLCommandBuilder object. If you create a SQLCommandBuilder based on an existing SQLDataAdapter, the SQLCommandBuilder will create the necessary SQLCommand objects and SQL statements needed to update the database. This results in far less code for you to write and maintain.

The downside to using a SQLDataAdapter in the cached DataSet scenario is that you must either cache the SQLDataAdapter objects in the Application object or recreate them each time you update data. Both options affect performance by using additional memory or by adding steps to the data update process. Choosing whether and where to store SQLDataAdapter objects involves balancing the amount of memory and number of applications the Web server holds.

Now that the DataSet and database are both updated with the new maximum transaction limit, a synchronization error has been introduced into my system. Since each Web server stores its own copy of the DataSet object, the data cached on the second Web server now stores a different maximum transaction limit for the company than that which is stored on the first server. Since the company has increased its transaction limit, it's possible that the second Web server will reject transactions that would be allowed on the first Web server.

The key to fixing these newfound synchronization problems lies in the definition of the Web Services themselves. Since Web Services are designed to make interaction between computers easy and seamless, I simply need to have the Web server with the correct data contact the Web server with the outdated DataSet and tell it to update itself. I do this by exposing several new Web methods on each Web Service.

When any code within my XML Web Services application updates information that is stored in the cached DataSet object, the Web Service must then call the appropriate Web method on the second Web server to indicate that the data has been updated. The main reason to use a Web method call instead of directly referencing and instantiating the second Web Service's DataSet object is flexibility. Typical Web farms consist of several Web servers housed in a central location that all have access to a single network. This is not the only scenario, however. If your Web farm consists of servers residing in multiple locations on multiple networks, direct component references may be more difficult or even impossible. Using Web Service calls also allows you to update cached data across multiple applications. Imagine an internal reporting application that displays summary reports to executives. This application would cache its own data, but could be automatically updated by the AuthorizeCC Web Service as necessary. This update can happen equally well across a server room or across the globe.

Another reason for using a Web method call to refresh data is consistency. In this scenario, I will write just one set of code that makes two Web method calls—that is, one for each server. I will then deploy that single code base to both Web servers. Since the code for calling internal methods is different from the code needed to call externally referenced methods, using a single codebase to make a Web Service call to both the local and external components keeps my code much more manageable.

Creating the Refresh Web Methods

Three methods need to be created on my Web Service to handle three common data updating situations: RefreshData, RefreshTable, and RefreshRow. The specific Web method that will be called depends upon the type of update being done, but each call indicates to the receiving server that it needs to update some portion of its cached data. Code for all three functions is shown in Figure 5.

  Figure 5 Three Refresh Web Methods

Copy Code

<WebMethod(Description:="Refreshes all cached data on this web server. If Propagate is 'True,' then requests will be sent to all other registered web servers to refresh their own cached data.", MessageName:="RefreshData")>
Public Function RefreshCachedData(ByVal _Propagate As Boolean) As Boolean
'Refreshes Cached Data on this and other servers
GetCachedData()If Propagate = True Then RefreshDataOnOtherServers("AuthorizeCC.asmx/ _RefreshSpecificTable?TableName=" _& TableName & "&Propagate=False")
End Function
'——————————————————————————————————
<WebMethod(Description:="Refreshes cached data in the specified table on this web server. If Propagate is 'True,' then requests will be sent to all other registered web servers to refresh their own cached data.", MessageName:="RefreshTable")>
Public Function RefreshCachedData(ByVal TableName As String, ByVal _
Propagate As Boolean) As Boolean
'Refreshes Cached Data on this and other servers, for the specified tableDim conn As New System.Data.SqlClient.SqlConnection()     'Connection to 'database
Dim ds As New DataSet()conn.ConnectionString = "server=localhost;database=MSDN1;uid=sa;pwd="
conn.Open()
FillTable("SELECT * FROM " & TableName, TableName, ds, conn)If Propagate = True Then RefreshDataOnOtherServers("AuthorizeCC.asmx/ _ RefreshSpecificTable?TableName=" _& TableName & "&Propagate=False")
End Function
'——————————————————————————————————
<WebMethod(Description:="Refreshes cached data in the specified row on this web server. If Propagate is 'True,' then requests will be sent to all other registered web servers to refresh their own cached data.", MessageName:="RefreshRow")>
Public Function RefreshCachedData(ByVal TableName As String, ByVal ID _
As Integer, ByVal Propagate As Boolean) As Boolean'Refreshes Cached Data on this and other servers, for the 'specified tableDim conn As New SqlConnection()     'Connection to database
Dim cmd As New SqlCommand()
Dim rdr As SqlDataReader
Dim ds As New DataSet()
Dim dr As DataRow
Dim dc As DataColumnconn.ConnectionString = "server=localhost;database=MSDN1;uid=sa;pwd="
conn.Open()
cmd.CommandText = "SELECT * FROM " & TableName
cmd.Connection = conn
rdr = cmd.ExecuteReader(CommandBehavior.SingleRow)dr = CType(Application.Item("CachedData"), _DataSet).Tables("TableName").Rows.Find("ID")
For Each dc In dr.Table.Columns'Store the new value in the cached DataSetdr.Item(dc.ColumnName) = rdr.Item(dc.ColumnName)
NextIf Propagate = True Then RefreshDataOnOtherServers("AuthorizeCC.asmx/ _RefreshSpecificTable?TableName=" _& TableName & "&Propagate=False")
End Function

The RefreshData method simply executes the GetCachedData function that I defined earlier. This creates a new DataSet object, fills it with fresh data from the database, and then stores it in the Application object. This meets my goal of re-synchronizing the two DataSet objects stored in each Web server's Application object, assuming the database has been previously updated. However, this is typically overkill since in most cases the code will not have changed data in every table in the DataSet.

The RefreshTable method takes a single String parameter called TableName. The TableName parameter must match one of the DataTable objects stored in the cached DataSet and indicates that only the specified table needs to be refreshed. The method then retrieves the data only for the specified table and replaces the DataTable object within the DataSet. Note that in this example there are only two possible values for the TableName parameter, so the application can easily branch to the appropriate code. There is some code duplication here because the code used to refresh a specific DataTable duplicates the code in the GetCachedData routine. In a situation where the cached DataSet contains many DataTable objects, it would be more efficient to have both the GetCachedData and RefreshTable routines call a general routine that accepts a TableName parameter.

The final method, RefreshRow, is designed to refresh cached data at an even more granular level. The method will identify a specific DataRow object within a DataTable object within the DataSet that should be refreshed. It will then pull from the database only the data necessary to refresh that single row. The parameters for this method are not as easily defined as for the two previous methods since database tables can have multiple keys of varying types. In this example, I am working on the assumption that any table that will need to be refreshed will have only a single key of type long. The method can then find the record with the specified KeyValue in the specified TableName and update the DataSet. This would work equally well for inserting and deleting rows. I could overload this Web method to take additional parameter sets to accommodate composite keys or keys of another type, but since this is a Web method, I would have to create a unique MessageName for each Web method. This would force my code to call methods with names like RefreshRowWithTwoLongKeys and RefreshRowWithOneGUIDKey. This quickly becomes too cumbersome to manage.

These three methods are specifically designed to be general to allow reuse in a variety of applications. It is possible, however, to eke out even better performance by creating very specific Web methods. In a situation where you know that certain data, such as maximum transaction limit, is going to be updated frequently, you could create a Web method to do just this. An UpdateMaxTransactionLimit would take a KeyValue parameter to identify the company and a NewTransactionLimit parameter that specifies the new value. This would eliminate the process of pulling data from the database on the second Web server, thus improving performance.

A final concern for my three Refresh Web methods is security. Since no data is being returned from the Refresh Web Services, it is unlikely that a user could gain unauthorized access to your data through the methods I have developed. However, depending on the amount of cached data and the speed of the database it is being stored in, refreshing it can be a lengthy process. This fact could be maliciously exploited by repeatedly calling the lengthy RefreshData Web method, bringing your Web server to its knees.

Calling the Refresh Methods

Now that I have created the three Refresh Web methods, I need to develop a way to call the appropriate method after I have updated the database. The appeal of Web Services is that they make use of industry standard protocols such as HTTP and SOAP, enabling them to work with any language that uses the same protocols. I could easily write the code to call the Refresh methods in Visual Basic 6.0, VBScript, or even Java, but since I am using Visual Basic .NET to write my own XML Web Service, I will also use it to call the new Web methods.

Web method calls can be made using one of three different HTTP techniques: GET, POST, or SOAP. HTTP-GET and HTTP-POST will be familiar to Web developers as the two methods HTML forms can use. HTTP-GET appends all parameters to the end of the URL while POST sends them in the HTTP header. SOAP is similar to HTTP-POST in that the parameters are sent in the header, but instead of individual parameters being passed, all parameters are bundled into a single SOAP payload.

I have chosen to use HTTP-GET and append my parameter name-value pairs to the end of my URL. In Figure 6 you can see the simple code that's required to make an HTTP Request call the RefreshTable method.

  Figure 6 Calling Refresh XML Web Services

Copy Code

Dim ieWebServers As IEnumerator
Dim sURL As New StringBuilder()
Dim wReqRouter As WebRequest
Dim wrespRouter As WebResponseTryieWebServers = CType(Application.Item("CachedData"), _DataSet).Tables("ServerName").Rows.GetEnumerator()
While ieWebServers.MoveNext()
If ieWebServers.Current("ServerName") <> Me.Server.MachineName Then'Clear out the URL for the next use sURL.Length = 0With sURL.Append("http://").Append(ieWebServers.Current("IP")).Append("/AuthorizeCC/AuthorizeCC.asmx/RefreshCachedData")End WithwReqRouter = WebRequest.Create(sURL.ToString())' Get the response from the WebRequest TrywrespRouter = wReqRouter.GetResponse()Catch ex As Exception'Handle exception hereEnd Try' Code to use the WebResponse goes here.Dim xmlRdr As New XmlTextReader(wrespRouter.GetResponseStream())While xmlRdr.Read()If xmlRdr.Name = "boolean" ThenIf xmlRdr.ReadAttributeValue() = True Then'Error value returned true!End IfEnd IfEnd While' Close the response to free resources.wrespRouter.Close()
End If
End While
Catch ex As Exception
'Handle exception here
End Try

The base URL for the Web method call is the standard http:// identifier followed by the standard address (in this case, Server1). To this, I have appended the name of my Web Service, AuthorizeCC.asmx. HTTP-GET uses a question mark to discriminate between the address and the parameter list, followed by name-value pairs separated by ampersands (&). The code in Figure 6 calls the RefreshTable method which requires only one parameter, so I append "?TableName=Customer". The URL is now complete and ready to call the appropriate Web method.

I execute the Web method by creating a WebRequest object using the URL I built as a constructor parameter. The WebRequest object is now ready to execute the Web method. I create a WebResponse object to receive the response returned by the WebRequest. The GetResponse method of the WebRequest object makes the actual call to my Web method and receives the response in its return value. Setting the WebResponse object to the return value of the GetResponse call allows me to look at the data returned from the Web method call.

Since the Web Service returns XML, I will instantiate an XMLTextReader to deal with the Web method's response. Since I know that the Web method returns a simple Boolean value, I will iterate through the elements in the XMLTextReader until I find an element with the name "boolean". I can then use the ReadAttributeValue method of the XMLTextReader to determine the success or failure of the Web method call. Note that this is a simplistic method for dealing with a simplistic response. More complex Web method return values will require more complex handling code.

I then update my URL to reflect the name of the second Web server, Server2, and make the Web request again. Since I have already updated the cached data on the local machine, I will add a simple If...Then construct that checks the name of the local Web server and does not call the Web method if the name of the server to be called matches the name of the calling server. Thus, Server1 will only refresh the cached data on Server2, and vice versa.

There is an improvement that can be made to this code in order to account for a design limitation of HTTP which limits URL length to 1,024 characters. For the AuthorizeCC Web Service this is plenty of space, but for Web Services that require many parameters or lengthy values you will probably have to use HTTP-POST or SOAP to avoid this limitation.

Adding New Servers

As I noted before, the AuthorizeCC Web Service is rapidly adding new customers. The existing Web farm with its two Web servers is performing well with each server using its own cached data and notifying the other server when updates are required. However, at peak usage times, the number of simultaneous hits is exceeding available capacity and Web Service consumers are noticing delays. It is time to add additional servers to the Web farm.

The load balancing software is designed to automatically handle as many Web servers as you grow in your Web farm, but unfortunately, the AuthorizeCC Web Service is not. The current Web Service is hardcoded to only update cached data on the two known servers, Server1 and Server2. When I add Server3, the code has no way of knowing that it should call the appropriate Refresh method on Server3 as well.

In order to overcome this, I will add a simple table named ServerName to my database that holds the names of all the servers in the Web farm. You may have noticed that the code in Figure 2 is already written to pull this table into the cached DataSet. I can alter my Web Service to pull a list of Web server names from the database. My code will then iterate through the database rows, using each server name to build a URL to call the appropriate Web method. As before, the code will skip the Web method call if the calling and receiving server names are the same. The code in Figure 6 includes all of these changes.

This improves my situation, for it is now easy for an administrator to add the name of a new Web server to the database and have it instantly included in the farm of servers using cached, refreshable data. What happens if the administrator forgets to enter a server name in the database or enters an incorrect name? In order to fix this potential problem, I will add a small bit of code to my Web Service that will add servers to the database automatically. The code in Figure 7 is added to the GetCachedData subroutine defined earlier. It checks the ServerName DataTable in the cached DataSet for the name of the Web server in question. If the server's name is not found, then a new entry is added to the database and the ServerName DataTable is refilled.

  Figure 7 Automatic Registration for New Servers

Copy Code

Public Sub GetCachedData()•••
Dim drTemp As DataRow
'Look for own address in Web_Service_IP if not found, add it
drTemp = ds.Tables("ServerName").Rows.Find(Me.Server.MachineName)
If drTemp Is Nothing Then
'Add our machine name to the database
Dim SQL As String
SQL = "INSERT INTO ServerName (ServerName) VALUES (" & _
Me.Server.MachineName & ")"'Setup the command object
Dim cmd As New System.Data.SqlClient.SqlCommand(SQL)
cmd.Connection = conn
cmd.ExecuteNonQuery()'Fill the ServerName table again
ds.Tables("ServerName").Clear()
FillTable("SELECT ServerName FROM ServerName", "ServerName", ds, conn)'Refresh other servers with new server name
RefreshCachedData("ServerName")
End If•••

Since each Web server now automatically registers itself so that it will be included in all calls to refresh cached data, I can now add new servers to my farm at any time without having to create a database record or recompile my code.

Conclusion

In this article I have demonstrated techniques for improving performance by using cached DataSets to reduce the number of round-trips made to the database. I have also shown how Web Services can communicate among themselves to force a refresh of the cached data, ensuring that all Web servers maintain current data in their cache.

These techniques can be easily expanded using additional enhancements tailored for your particular situation. For instance, you may want to consider moving the code that makes Web method calls to its own Manager Web Service. Each of your production Web Services would call the Manager Web Service, which would in turn call the appropriate Refresh methods on each Web server. This would reduce the amount of administrative functionality in your production Web Services, thereby improving performance.

Using the Microsoft® .NET Framework and these techniques, it is easy to build high performance XML Web Services that still offer the redundancy benefits of a Web farm.

转载于:https://www.cnblogs.com/philzhou/archive/2011/03/01/1968210.html

Use Data Caching Techniques to Boost Performance and Ensure Synchronization(转)相关推荐

  1. Big Data Caching for Networking: Moving from Cloud to Edge 论文分享

    Big Data Caching for Networking: Moving from Cloud to Edge Abstract 问题背景: 为应对5G无线网络下的流量爆炸问题,目前解决方法包括 ...

  2. Data Augmentation techniques in time series domain: A survey and taxonomy

    本文是对<Data Augmentation techniques in time series domain: A survey and taxonomy>的翻译. 时间序列域的数据增强 ...

  3. 2021-07-19 专著-Data Mining Techniques for the Life Sciences(1)

    目录 专著 Data Mining Techniques for the Life Sciences 2009年第一版 2016版第二版 阅读笔记 1.1 核酸序列数据库 1.2 NCBI的基因组数据 ...

  4. Integrating Caching Techniques in CDNs using a Classification Approach

    1.Pallis和Stomas的又一篇,发表在一个期刊上,没被人引用. 2.相比前一篇的那个 A similarity based approach for integrated web cachin ...

  5. 【论文翻译】Learning from Few Samples: A Survey 小样本学习综述

    论文链接:https://arxiv.org/abs/2007.15484 摘要 Deep neural networks have been able to outperform humans in ...

  6. Github:NLP相关代码、书目、论文、博文、算法、项目资源(附链接)

    来源:AINLP 本文多资源,建议阅读6分钟. 本文为你推荐Github上一个NLP相关的项目:msgi/nlp-journey. 推荐Github上一个NLP相关的项目: msgi/nlp-jour ...

  7. 集合啦,NLP数据增强技术!超全资源汇总

    点击上方"AI遇见机器学习",选择"星标"公众号 重磅干货,第一时间送达 白交 发自 凹非寺  量子位 报道 | 公众号 QbitAI 数据增强技术已经是CV领 ...

  8. gan 总结 数据增强_[NLP]聊一聊,预处理和数据增强技术

    在基于margin-loss的句子相似度这个项目中,为了验证想法,找不到开放数据集,因此自己从新浪爱问爬取了数据.自己爬的数据和学界开放的数据对比,数据显得非常脏.这里有三个含义:第一:数据不规范,比 ...

  9. 数据增强_NLP 数据增强方法 EDA

    当数据集比较少的时候,往往会导致模型陷入过拟合.数据增强是一种比较有效的扩充数据集的方法,在计算机视觉领域有比较重要的作用.但是在 NLP 领域数据增强的方法相对少一些,本文介绍一种比较传统的 NLP ...

最新文章

  1. [bzoj4562][Haoi2016]食物链_记忆化搜索_动态规划
  2. Block介绍(二)内存管理与其他特性
  3. element表格取消全选_ElementUi 表格取消全选框,用文字表示
  4. Linux系统监控工具
  5. android解析XML总结(SAX、Pull、Dom三种方式)
  6. linux(虚拟机中)与windows共享文件两种方法
  7. fiddler抓包工具配置详解
  8. Bootstrap 打印机类
  9. 使用rpm安装mysql_如何使用rpm安装MySQL
  10. java getSource()和 getActionCommand()区别
  11. 【2021考研数学汤家凤高数辅导讲义】第四章 不定积分
  12. win10命令提示符cd 不到指定路径的解决
  13. 异常与调试之SEH、UEH、VEH、VCH以及SEH原理
  14. 目标检测中常见指标 AP MAP coco Pascal voc 评价指标说明
  15. 我这些年对游戏外挂辅助开发的一些心得和体会
  16. Java控制手机在同一网下_安卓手机控制另一手机的方法【详解】
  17. EV录制文件损坏-修复方法
  18. jq左右按钮控制内容左右移动
  19. 河南联通网通封杀路由器解决办法
  20. MySQL的隐式类型转换

热门文章

  1. python中什么具有去重功能_python中去重的方法
  2. Nacos教程_3 整合SpringCloud(配置中心+服务发现)
  3. lenovo电脑_办公笔记本电脑有哪些值得推荐?
  4. 【汇编语言】子程序结构
  5. QT_在循环中刷新界面
  6. 【七】zuul路由网关
  7. 关于jquery中html()、text()、val()的区别
  8. scala 冒泡排序
  9. Python学习小结---函数
  10. Handsontable 类似 excel 表格编辑器