2011-09-27 38 views
13

Chúng tôi có một vai trò NET Web lưu trữ trên Windows Azure rằng chỉ phục vụ một API REST của với chỉ một tay vài phương pháp web.Làm cách nào để đạt được API REST hiệu suất cao trên Azure bằng .NET?

API được sử dụng khá tích cực bởi ứng dụng được lưu trữ trên đám mây khác (không phải trình duyệt). Mỗi phương thức là không trạng thái cho phép mở rộng trực tiếp và thường tương tác với Blob hoặc Bảng lưu trữ.

Sau đó, trái với hầu hết các API cổ điển, lượng dữ liệu tải lên API thường là lớn hơn nhiều so với số liệutải từ API. Sau đó, kích thước thông điệp trung bình thường khá lớn (ví dụ: trên 100kB).

Cho đến giờ, chúng tôi là sử dụng WCF trên đầu trang của Biểu mẫu ASP.NET có thông báo POX (Plain Old Xml). Hiệu suất front-end không phải là rất tốt, thủ phạm là:

  • XML là verbose ==> giới hạn băng thông.
  • ASP.NET + WCF + WcfRestContrib làm chậm để phân tích/tuần tự hóa thông báo ==> Giới hạn CPU.

tôi tự hỏi chiến lược tốt nhất để đạt được hiệu suất front-end cao nhất có thể là những gì để giảm số lượng các máy ảo cần thiết để hỗ trợ khối lượng công việc.

chiến lược khả thi mà tôi đang xem xét:

  • Huỷ XML ủng hộ Protobuf.
  • Thêm ngược dòng Nén GZip (nén HTTP cổ điển chỉ áp dụng hạ lưu).
  • Loại bỏ WCF hoàn toàn có lợi cho nguyên HttpHandler s.

Có ai đã đánh giá các giải pháp thay thế khác nhau để đạt được tối đa mỗi máy ảo Azure để sử dụng như vậy không?

Ps: Ngụ ý giới thiệu Lokad Forecasting API nhưng đã cố gắng cụm từ câu hỏi theo cách tổng quát hơn.

+0

Bạn phát hiện ra vấn đề/giải pháp là gì? – Rory

Trả lời

1

Trong POC của bạn, tôi nghĩ bạn có thể xóa Azure khỏi phương trình khi bạn kiểm tra thông qua một số trường hợp.

Nếu đây thực sự là băng thông, nén chắc chắn là một tùy chọn, nhưng có thể có vấn đề nếu dịch vụ web này sẽ được mở cho "công khai" thay vì đơn giản được sử dụng bởi các ứng dụng mà bạn kiểm soát. Điều này đặc biệt đúng trong một môi trường dị sinh.

Một định dạng ít tiết là một tùy chọn, miễn là bạn có phương tiện tốt để thất bại trong giao tiếp REST do định dạng sai. XML làm cho điều này rất dễ dàng. Thiếu kinh nghiệm trong ProtoBuf, nó dường như có một số an toàn trong lĩnh vực này, vì vậy nó có thể là một lựa chọn rất tốt nếu băng thông là vấn đề của bạn và có thể giải quyết được tốc độ phân tích vấn đề. Tôi sẽ POC nó bên ngoài của Azure đầu tiên và sau đó đặt nó vào.

Tôi sẽ chỉ chạy hướng HttpHandler thô nếu bạn có bằng chứng WCF overhead là một vấn đề. Azure là khó khăn đủ để gỡ lỗi với rất nhiều được trong cấu hình mà tôi không thuyết phục thêm các vấn đề bổ sung của HttpHandlers liệu là hướng thích hợp để đi.

3

XML của bạn có được tuần tự hóa thông qua phản ánh (ví dụ: sử dụng thuộc tính và vv) không? Nếu có, thì protobuf-netmuch, much faster. Tuy nhiên, trên thực tế, ngay cả khi serialization XML của bạn được tùy biến bằng cách sử dụng getter rõ ràng và setter Func<> s, bạn vẫn có thể thấy một số tăng đáng kể với protobuf-net. Trong trường hợp của chúng tôi, tùy thuộc vào kích thước và nội dung của các đối tượng đang được đăng, chúng tôi thấy tốc độ tăng 5-15% trong thời gian tuần tự hóa.

Sử dụng protobuf-net cũng sẽ cung cấp khả năng băng thông có sẵn, mặc dù điều đó sẽ tùy thuộc vào nội dung của bạn ở mức độ lớn.

Hệ thống của chúng tôi có vẻ hơi khác so với của bạn, nhưng FWIW chúng tôi thấy rằng bản thân WCF có chi phí thấp gần như không đáng kể so với phần còn lại của luồng. Một profiler như dotTrace có thể giúp xác định nơi bạn có thể lưu khi bạn đã chuyển sang protobufs.

+0

Nhiều người cần biết cách tuần tự hóa XML chậm như thế nào, liên kết mà bạn cung cấp nói lên tất cả. – knightpfhor

+1

+1 cho hồ sơ. Ngoài ra, WCF tự lưu trữ có thể nhanh hơn WCF-over-ASP.NET. Xem ở đây: http://msdn.microsoft.com/en-us/library/ms731758.aspx –

0

Tôi đã tìm thấy việc khởi tạo lưu trữ blob (CreateCloudBlobClient(), GetContainerReference() v.v ...) khá chậm. Đó là một ý tưởng tốt để xem xét điều này khi thiết kế các dịch vụ Azure.

Tôi có các dịch vụ riêng cho bất kỳ thứ gì yêu cầu quyền truy cập blob khi nó kéo xuống thời gian cho các yêu cầu db thuần túy.

3

Kích thước của thư mà dịch vụ của bạn nhận được quá lớn vì có một lượng lớn dữ liệu trong thư hoặc vì chúng chứa tệp?

Nếu đây là trường hợp đầu tiên, thì ProtoBuf thực sự có vẻ như là một lựa chọn rất tốt.

Nếu kích thước thư lớn vì nó nhúng tệp, thì một chiến lược tôi đã sử dụng thành công là tạo hai kiến ​​trúc khác nhau cho các phương pháp dịch vụ của bạn: một phương pháp tải lên và tải xuống tệp và một phương pháp khác và nhận tin nhắn.

Các phương pháp liên quan đến tệp sẽ chỉ truyền các tệp bên trong phần thân của các yêu cầu HTTP, dưới dạng nhị phân mà không cần bất kỳ phép chuyển đổi hoặc mã hóa nào. Phần còn lại của thông số sẽ được gửi bằng URL yêu cầu.

Để tải tệp lên, trong dịch vụ REST WCF, trong phương thức dịch vụ, bạn sẽ phải khai báo tham số thể hiện tệp thuộc loại luồng. Ví dụ:

[OperationContract] 
[WebInvoke(Method = "POST", UriTemplate = "uploadProjectDocument?projectId={projectId}")] 
void UploadProjectDocument(Guid projectId, Stream document); 

Khi gặp thông số luồng, WCF sẽ chỉ lấy nội dung trực tiếp từ phần yêu cầu mà không thực hiện bất kỳ thao tác nào. Bạn chỉ có thể có một tham số kiểu luồng trên một phương thức dịch vụ (điều này có ý nghĩa vì mỗi yêu cầu HTTP chỉ có một phần thân).

Nhược điểm của phương pháp trên là bên cạnh tham số đại diện cho tệp, tất cả những thứ khác cần phải có các loại cơ bản (như chuỗi, số, GUID). Bạn không thể vượt qua bất kỳ đối tượng phức tạp nào. Nếu bạn cần làm điều đó, bạn sẽ phải tạo một phương thức riêng cho nó, vì vậy bạn có thể có hai phương thức (mà sẽ dịch trong hai cuộc gọi lúc chạy) tại thời điểm bạn chỉ có một.Tuy nhiên, việc tải lên tệp trực tiếp trong phần nội dung của yêu cầu sẽ hiệu quả hơn nhiều so với việc tuần tự hóa chúng, vì vậy ngay cả với những điều cần gọi thêm thì cần được cải thiện.

Để tải xuống tệp từ dịch vụ, bạn cần phải khai báo các phương thức WCF khi trả về Luồng và chỉ cần ghi tệp trong đối tượng được trả về. Như với các tham số Stream, WCF sẽ xuất nội dung của Stream trực tiếp vào phần thân của kết quả mà không có bất kỳ phép biến đổi nào trên nó.

3

Bài viết này http://social.msdn.microsoft.com/Forums/en-US/windowsazuredata/thread/d84ba34b-b0e0-4961-a167-bbe7618beb83 bao gồm các vấn đề về hiệu suất với Azure.

Vai trò Azure theo mặc định chỉ chạy trong một chuỗi duy nhất, điều này rất không hiệu quả trên các máy chủ. Có một số mẫu thiết kế rất đẹp ra có cho bạn thấy làm thế nào để thực hiện các vai trò đa luồng Azure, cá nhân tôi theo dõi này http://www.31a2ba2a-b718-11dc-8314-0800200c9a66.com/2010/12/running-multiple-threads-on-windows.html. Với điều này vai trò của bạn có thể tuần tự hóa các đối tượng song song.

Tôi sử dụng JSON làm định dạng trao đổi thay vì XML, nó có kích thước nhỏ hơn nhiều và được hỗ trợ tốt với .NET 4. Tôi hiện đang sử dụng DataContractJsonSerializer nhưng bạn cũng có thể xem JavaScriptSerializer hoặc JSON.NET. hiệu suất của bạn sau khi tôi đề nghị bạn so sánh chúng.

Dịch vụ WCF được luồn đơn theo mặc định (nguồn: http://msdn.microsoft.com/query/dev10.query?appId=Dev10IDEF1&l=EN-US&k=k(SYSTEM.SERVICEMODEL.SERVICEBEHAVIORATTRIBUTE.CONCURRENCYMODE);k(TargetFrameworkMoniker-%22.NETFRAMEWORK%2cVERSION%3dV4.0%22);k(DevLang-CSHARP)&rd=true). Đây là một mẫu mã mà sẽ làm cho API RESTfull bạn đa luồng:

ExampleService.svc.cs

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.PerCall, 
     IncludeExceptionDetailInFaults = false, MaxItemsInObjectGraph = Int32.MaxValue)] 
    public class ExampleService : IExample 

web.config

<system.serviceModel> 
    <protocolMapping> 
     <add scheme="http" binding="webHttpBinding" bindingConfiguration="" /> 
    </protocolMapping> 
    <behaviors> 
     <endpointBehaviors> 
     <behavior name=""> 
      <webHttp defaultOutgoingResponseFormat="Json" /> 
     </behavior> 
     </endpointBehaviors> 
     <serviceBehaviors> 
     <behavior name=""> 
      <serviceMetadata httpGetEnabled="true" /> 
      <serviceDebug includeExceptionDetailInFaults="false" /> 
     </behavior> 
     </serviceBehaviors> 
    </behaviors> 
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" /> 
    </system.serviceModel> 

ExampleService.svc

<%@ ServiceHost Language="C#" Debug="true" Service="WebPages.Interfaces.ExampleService" CodeBehind="ExampleService.svc.cs" %> 

Ngoài ra, ASP.NET theo mặc định chỉ cho phép hai kết nối HTTP đồng thời (nguồn Xem http://social.msdn.microsoft.com/Forums/en-US/windowsazuredata/thread/d84ba34b-b0e0-4961-a167-bbe7618beb83). Các thiết lập này sẽ cho phép lên đến 48 kết nối HTTP đồng thời:

web.config

<system.net> 
    <connectionManagement> 
     <!-- See http://social.msdn.microsoft.com/Forums/en-US/windowsazuredata/thread/d84ba34b-b0e0-4961-a167-bbe7618beb83 --> 
     <add address="*" maxconnection="48" /> 
    </connectionManagement> 
    </system.net> 

Nếu thông điệp cơ thể HTTP POST của bạn thường nhỏ hơn so với 1460 byte bạn nên bật của nagling để cải thiện hiệu suất (nguồn http://social.msdn.microsoft.com/Forums/en-US/windowsazuredata/thread/d84ba34b-b0e0-4961-a167-bbe7618beb83). Dưới đây là một số thiết lập mà thực hiện điều này:

web.config

<system.net> 
    <settings> 
     <!-- See http://social.msdn.microsoft.com/Forums/en-US/windowsazuredata/thread/d84ba34b-b0e0-4961-a167-bbe7618beb83 --> 
     <servicePointManager expect100Continue="false" /> 
    </settings> 
    </system.net> 

Xác định API JSON của bạn một cái gì đó như thế này:

using System.ServiceModel; 
using System.ServiceModel.Web; 
using Interchange; 

namespace WebPages.Interfaces 
{ 
    [ServiceContract] 
    public interface IExample 
    { 
     [OperationContract] 
     [WebInvoke(Method = "POST", 
      BodyStyle = WebMessageBodyStyle.Bare, 
      RequestFormat = WebMessageFormat.Json, 
      ResponseFormat = WebMessageFormat.Json)] 
     string GetUpdates(RequestUpdates name); 

     [OperationContract] 
     [WebInvoke(Method = "POST", 
      BodyStyle = WebMessageBodyStyle.Bare, 
      RequestFormat = WebMessageFormat.Json, 
      ResponseFormat = WebMessageFormat.Json)] 
     string PostMessage(PostMessage message); 

    } 
} 

Bạn có thể serialize để JSON trong.NET 4 như thế này:

string SerializeData(object data) 
{ 
    var serializer = new DataContractJsonSerializer(data.GetType()); 
    var memoryStream = new MemoryStream(); 
    serializer.WriteObject(memoryStream, data); 
    return Encoding.Default.GetString(memoryStream.ToArray());    
} 

Một thực thể trao đổi thông thường bạn có thể định nghĩa như bình thường:

using System.Collections.Generic; 
using System.Runtime.Serialization; 

namespace Interchange 
{ 
    [DataContract] 
    public class PostMessage 
    { 
     [DataMember] 
     public string Text { get; set; } 

     [DataMember] 
     public List<string> Tags { get; set; } 

     [DataMember] 
     public string AspNetSessionId { get; set; } 
    } 
} 

Bạn có thể viết HTTPModule của riêng bạn cho nén Gzip thượng nguồn, nhưng tôi sẽ cố gắng những thứ ở trên đầu.

Cuối cùng, hãy đảm bảo rằng bộ nhớ bảng của bạn ở cùng một vị trí với các dịch vụ tiêu thụ chúng.

+0

Tôi không nghĩ rằng đó là sự thật rằng vai trò Web chỉ chạy trong một chủ đề duy nhất, phải không?Bài viết mà bạn đã liên kết chỉ đề cập đến vai trò Công nhân. – Rory

+0

@Rory ASP.NET theo mặc định chỉ cho phép hai kết nối HTTP đồng thời (xem http://social.msdn.microsoft.com/Forums/en-US/windowsazuredata/thread/d84ba34b-b0e0-4961-a167-bbe7618beb83) –

3

Tôi đã có trải nghiệm rất thú vị với ServiceStack:

http://www.servicestack.net.

Về cơ bản, đây là lựa chọn cuối cùng của bạn; một lớp khá mỏng trên đầu trang của HttpHandlers với khả năng tuần tự hóa XML và JSON nhanh chóng, cho thấy một API REST.

Việc serialization JSV nó cũng cung cấp là khoảng một nửa tốc độ của Protobuf.NET tôi tin, và hỗ trợ cho ProtoBuf được lên kế hoạch.

Tôi không biết chắc chắn nếu nó chạy trên Azure, nhưng tôi không thể nghĩ ra một lý do tại sao không vì nó chỉ đơn giản là tích hợp vào bất kỳ ứng dụng ASP.NET.

1

Dưới đây là Benchmarks for different .NET serialization options

Trong số tất cả serializers JSON Tôi đã benchmarked Json serializer ServiceStack tôi thực hiện tốt nhất xung quanh 3x nhanh hơn JSON.NET. Dưới đây là một vài tiêu chuẩn bên ngoài cho thấy điều này:

  1. http://daniel.wertheim.se/2011/02/07/json-net-vs-servicestack/
  2. http://theburningmonk.com/2011/08/performance-test-json-serializers/

ServiceStack (một mã nguồn mở thay thế để WCF) đi kèm cấu hình sẵn với của NET nhanh nhất JSVJSON chữ serializers OOB .

Tôi thấy ai đó bao gồm cấu hình dài về cách bạn có thể bẻ cong WCF để định cấu hình để sử dụng Trình xử lý JSON chậm hơn được giao với .NET. Trong Service Stack mọi dịch vụ web tự động có sẵn thông qua JSON, XML, SOAP (inc. JSV, CSV, HTML) tự động mà không cần bất kỳ cấu hình nào, vì vậy bạn có thể chọn điểm cuối thích hợp nhất mà không cần thêm bất kỳ nỗ lực nào.

Cùng một lượng mã và cấu hình cho ví dụ WCF trong Dịch vụ stack chỉ là:

public class PostMessage 
{ 
    public string Text { get; set; } 
    public List<string> Tags { get; set; } 
    public string AspNetSessionId { get; set; } 
} 

public class GetUpdatesService : IService<GetUpdates> 
{ 
    public object Execute(GetUpdates request){ ... } 
} 

public class PostMessageService : IService<PostMessage> 
{ 
    public object Execute(PostMessage request){ ... } 
} 

Lưu ý: trang trí DTOs của bạn với [DataContract] là không bắt buộc.

Ví dụ ServiceStack Hello World hiển thị tất cả liên kết các định dạng khác nhau, trang siêu dữ liệu XSD Schemas và SOAP WSDLs tự động có sẵn sau khi bạn tạo dịch vụ web.

Các vấn đề liên quan