Proactive C # principle 34: creating large-capacity Web APIs)

Source: Internet
Author: User

Proactive C # principle 34: creating large-capacity Web APIs
Item 34: create large-grain Web APIs

The overhead and trouble of interaction protocols are how to use data media. Different media may be used during interaction. For example, you need different phone numbers, faxes, addresses, and email addresses for communication. Let's look back at the last order catalog. When you order by phone, you have to answer a series of questions from the SALESPERSON:

"Can you fill in the first item ?"

"This item number is 123-456"

"How much do you want to order? "

"Three"

For example, you must know your order address, credit card information, and shipping address, and other necessary information to complete this transaction. It is encouraging to finish this discussion over the phone. Because you will not be talking to yourself for a long time, and you will not endure the quietness of sales staff for a long time.

You must fill in the entire order document and then send the entire document to the company. One-time transmission of a file is completed. You do not need to fill in the product number, send a fax, enter the address, fax, enter the credit card number, and then send a fax.

The following describes common defects that may occur when a poorly defined web method interface is used. When using web services or. NET remote interaction, you must remember that the most expensive overhead is when objects are transmitted between two remote machines. You should not just re-encapsulate the interface used on the local computer to create a Remote API. Although this can work, the efficiency is very low.
This is a bit like a telephone call to complete the task of ordering by fax. Your applicationProgramMost of the time, after sending a piece of data to the channel, wait for the network. The more small pieces of API are used, the application waits for the server data to return a longer time than the application.

On the contrary, when creating a web-based interface, we should serialize a series of objects on the server and client, and then transmit them based on the serialized document. Your remote communication should be the same as the form used when you order by Fax: the client should have an extended running period that does not communicate with the server. At this time, when the information used has been filled in, the user can submit this document to the server at one time. The same thing is done on the server: when the information returned to the customer on the server arrives, the customer obtains all the information required to complete the ordering task on hand.

In comparison, we need to paste a customer order. We need to design a customer's order processing system, which must be consistent with the network access information of the central server and desktop users. A class in the system is the customer class. If you ignore the transmission problem, the customer class may be designed like this, which allows the user to retrieve or modify the name, shipping address, and account information:

Public Class Customer
{
Public customer ()
{
}

// Properties to access and modify customer fields:
Public string name
{
// Get and Set details elided.
}

Public Address shippingaddr
{
// Get and Set details elided.
}

Public Account creditcardinfo
{
// Get and Set details elided.
}
}

This customer class does not include remotely called APIs. Calling a remote user between the server and the customer will cause serious traffic congestion:

// Create customer on the server.
Customer c = new server. Customer ();
// Round trip to set the name.
C. Name = DLG. Name. text;
// Round trip to set the ADDR.
C. shippingaddr = DLG. ADDR;
// Round trip to set the CC card.
C. creditcardinfo = DLG. credit;

Instead, you should create a complete customer object on the local machine, and then deliver the customer object to the server after the user fills in all the information:

// Create customer on the client.
Customer c = new customer ();
// Set local copy
C. Name = DLG. Name. text;
// Set the local ADDR.
C. shippingaddr = DLG. ADDR;
// Set the local CC card.
C. creditcardinfo = DLG. credit;
// Send the finished object to the server. (One trip)
Server. addcustomer (C );

This customer's example clearly and simply demonstrates this problem: the entire object is transmitted one by one between the server and the client. But to write efficientCodeYou should extend this simple example to include the correct collection of related objects. In a remote request, a single attribute of an object is a small particle ). However, for each transmission between the server and the customer, a customer instance may not be a particle of the correct size.

Let's extend this example to bring it closer to some problems encountered in actual design. Let's make some assumptions about the system. This software mainly supports an online seller with 1 million customers. Assume that each user has a main directory for house ordering. On average, there were 15 orders last year.
Each telephone operator uses one machine for shift operations and, regardless of whether the phone orderer answers the call, they need to find or create this order record. Your design task is to determine a collection of efficient objects transmitted between the client and the server.

In the beginning, you may eliminate some obvious options. For example, retrieving the information of each customer and each order should be clearly prohibited: 1 million customers and 15 million (1 million 5 million) the order record is obviously too big to go back to a customer. This makes it easy for another user to encounter bottlenecks. Each time data may be updated, it will blow up the server. You need to send a request containing 15 million objects. Of course, this is only a transaction, but it is too inefficient.

Instead, consider how you can best retrieve an object set. You can create a good data set proxy to process objects that will be used in a few minutes. An operator replies to a call and may be interested in a customer. During a telephone conversation, the operator may add or remove orders, modify orders, or modify the account information of a customer. The obvious choice is to retrieve a customer and all orders of the user. The method on the server may be as follows:

Public orderdata findorders (string customername)
{
// Search for the customer by name.
// Find all orders by that customer.
}

Right? Orders sent to the customer and received by the customer may not be required on the client. A better way is to retrieve only one order for each requested user. The server method may be changed to the following:

Public orderdata findopenorders (string customername)
{
// Search for the customer by name.
// Find all orders by that customer.
// Filter out those that have already
// Been received.
}

In this way, you still need to ask the client to create a new request for each phone order. Is there a way to optimize communication? It is better than downloading all orders included by users. We will add some new assumptions in business processing to give you some methods. Assume that the call center is distributed so that each Working Group receives different phone numbers. Now you can modify your design to optimize the interaction.

The operator in each region may retrieve and update the customer and order information at the first shift. After each call, the customer application should return the modified data to the service, and the server should respond to all modifications made after the last customer request data. The result is that after each call, the operator sends all the modifications, including all the modifications made by other operators in the group. This design means that each call has only one session, and each operator should have data set access each time he replies to the call. In this way, there may be two methods on the server:

Public customerset retrievecustomerdata (
Areacode theareacode)
{
// Find all customers for a given area code.
// Foreach customer in that area code:
// Find all orders by that customer.
// Filter out those that have already
// Been received.
// Return the result.
}

Public customerset updatecustomer (customerdata
Updates, datatime lastupdate, areacode theareacode)
{
// First, save any updates, marking each update
// With the current time.

// Next, get the updates:
// Find all customers for a given area code.
// Foreach customer in that area code:
// Find all orders by that customer that have been
// Updated since the last time. Add those to the result.
// Return the result.
}

However, this may waste some bandwidth. The last design is the most effective when every known customer calls every day. But this is probably not true. If yes, your company should have a major problem in customer service, which cannot be solved by software.

How can we further limit the transmission size without increasing the number of sessions and the server response latency? You can make assumptions about the customers preparing to make phone calls in the database. You can track some statistical tables and find that if some customers have no orders for six months, they will probably not have orders again. At this point, you should stop retrieving these customers and their orders from that day. This can contract the initial transfer size. You can also find that many customers often call to ask about the last order after placing an order through a short phone call. Therefore, you can modify the order list and transmit only the last orders instead of all orders. This may not need to modify the method signature on the server, but it will contract the size of the package transmitted to the customer.

The focus of these assumptions is to give you the idea of remote interaction: you reduce the session frequency between two machines and the packet size during the session. These two goals are contradictory. You need to make a balanced choice between them. You should take two extreme vertices, instead of making the wrong choice too large or too small session.
======================================

Item 34: create large-grain Web APIs
The cost and inconvenience of a communication protocol dictates how you should use the medium. you communicate differently using the phone, fax, letters, and email. think back on the last time you ordered from a catalog. when you order by phone, you engage in a question-and-answer session with the sales staff:

"Can I have your first item? "

"Item number 123-456 ."

"How many wowould you like? "

"Three ."

This conversation continues until the sales staff has your entire order, your billing address, your credit-card information, your shipping address, and any other information necessary to complete the transaction. it's comforting on the phone to have this back-and-forth discussion. you never give long soliloquies with no feedback. you never endure long periods of silence wondering if the salesperson is still there.

Contrast that with ordering by fax. you fill out the entire document and fax the completed document to the company. one document, one transaction. you do not fill out one product line, fax it, add your address, fax again, add your credit number, and fax again.

this variable strates the common pitfalls of a poorly defined web method interface. whether you use a web service or. net remoting, you must remember that the most expensive part of the operation comes when you transfer objects between distant machines. you must stop creating remote APIs that are simply a repackaging of the same local interfaces that you use. it works, but it reeks of inefficiency. it's using the phone call metaphor to process your catalog request via fax. your application waits for the network each time you make a round trip to pass a new piece of information through the pipe. the more granular the API is, the higher percentage of time your application waiting ds waiting for data to return from the server.

instead, create web-based interfaces based on serializing events or sets of objects between client and server. your remote communications shocould work like the order form you fax to the catalog company: the client machine shocould be capable of working for extended periods of time without contacting the server. then, when all the information to complete the transaction is filled in, the client can send the entire document to the server. the server's responses work the same way: When information gets sent from the server to the client, the client has es all the information necessary to complete all the tasks at hand.

Sticking with the customer order metaphor, We'll design a customer order-processing system that consists of a central server and desktop clients accessing information via web services. one class in the system is the customer class. if you ignore the transport issues, the customer class might look something like this, which allows client code to retrieve or modify the name, shipping address, and account information:

Public Class Customer
{
Public customer ()
{
}

// Properties to access and modify customer fields:
Public string name
{
// Get and Set details elided.
}

Public Address shippingaddr
{
// Get and Set details elided.
}

Public Account creditcardinfo
{
// Get and Set details elided.
}
}

 

The customer class does not contain the kind of API that shocould be called remotely. Calling a remote customer results in excessive traffic between the client and the server:

// Create customer on the server.
Customer c = new server. Customer ();
// Round trip to set the name.
C. Name = DLG. Name. text;
// Round trip to set the ADDR.
C. shippingaddr = DLG. ADDR;
// Round trip to set the CC card.
C. creditcardinfo = DLG. credit;

 

Instead, you wocould create a local customer object and transfer the customer to the server after all the fields have been set:

// Create customer on the client.
Customer c = new customer ();
// Set local copy
C. Name = DLG. Name. text;
// Set the local ADDR.
C. shippingaddr = DLG. ADDR;
// Set the local CC card.
C. creditcardinfo = DLG. credit;
// Send the finished object to the server. (One trip)
Server. addcustomer (C );

 

The customer example between strates an obvious and simple example: Transfer entire objects back and forth between client and server. but to write efficient programs, you need to extend that simple example to include the right set of related objects. making remote invocations to set a single property of an object is too small of a granularity. but one customer might not be the right granularity for transactions between the client and server, either.

to extend this example into the real-world design issues you'll encounter in your programs, we'll make a few assumptions about of the system. this software system supports a major online vendor with more than 1 million MERs. imagine that it is a major catalog ordering house and that each customer has, on average, 15 orders in the last year. each telephone operator uses one machine during the shift and must lookup or create customer records whenever he or she answers the phone. your design task is to determine the most efficient set of objects to transfer between client machines and the server.

you can begin by eliminating some obvious choices. retrieving every customer and every order is clearly prohibitive: 1 million MERs and 15 million order records are just too much data to bring to each client. you 've simply traded one bottleneck for another. instead of constantly bombarding your server with every possible data update, you send the server a request for more than 15 million objects. sure, it's only one transaction, but it's a very inefficient transaction.

Instead, consider how you can best retrieve a set of objects that can constitute a good approximation of the set of data that an operator must use for the next several minutes. an operator will answer the phone and be interacting with one customer. during the course of the phone call, that operator might add or remove orders, change orders, or modify a customer's account information. the obvious choice is to retrieve one customer, with all orders that have been placed by that customer. the server method wocould be something like this:

Public orderdata findorders (string customername)
{
// Search for the customer by name.
// Find all orders by that customer.
}

 

Or is that right? Orders that have been shipped and stored ed by the customer are almost certainly not needed at the client machine. A better answer is to retrieve only the open orders for the requested customer. the server method wocould change to something like this:

Public orderdata findopenorders (string customername)
{
// Search for the customer by name.
// Find all orders by that customer.
// Filter out those that have already
// Been received.
}

 

you are still making the client machine create a new request for each customer phone call. Are there ways to optimize this communication channel more than including orders in the customer download? We'll add a few more assumptions on the business processes to give you some more ideas. suppose that the call center is partitioned so that each working team has es cballs from only one area code. now you can modify your design to optimize the communication quite a bit more.

each operator wowould retrieve the updated customer and order information for that one area code at the start of the shift. after each call, the client application wocould push the modified data back to the server, and the server wocould respond with all changes since the last time this client machine asked for data. the end result is that after every phone call, the operator sends any changes made and retrieves all changes made by any other operator in the same work group. this design means that there is one transaction per phone call, and each operator shoshould always have the right set of data available when he or she answers a call. now the server contains two methods that wowould look something like this:

Public customerset retrievecustomerdata (
Areacode theareacode)
{
// Find all customers for a given area code.
// Foreach customer in that area code:
// Find all orders by that customer.
// Filter out those that have already
// Been received.
// Return the result.
}

Public customerset updatecustomer (customerdata
Updates, datatime lastupdate, areacode theareacode)
{
// First, save any updates, marking each update
// With the current time.

// Next, get the updates:
// Find all customers for a given area code.
// Foreach customer in that area code:
// Find all orders by that customer that have been
// Updated since the last time. Add those to the result.
// Return the result.
}

 

but you might still be wasting some bandwidth. your last design works best when every known customer CILS every day. that's probably not true. if it is, your company has customer service problems that are far outside of the scope of a software program.

How can we further limit the size of each transaction without increasing the number of transactions or the latency of the service rep's responsiveness to a customer? You can make some assumptions about which MERs in the database are going to place CILS. you track some statistics and find that if customers go six months without ordering, they are very unlikely to order again. so you stop retrieving those mers MERs and their orders at the beginning of the day. that shrinks the size of the initial transaction. you also find that any customer who callshortly after placing an order is usually inquiring about the last order. so you modify the list of orders sent down to the client to include only the last order rather than all orders. this wocould not change the signatures of the server methods, but it wocould shrink the size of the packets sent back to the client.

this hypothetical discussion focused on getting you to think about the communication between remote machines: You want to minimize both the frequency and the size of the transactions sent between machines. those two goals are at odds, and you need to make trade-offs between them. you shoshould end up close to the center of the two extremes, but err toward the side of fewer, larger transactions.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.