2012-06-23 24 views
21

Đây có phải là một ví dụ hay về một HttpListener có thể mở rộng được đa luồng không?HttpListener đa luồng với await async và Tasks

Đây có phải là ví dụ như một IIS thực sự sẽ làm điều đó không?

public class Program 
{ 
    private static readonly HttpListener Listener = new HttpListener(); 

    public static void Main() 
    { 
     Listener.Prefixes.Add("http://+:80/"); 
     Listener.Start(); 
     Listen(); 
     Console.WriteLine("Listening..."); 
     Console.WriteLine("Press any key to exit..."); 
     Console.ReadKey(); 
    } 

    private static async void Listen() 
    { 
     while (true) 
     { 
      var context = await Listener.GetContextAsync(); 
      Console.WriteLine("Client connected"); 
      Task.Factory.StartNew(() => ProcessRequest(context)); 
     } 

     Listener.Close(); 
    } 

    private static void ProcessRequest(HttpListenerContext context) 
    { 
     System.Threading.Thread.Sleep(10*1000); 
     Console.WriteLine("Response"); 
    } 
} 

Tôi đang tìm kiếm giải pháp có thể mở rộng không dựa trên IIS. Thay vào đó chỉ trên http.sys (đó là lớp httplistener) - Lý do không dựa vào iIS là vì govt. khu vực tôi làm việc đòi hỏi diện tích bề mặt tấn công cực kỳ giảm.

Trả lời

19

Tôi đã làm điều gì đó tương tự tại https://github.com/JamesDunne/Aardwolf và đã thực hiện một số thử nghiệm mở rộng về vấn đề này.

Xem mã tại https://github.com/JamesDunne/aardwolf/blob/master/Aardwolf/HttpAsyncHost.cs#L107 để thực hiện vòng lặp sự kiện cốt lõi.

Tôi thấy rằng sử dụng Semaphore để kiểm soát số lượng yêu cầu đồng thời GetContextAsync đang hoạt động là cách tiếp cận tốt nhất. Về cơ bản, vòng lặp chính tiếp tục chạy cho đến khi semaphore chặn luồng do số đếm được đạt tới. Sau đó sẽ có N đồng thời "kết nối chấp nhận" hoạt động. Mỗi lần kết nối được chấp nhận, semaphore được phát hành và yêu cầu mới có thể thay thế.

Giá trị đếm ban đầu và giá trị tối đa của semaphore yêu cầu một số điều chỉnh tinh chỉnh, tùy thuộc vào tải bạn mong muốn nhận được. Đó là hành động cân bằng tinh tế giữa số lượng kết nối đồng thời bạn mong đợi so với thời gian phản hồi trung bình mà khách hàng của bạn mong muốn. Giá trị cao hơn có nghĩa là có thể duy trì nhiều kết nối hơn với thời gian phản hồi trung bình chậm hơn nhiều; ít kết nối hơn sẽ bị từ chối. Giá trị thấp hơn có nghĩa là ít kết nối hơn có thể được duy trì ở thời gian đáp ứng trung bình nhanh hơn nhiều; nhiều kết nối hơn sẽ bị từ chối.

Tôi đã tìm thấy, trên thực tế (trên phần cứng của mình), giá trị xung quanh 128 cho phép máy chủ xử lý số lượng lớn kết nối đồng thời (tối đa 1.024) ở thời gian phản hồi có thể chấp nhận. Thử nghiệm bằng phần cứng của riêng bạn và điều chỉnh các thông số của bạn cho phù hợp.

Tôi cũng thấy rằng một cá thể WCAT không thích xử lý hơn 1.024 kết nối. Vì vậy, nếu bạn nghiêm túc về việc tải thử nghiệm, hãy sử dụng nhiều máy khách với WCAT đối với máy chủ của bạn và đảm bảo kiểm tra qua mạng nhanh, ví dụ: 10 GbE và giới hạn của hệ điều hành của bạn không làm chậm bạn xuống. Đảm bảo kiểm tra trên các SKU của Windows Server vì các SKU trên màn hình được giới hạn theo mặc định.

Tóm tắt: Cách bạn viết vòng chấp nhận kết nối là rất quan trọng đối với khả năng mở rộng của máy chủ.

+0

Liên kết đã chết ... –

+0

Liên kết được cập nhật. Cảm ơn bạn đã bình luận! –

+0

Có sự khác biệt nào giữa việc sử dụng các ẩn dụ và ServicePointManager.DefaultConnectionLimit không? –

5

Về mặt kỹ thuật, bạn đã đúng. Để làm cho nó có thể mở rộng, bạn có thể muốn có nhiều GetContextAsync chạy cùng một lúc (kiểm tra hiệu năng cần biết chính xác có bao nhiêu, nhưng "một vài cho mỗi lõi" có lẽ là câu trả lời đúng).

Sau đó, tự nhiên, như được chỉ ra bởi nhận xét; không sử dụng IIS có nghĩa là bạn cần phải khá nghiêm túc về bảo mật cho rất nhiều thứ IIS cung cấp cho bạn "miễn phí".

1

Tôi biết tôi rất muộn đối với đảng về điều này, nhưng tôi đã xuất bản một thư viện (nguồn ở đây https://github.com/jchristn/WatsonWebserver) trên NuGet đóng gói một máy chủ web không đồng bộ.