<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                # 原則28:創建大粒度的網絡服務 APIs **By D.S.Qiu** **尊重他人的勞動,支持原創,轉載請注明出處:[http://dsqiu.iteye.com](http://dsqiu.iteye.com)** 通信協議的花費和不便決定了你將會怎么使用這些媒介。使用電話,傳真,信件和電子郵件交流是不同的。回想上次你從商品目錄中下單。當你用電話下單,你和售貨員進行問-答的交互: “我能知道你第一選項么?” “我選的序號是123-456。” “你需要多少份?” “3。” 這段交流直到售貨員知道整個訂單,你的賬單地址,你的信用卡信息,你的送貨地址,和其他完成交易的信息才終止。在電話上來回討論是非常方便的。你不會一直自言自語而沒有反饋。你不能忍受長時間的沉默如果銷售人員仍然還在。 用傳真訂單會不一樣。你會填滿整個文檔然后在把整個文檔傳真給公司。一個文檔,一次交易。你不會填一欄,傳真一次,填寫地址,又傳真一次,添加信用卡新,又傳真一次。 這說明了缺乏定義的服務接口常見的誤區。不管你使用 web 服務,.NET 遠程,或基于 Azure 編程,你必須記住在兩臺機器傳遞對象的操作的昂貴的花費。你必須停止創建的遠程 API 只是對本地接口的一個封裝。這就像是用打電話處理本要用傳真處理的訂單。你的程序每次都要等待在網絡管道傳遞信息往返的時間。更大粒度的 API ,程序的更高比例時間花在等待數據從服務器返回。 相反,在客戶端和服務器之間創建基于 web 的接口要基于一系列文檔和對象集。你的遠程交流應該向像用傳真向商品公司下訂單一樣工作:客服端機器應該能在沒有和服務器交流的時間工作。然后,等所有交易信息填寫完畢,客服端發送整個文檔給服務器。服務器用同樣的方式工作:從服務器發送信息到客服端,客服端接受所有必要信息并接著完成所有任務。 接著消費者下單的比喻。我們設計客戶下單處理系統,它由中心服務器和桌面客服端,彼此通過 web 服務訪問信息。系統中的一個類就是 Customer 類。如果你忽略了運輸問題,客戶類可能是這樣子的,它允許客戶端代碼檢索或修改的名稱,送貨地址,和帳戶信息: ``` public class Customer { public Customer() { } // Properties to access and modify customer fields: public string Name { get; set; } public Address ShippingAddr { get; set; } public Account CreditCardInfo { get; set; } } ``` Customer 類沒有包含會被遠程調用的 API 。調用遠程的 Customer 會導致在客服端和服務器之間過度的交流: ``` // create customer on the server. Customer c = Server.NewCustomer(); // round trip to set the name. c.Name = dlg.Name; // round trip to set the addr. c.ShippingAddr = dlg.ShippingAddr; // round trip to set the cc card. c.CreditCardInfo = dlg.CreditCardInfo; ``` 取而代之,我們會創建一個局部 Customer 對象,并且當這個對象所有域都設置好之后傳遞給服務器: ``` // create customer on the client. Customer c2 = new Customer(); // Set local copy c2.Name = dlg.Name; // set the local addr. c2.ShippingAddr = dlg.ShippingAddr; // set the local cc card. c2.CreditCardInfo = dlg.CreditCardInfo; // send the finished object to the server. (one trip) Server.AddCustomer(c2); ``` 這個客戶的例子說明一個明顯又簡單的例子:在客服端和服務器之間來回傳遞整個對象。但是為了編寫高效的程序,你需要擴展這個簡單例子以囊括相關的對象集。遠程調用一個對象的單個屬性粒度太小了。但是一個客戶也可能不是在服務器和客服端交易合適的粒度。 擴展這個例子到實際的設計問題是你會在程序中遇到的,我們對系統進行些假設。這個軟件系統支持主要在線廠商和一百萬客戶的交易。想象下大多數客戶都在家里下單,去年平均15單。每個電話操作員每次都要同一臺機器上下切換記錄客戶回答的信息。你的設計任務是決定更多高效對象集在客服端機器和服務器之間傳遞。 你開始就可以消除一些明顯的選擇。檢索每個客戶和每個訂單是很明確被禁止的:一百萬的客戶和一千五百萬的訂單記錄數據大到不可能傳遞給每個客戶端。你需要為一個瓶頸去權衡其他。為了不每個可能的數據更新不斷轟擊你的服務器,你向服務器發送一個超過一千五百萬的對象請求。當然,這只是一個交易,但這是一個非常低效的交易。 相反,考慮如何最好的檢索一組對象集,操作者接下來的幾分鐘必須使用一個近似的對象的數據集。操作者會接電話并和客戶交流。在通話過程中,操作者可能添加和移除訂單,改變訂單,或者修改客戶的賬戶信息。顯而易見的選擇是一次檢索整個客戶的所有訂單。服務器的方法是下面這樣的: ``` public OrderDataCollection FindOrders(string customerName) { // Search for the customer by name. // Find all orders by that customer. } ``` 這樣就正確了?那些已經發貨或已經被簽收的訂單大多數情況下客戶端幾乎不需要。一個請求客戶更好的檢索只是開放的訂單。服務器的方法會改成這樣: ``` 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. } ``` 你仍然在每個客戶電話的開始就請求數據。有沒有方法優化下載客戶端訂單信息的通信。我們繼續添加一些業務流程的假設,你會得到一些想法。假設呼叫中心劃分使每個工作團隊只會接到一個區域代碼。現在你可以修改你的設計優化傳播得更多。 每個操作者會在開始切換的區域代碼而檢索被更新的客戶和訂單信息。每次電話后,客戶端會將修改數據推送會服務器,服務器會對后面的客戶端請求推送改變的數據。這樣的結果是每次電話后,操作者會發送修改的數據給服務器并從服務器獲得同組的其他操作者修改的數據。這個設計意味著每個電話只能進行一個交易,每個操作者在回答電話時總是獲得正確的數據集。這就每個電話只有一個來回。現在服務器包含下面兩個方法: ``` 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, DateTime lastUpdate, AreaCode theAreaCode) { // First, save any updates. // 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. } ``` 但是你可能還會浪費一些帶寬。當每個已知客戶每個都打電話來下單時,你最后的設計作品效果最好。這是不正確的。如果是,你的公司已經遠遠超出一個軟件項目范圍的客戶服務問題。 在不增加事務請求數量或服務響應客戶的延遲的情況下,我們怎樣才能進一步限制每筆交易的數據的大小?你可以對數據庫中的客戶進一步假設。你跟蹤的一些統計并發現如果客戶六個月不訂購,他們不可能再次訂購。所以從那日期你可以停止這些客戶和他們的訂單。這會縮小初始化交易的大小。你還發現很多客戶在下了單之后在打電話來通常是詢問上一次訂單。所以你修改發送給客戶端的訂單信息只是上一次的而不是所有的訂單列表。者不需要改服務器方法的前面,但是會減少發給客戶端數據包的大小。 這一假設的討論集中在讓你們去思考遠程機器之間的通信:你要最小化機器之間通信的頻率與傳輸的大小。這兩個目標是相違背的,你需要在它們之間做出權衡。你放棄以兩個極端的中心的做法,但是大通信量會有相對更少的負面影響。 小結: 這個原則介紹的如果服務器和客戶端高效的通信,數據量和頻率——其實就是一次數據請求的完整性和網絡帶寬的權衡,這么大的問題,放在一個原則來講,有點華而不實。 歡迎各種不爽,各種噴,寫這個純屬個人愛好,秉持”分享“之德! 有關本書的其他章節翻譯請[點擊查看](/category/297763),轉載請注明出處,尊重原創! 如果您對D.S.Qiu有任何建議或意見可以在文章后面評論,或者發郵件(gd.s.qiu@gmail.com)交流,您的鼓勵和支持是我前進的動力,希望能有更多更好的分享。 轉載請在**文首**注明出處:[http://dsqiu.iteye.com/blog/2086414](/blog/2086414) 更多精彩請關注D.S.Qiu的博客和微博(ID:靜水逐風)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看