নিট 4.5.৪ থেকে অ্যাসিঙ্ক এইচটিপিপিলেট কি নিবিড় লোড অ্যাপ্লিকেশনগুলির জন্য খারাপ পছন্দ?


130

আমি সম্প্রতি এইচটিটিপি কল থ্রুপুট পরীক্ষার জন্য একটি সাধারণ অ্যাপ্লিকেশন তৈরি করেছি যা একটি ক্লাসিকাল মাল্টিথ্রেডেড পদ্ধতির বনাম একটি অ্যাসিনক্রোনাস পদ্ধতিতে তৈরি করা যেতে পারে।

অ্যাপ্লিকেশনটি এইচটিটিপি কলগুলির একটি পূর্বনির্ধারিত সংখ্যা সম্পাদন করতে সক্ষম এবং শেষে এটি সম্পাদন করার জন্য প্রয়োজনীয় সময়টি প্রদর্শন করে। আমার পরীক্ষার সময়, সমস্ত HTTP কলগুলি আমার স্থানীয় আইআইএস সেভারে করা হয়েছিল এবং তারা একটি ছোট পাঠ্য ফাইল (আকারে 12 বাইট) উদ্ধার করেছে rie

অ্যাসিক্রোনাস বাস্তবায়নের জন্য কোডের সবচেয়ে গুরুত্বপূর্ণ অংশটি নীচে তালিকাভুক্ত করা হয়েছে:

public async void TestAsync()
{
    this.TestInit();
    HttpClient httpClient = new HttpClient();

    for (int i = 0; i < NUMBER_OF_REQUESTS; i++)
    {
        ProcessUrlAsync(httpClient);
    }
}

private async void ProcessUrlAsync(HttpClient httpClient)
{
    HttpResponseMessage httpResponse = null;

    try
    {
        Task<HttpResponseMessage> getTask = httpClient.GetAsync(URL);
        httpResponse = await getTask;

        Interlocked.Increment(ref _successfulCalls);
    }
    catch (Exception ex)
    {
        Interlocked.Increment(ref _failedCalls);
    }
    finally
    { 
        if(httpResponse != null) httpResponse.Dispose();
    }

    lock (_syncLock)
    {
        _itemsLeft--;
        if (_itemsLeft == 0)
        {
            _utcEndTime = DateTime.UtcNow;
            this.DisplayTestResults();
        }
    }
}

মাল্টিথ্রেডিং বাস্তবায়নের সর্বাধিক গুরুত্বপূর্ণ অংশটি নীচে তালিকাভুক্ত করা হয়েছে:

public void TestParallel2()
{
    this.TestInit();
    ServicePointManager.DefaultConnectionLimit = 100;

    for (int i = 0; i < NUMBER_OF_REQUESTS; i++)
    {
        Task.Run(() =>
        {
            try
            {
                this.PerformWebRequestGet();
                Interlocked.Increment(ref _successfulCalls);
            }
            catch (Exception ex)
            {
                Interlocked.Increment(ref _failedCalls);
            }

            lock (_syncLock)
            {
                _itemsLeft--;
                if (_itemsLeft == 0)
                {
                    _utcEndTime = DateTime.UtcNow;
                    this.DisplayTestResults();
                }
            }
        });
    }
}

private void PerformWebRequestGet()
{ 
    HttpWebRequest request = null;
    HttpWebResponse response = null;

    try
    {
        request = (HttpWebRequest)WebRequest.Create(URL);
        request.Method = "GET";
        request.KeepAlive = true;
        response = (HttpWebResponse)request.GetResponse();
    }
    finally
    {
        if (response != null) response.Close();
    }
}

পরীক্ষা চালানো থেকে জানা গেল যে মাল্টিথ্রেডেড সংস্করণটি দ্রুত ছিল। এটি 10 ​​কে অনুরোধগুলি সম্পূর্ণ করতে প্রায় 0.6 সেকেন্ড সময় নিয়েছে, যখন অ্যাসিঙ্ক এক একই পরিমাণের বোঝা শেষ করতে প্রায় 2 সেকেন্ড সময় নিয়েছিল। এটি কিছুটা অবাক হয়েছিল, কারণ আমি আশা করছিলাম যে অ্যাসিঙ্কটি দ্রুততর হবে। হতে পারে এটি আমার এইচটিটিপি কলগুলি খুব দ্রুত ছিল of সত্যিকারের বিশ্বের দৃশ্যে, যেখানে সার্ভারটির আরও অর্থবহ অপারেশন করা উচিত এবং যেখানে নেটওয়ার্কের কিছুটা বিলম্ব হওয়া উচিত সেখানে ফলাফলগুলি বিপরীত হতে পারে।

যাইহোক, লোড বাড়ানোর সাথে সাথে HTTPClient যেভাবে আচরণ করে তা হ'ল সত্যই আমাকে উদ্বেগিত করে। যেহেতু এটি 10 ​​কে বার্তা সরবরাহ করতে প্রায় 2 সেকেন্ড সময় নেয়, তাই আমি ভেবেছিলাম যে 10 বারের সংখ্যার বার বার 10 সেকেন্ড দেওয়ার জন্য এটি প্রায় 20 সেকেন্ডের মতো লাগবে, তবে পরীক্ষাটি চালিয়ে গেছে যে 100 কে বার্তা সরবরাহ করতে প্রায় 50 সেকেন্ডের প্রয়োজন needs তদতিরিক্ত, 200k বার্তা সরবরাহ করতে সাধারণত 2 মিনিটের বেশি সময় লাগে এবং প্রায়শই, কয়েক হাজার (3-4-) নিম্নলিখিত ব্যতিক্রম ব্যর্থ হয়:

সকেটে একটি অপারেশন করা যায়নি কারণ সিস্টেমের পর্যাপ্ত বাফার জায়গার অভাব ছিল বা একটি সারি পূর্ণ ছিল।

আমি আইআইএস লগগুলি এবং অপারেশনগুলি যাচাই করেছিলাম যা কখনও সার্ভারে পেল না। তারা ক্লায়েন্টের মধ্যে ব্যর্থ হয়েছে। 49152 থেকে 65535 অবধি সাময়িক বন্দরগুলির ডিফল্ট পরিসীমা সহ আমি একটি উইন্ডোজ 7 মেশিনে পরীক্ষা চালিয়েছি ne বন্দরগুলির অভাব যদি সত্যই ব্যতিক্রমগুলির কারণ হয়ে দাঁড়ায় তবে এর অর্থ হ'ল নেটস্ট্যাট পরিস্থিতিটি সঠিকভাবে জানায় নি বা এইচটিসি ক্লায়েন্ট কেবলমাত্র সর্বাধিক সংখ্যক বন্দর ব্যবহার করে যার পরে এটি ব্যতিক্রম ছোঁড়া শুরু করে।

বিপরীতে, এইচটিটিপি কল উত্পন্ন করার মাল্টিথ্রিড পদ্ধতিটি খুব অনুমানযোগ্য আচরণ করেছিল। আমি এটি 10k বার্তাগুলির জন্য 0.6 সেকেন্ডের কাছাকাছি নিয়েছিলাম, 100k বার্তাগুলির জন্য প্রায় 5.5 সেকেন্ড এবং 1 মিলিয়ন বার্তাগুলির জন্য প্রায় 55 সেকেন্ডের প্রত্যাশিত। কোনও বার্তা ব্যর্থ হয়েছে। আরও, এটি চালানোর সময় এটি 55 এমবি র‌্যামের বেশি কখনও ব্যবহার করেনি (উইন্ডোজ টাস্ক ম্যানেজারের মতে)। অসম্পূর্ণভাবে বার্তা প্রেরণের সময় ব্যবহৃত মেমরিটি লোডের সাথে আনুপাতিকভাবে বেড়েছে grew এটি 200k বার্তা পরীক্ষার সময় প্রায় 500 এমবি র‌্যাম ব্যবহার করে।

আমি মনে করি উপরোক্ত ফলাফলগুলির জন্য দুটি মূল কারণ রয়েছে। প্রথমটি হ'ল এইচটিপিপ্লিয়েন্ট সার্ভারের সাথে নতুন সংযোগ তৈরি করতে খুব লোভী বলে মনে হচ্ছে। নেটস্ট্যাট দ্বারা ব্যবহৃত বন্দরগুলির উচ্চ সংখ্যার অর্থ হ'ল এটি সম্ভবত HTTP- র বেঁচে থাকার থেকে খুব বেশি উপকার করে না।

দ্বিতীয়টি হ'ল এইচটিপিপ্লেইন্টের কাছে থ্রোলটিং মেকানিজম নেই বলে মনে হচ্ছে। আসলে এটি async অপারেশন সম্পর্কিত একটি সাধারণ সমস্যা বলে মনে হচ্ছে। আপনার যদি খুব বড় সংখ্যক ক্রিয়াকলাপ সম্পাদন করা দরকার হয় তবে সেগুলি একবারে শুরু করা হবে এবং তারপরে এটি উপলব্ধ থাকায় তাদের ধারাবাহিকতা কার্যকর করা হবে। তত্ত্বের ক্ষেত্রে এটি ঠিক হওয়া উচিত, কারণ অ্যাসিঙ্ক অপারেশনগুলিতে বোঝা বাহ্যিক সিস্টেমে থাকে তবে উপরে প্রমাণিত হিসাবে এটি সম্পূর্ণরূপে নয়। প্রচুর অনুরোধ একবারে শুরু করা মেমরির ব্যবহার বাড়িয়ে তুলবে এবং পুরো সম্পাদনাকে ধীর করবে।

আমি একটি সহজ তবে আদিম বিলম্ব প্রক্রিয়া সহ অ্যাসিঙ্ক্রোনাস অনুরোধের সর্বাধিক সংখ্যাকে সীমাবদ্ধ করে আরও ভাল ফলাফল, মেমরি এবং কার্যকর করার সময় অনুযায়ী প্রাপ্ত করতে সক্ষম হয়েছি:

public async void TestAsyncWithDelay()
{
    this.TestInit();
    HttpClient httpClient = new HttpClient();

    for (int i = 0; i < NUMBER_OF_REQUESTS; i++)
    {
        if (_activeRequestsCount >= MAX_CONCURENT_REQUESTS)
            await Task.Delay(DELAY_TIME);

        ProcessUrlAsyncWithReqCount(httpClient);
    }
}

এটি সত্যিই কার্যকর হবে যদি এইচটিটিপি ক্লায়েন্ট সামনের অনুরোধগুলির সংখ্যা সীমিত করার জন্য একটি প্রক্রিয়া অন্তর্ভুক্ত করে। টাস্ক ক্লাসটি ব্যবহার করার সময় (যা নেট থ্রেড পুলের উপর ভিত্তি করে) সামঞ্জস্যিক থ্রেডের সংখ্যা সীমিত করে স্বয়ংক্রিয়ভাবে থ্রোটলিং অর্জন করা হয়।

সম্পূর্ণ পর্যালোচনার জন্য, আমি এইচটিপিপিবলেন্টের পরিবর্তে এইচটিপিওয়েব্রেকয়েস্টের ভিত্তিতে এসিএনসি পরীক্ষার একটি সংস্করণও তৈরি করেছি এবং আরও ভাল ফলাফল অর্জন করতে পেরেছি। একটি সূচনার জন্য, এটি একযোগে সংযোগগুলির সংখ্যার (সার্ভিসপয়েন্ট ম্যানেজার.ডাফল্ট সংযোগ লিমিট বা কনফিগার মাধ্যমে) সীমা নির্ধারণের অনুমতি দেয়, যার অর্থ এটি পোর্টের বাইরে চলে না এবং কোনও অনুরোধে কখনই ব্যর্থ হয় না (এইচটিটিপিপ্লিনেন্ট, ডিফল্টরূপে, HTTPWebRequest এর উপর ভিত্তি করে , তবে এটি সংযোগ সীমাবদ্ধতা সেটিংসকে উপেক্ষা করে বলে মনে হচ্ছে)।

অ্যাসিঙ্ক এইচটিটিপিওব্রেইকয়েস্ট পদ্ধতিটি এখনও বহু-পাঠ্যক্রমের চেয়ে প্রায় 50 - 60% ধীর ছিল, তবে এটি অনুমানযোগ্য এবং নির্ভরযোগ্য ছিল। এর একমাত্র অবক্ষয়টি হ'ল এটি বিশাল বোঝার নীচে বিশাল পরিমাণ স্মৃতি ব্যবহার করেছিল। উদাহরণস্বরূপ, 1 মিলিয়ন অনুরোধ প্রেরণের জন্য এটি প্রায় 1.6 গিগাবাইটের প্রয়োজন। সাম্প্রতিক অনুরোধের সংখ্যা সীমিত করে (যেমনটি আমি এইচটিটিপিপ্লিনেন্টের জন্য উপরে করেছি) আমি ব্যবহৃত মেমরিটি মাত্র 20 এমবি করে কমিয়ে আনতে পেরেছি এবং মাল্টিথ্রেডিং পদ্ধতির চেয়ে 10% ধীর গতিতে কার্যকর করার সময়টি পেয়েছি।

এই দীর্ঘ উপস্থাপনের পরে, আমার প্রশ্নগুলি: নিখরচায় লোড অ্যাপ্লিকেশনগুলির জন্য নেট .৫.৫ থেকে এইচটিপিপ্লিয়েন্ট শ্রেণি কি খারাপ পছন্দ? এটিকে থ্রটল করার কোনও উপায় আছে, যা আমি উল্লেখ করি এমন সমস্যাগুলি সমাধান করা উচিত? HttpWebRequest এর async গন্ধ সম্পর্কে কী?

আপডেট (ধন্যবাদ @ স্টিফেন ক্লিয়ারি)

যেমনটি দেখা যাচ্ছে, এইচটিপিপ্লিয়েন্ট, ঠিক এইচটিটিপিওয়েব্রেইকেষ্টের (যেমন এটি ডিফল্ট ভিত্তিক) এটির সাথে একই পয়েন্টে সার্ভিসপয়েন্ট ম্যানেজার.ডেফল্টকনেকশন লিমিটের সাথে সীমাবদ্ধ একই হোস্টে সংযোগের সংখ্যা থাকতে পারে। আশ্চর্যের বিষয়টি হ'ল এমএসডিএন অনুসারে , সংযোগের সীমাটির জন্য ডিফল্ট মান 2 I আমি এটিও পরীক্ষা করেছিলাম যে আমার দিকে ডিবাগারটি ব্যবহার করে যা নির্দেশ করে যে সত্যই 2 ডিফল্ট মান। যাইহোক, দেখে মনে হচ্ছে সার্ভিসপয়েন্ট ম্যানেজার.ডাফল্ট সংযোগ-লিমিটের স্পষ্টভাবে কোনও মান সেট না করা হলে ডিফল্ট মানটিকে অগ্রাহ্য করা হবে। যেহেতু আমার এইচটিটিপিপ্লিনেন্ট পরীক্ষার সময় আমি স্পষ্টভাবে এর জন্য কোনও মান সেট করি নি বলে আমি ভেবেছিলাম এটি উপেক্ষা করা হয়েছে।

সার্ভিসপয়েন্ট ম্যানেজার.ডাফল্টক্লিকেশনলিমিটটি 100 এইচটিপিপিপ্লাইনেট স্থাপনের পরে নির্ভরযোগ্য এবং পূর্বাভাসযোগ্য হয়ে উঠেছে (নেটস্ট্যাট নিশ্চিত করে যে কেবল 100 টি পোর্ট ব্যবহৃত হয়)। এটি এখনও async HttpWebRequest (প্রায় 40% দ্বারা) এর চেয়ে ধীরে ধীরে, তবে আশ্চর্যের বিষয় হল এটি কম স্মৃতি ব্যবহার করে। 1 মিলিয়ন অনুরোধগুলির সাথে জড়িত পরীক্ষার জন্য, এটি অ্যাসিঙ্ক এইচটিটিপিওয়েব্রেকয়েস্টের 1.6 গিগাবাইটের তুলনায় সর্বাধিক 550 এমবি ব্যবহার করে।

সুতরাং, যদিও সার্ভিসপয়েন্ট ম্যানেজার.ডাফল্টক্লিকেশন লিমিটের সংমিশ্রণে এইচটিপিপ্লিয়েন্টটি নির্ভরযোগ্যতা নিশ্চিত করে বলে মনে হচ্ছে (কমপক্ষে সেই দৃশ্যের জন্য যেখানে সমস্ত কল একই হোস্টের দিকে করা হচ্ছে), এটি এখনও মনে হচ্ছে সঠিক থ্রোটলিং ব্যবস্থা না থাকার কারণে তার অভিনয়টি নেতিবাচকভাবে প্রভাবিত হয়েছে। এমন কিছু যা অনুরোধের একযোগে সংখ্যাকে একটি কনফিগারযোগ্য মানের মধ্যে সীমাবদ্ধ রাখে এবং বাকীগুলিকে একটি কাতারে রাখে তা উচ্চ স্কেলিবিলিটি দৃশ্যের জন্য এটি আরও বেশি উপযুক্ত করে তুলবে।


4
HttpClientশ্রদ্ধা করা উচিত ServicePointManager.DefaultConnectionLimit
স্টিফেন ক্লিয়ারি

2
আপনার পর্যবেক্ষণগুলি তদন্ত করার মতো বলে মনে হচ্ছে। যদিও একটি জিনিস আমাকে বিরক্ত করছে: আমি মনে করি এটি একবারে হাজার হাজার অ্যাসিঙ্ক আইও প্রদান করা অত্যন্ত চূড়ান্ত ri আমি কখনও প্রযোজনায় এটি করতাম না। আপনি async এর অর্থ এই নয় যে আপনি বিভিন্ন সংস্থান গ্রহণ করে বাদাম যেতে পারেন। (Microsofts কর্মকর্তা নমুনা একটু পাশাপাশি যে বিষয়ে বিভ্রান্তিকর আছে।)
usr ডিরেক্টরির

1
যদিও সময় বিলম্বের সাথে থ্রটল করবেন না। আপনি স্থিরভাবে নির্ধারিত স্থির সমঝোতার স্তরে থ্রোটল। একটি সহজ সমাধান হ'ল সেমফোরস্লিম Wউইটঅ্যানসিঙ্ক যদিও এটি নির্বিচারে বড় পরিমাণে কাজের জন্যও উপযুক্ত হবে না।
usr ডিরেক্টরির

1
@ ফ্লোরিনডুমিট্রেস্কু থ্রোটলিংয়ের জন্য, আপনি SemaphoreSlimইতিমধ্যে উল্লিখিত হিসাবে, বা ActionBlock<T>টিপিএল ডেটাফ্লো থেকে ব্যবহার করতে পারেন ।
সুইভ

1
@ এসভিক, আপনার পরামর্শের জন্য ধন্যবাদ থ্রোটলিং / সমঝোতা সীমাবদ্ধতার জন্য ম্যানুয়ালি কোনও পদ্ধতি প্রয়োগ করতে আমি আগ্রহী নই। যেমনটি উল্লেখ করা হয়েছে, আমার প্রশ্নের অন্তর্ভুক্ত বাস্তবায়ন কেবলমাত্র একটি তত্ত্বকে পরীক্ষা করার জন্য এবং বৈধতার জন্য। আমি এটির উন্নতি করার চেষ্টা করছি না, যেহেতু এটি উত্পাদন পাবে না। আমি যে বিষয়ে আগ্রহী তা হ'ল যদি নেট ফ্রেমওয়ার্কটি অ্যাসিঙ্ক আইও ক্রিয়াকলাপের সীমাবদ্ধকরণের জন্য একটি বিল্ট ইন মেকানিজম সরবরাহ করে (এইচটিটিপি ক্লায়েন্ট অন্তর্ভুক্ত)।
ফ্লোরিন ডুমিট্রেস্কু

উত্তর:


64

প্রশ্নে উল্লিখিত পরীক্ষাগুলির পাশাপাশি আমি সম্প্রতি কিছু কম নতুন এইচটিটিপি কল যুক্ত করেছি (যা আগে 1 মিলিয়ন এর তুলনায় 5000) তবে অনুরোধে কার্যকর হতে বেশি সময় লেগেছিল (প্রায় 1 মিলিসেকেন্ডের তুলনায় 500 মিলিসেকেন্ড)। উভয় পরীক্ষক অ্যাপ্লিকেশন, সিঙ্ক্রোনালি মাল্টিথ্রেডেড ওয়ান (এইচটিপিপিউব্রেকুয়েস্টের উপর ভিত্তি করে) এবং অ্যাসিনক্রোনাস আই / ওয়ান (এইচটিটিপি ক্লায়েন্টের উপর ভিত্তি করে) একই রকম ফলাফল তৈরি করেছে: সিপিইউর প্রায় 3% এবং 30 এমবি মেমরি ব্যবহার করে প্রায় 10 সেকেন্ড কার্যকর করতে হবে। দুটি পরীক্ষকের মধ্যে কেবলমাত্র পার্থক্যটি ছিল যে মাল্টিথ্রেডেড একটি কার্যকর করতে 310 থ্রেড ব্যবহার করেছিল, যখন অ্যাসিক্রোনাস মাত্র 22 টি।

আমার পরীক্ষাগুলির উপসংহার হিসাবে, খুব দ্রুত অনুরোধগুলি মোকাবেলা করার সময় অ্যাসিনক্রোনাস এইচটিটিপি কলগুলি সেরা বিকল্প নয়। এর পেছনের কারণটি হ'ল একটি টাস্কে যখন অ্যাসিক্রোনাস আই / ও কল থাকে, তখন যে থ্রেডটির উপর টাস্কটি শুরু হয়েছিল তা অ্যাসিক্রোনাস কল করার সাথে সাথেই বন্ধ হয়ে যায় এবং বাকী কাজটি কলব্যাক হিসাবে নিবন্ধিত হয়। তারপরে, যখন আই / ও অপারেশন সম্পূর্ণ হয়, কলব্যাকটি প্রথম উপলব্ধ থ্রেডে কার্যকর করার জন্য সারি করা হয়। এগুলি একটি ওভারহেড তৈরি করে, যা থ্রেডে চালিত হওয়ার পরে দ্রুত I / O ক্রিয়াকলাপগুলিকে আরও দক্ষ করে তোলে।

দীর্ঘ বা সম্ভাব্য দীর্ঘ I / O ক্রিয়াকলাপগুলির সাথে লেনদেন করার সময় অ্যাসিঙ্ক্রোনাস এইচটিটিপি কলগুলি একটি ভাল বিকল্প কারণ এটি আই / ও অপারেশনগুলি সম্পূর্ণ হওয়ার অপেক্ষায় কোনও থ্রেডকে ব্যস্ত রাখে না। এটি সিপিইউ বাউন্ড ক্রিয়াকলাপ দ্বারা আরও সিপিইউ সময় ব্যয় করতে দেয় এমন অ্যাপ্লিকেশন দ্বারা ব্যবহৃত থ্রেডগুলির সামগ্রিক সংখ্যা হ্রাস করে। তদুপরি, অ্যাপ্লিকেশনগুলিতে কেবলমাত্র সীমিত সংখ্যক থ্রেড বরাদ্দ করা হয় (যেমন এটি ওয়েব অ্যাপ্লিকেশনগুলির ক্ষেত্রে যেমন হয়), অ্যাসিঙ্ক্রোনাস আই / ও থ্রেড পুলের থ্রেড হ্রাস হ্রাস করে, যা I / O কলগুলি সুসংগতভাবে সম্পাদন করলে ঘটতে পারে।

সুতরাং, নিবিড় লোড অ্যাপ্লিকেশনগুলির জন্য অ্যাসিঙ্ক এইচটিপিপিলেটটি কোনও বাধা নয়। এটি ঠিক যে এটির প্রকৃতি অনুসারে এটি খুব দ্রুত এইচটিটিপি অনুরোধগুলির জন্য খুব উপযুক্ত নয়, পরিবর্তে এটি দীর্ঘ বা সম্ভাব্য দীর্ঘতরগুলির জন্য আদর্শ, বিশেষত অ্যাপ্লিকেশনের অভ্যন্তরে কেবলমাত্র সীমিত সংখ্যক থ্রেড উপলব্ধ। এছাড়াও, সার্ভিসপয়েন্ট ম্যানেজ.ডেফল্টস কানেকশন লিমিটের মাধ্যমে সামঞ্জস্যতা সীমাবদ্ধ করা একটি ভাল অনুশীলন যা সমান্তরালতার একটি ভাল স্তর নিশ্চিত করার জন্য যথেষ্ট উচ্চ, তবে সাময়িক বন্দর অবনতি রোধ করতে যথেষ্ট কম। আপনি পরীক্ষা এবং সিদ্ধান্তে এই প্রশ্নের জন্য উপস্থাপন উপর আরো বিস্তারিত জানতে পারেন এখানে


3
"খুব দ্রুত" কত দ্রুত? 1ms? 100 মিঃসে? 1,000ms?
টিম পি।

আমি উইন্ডোজটিতে মোতায়েন করা ওয়েবলোগিক ওয়েব সার্ভারে একটি বোঝা পুনরায় খেলতে আপনার "অ্যাসিঙ্ক" পদ্ধতির মতো কিছু ব্যবহার করছি, তবে আমি দ্রুত এফিকিমিক পোর্ট হ্রাসের সমস্যাটি পাচ্ছি। আমি সার্ভিসপয়েন্ট ম্যানেজআর। ডিফল্ট সংযোগ লিমিটটি স্পর্শ করি নি এবং প্রতিটি অনুরোধে আমি সবকিছু নিষ্পত্তি এবং পুনরায় তৈরি করছি (HttpClient এবং প্রতিক্রিয়া)। সংযোগগুলি উন্মুক্ত থাকার এবং বন্দরগুলি অপসারণের কারণ কী হতে পারে আপনার কোনও ধারণা আছে?
ইরাভানচি

@TimP। আমার পরীক্ষাগুলির জন্য, উপরে উল্লিখিত হিসাবে, "খুব দ্রুত" হ'ল অনুরোধগুলি যা সম্পূর্ণ করতে মাত্র 1 মিলিসেকেন্ড নিচ্ছে। বাস্তব বিশ্বে এটি সর্বদা সাবজেক্টিভ থাকবে। আমার দৃষ্টিকোণ থেকে, স্থানীয় নেটওয়ার্ক ডাটাবেসে একটি ছোট প্রশ্নের সাথে সমান কিছু, দ্রুত বিবেচনা করা যেতে পারে, যখন ইন্টারনেটের মাধ্যমে একটি এপিআই কলের সমতুল্য কিছু ধীর বা সম্ভাব্য ধীর হিসাবে বিবেচনা করা যেতে পারে।
ফ্লোরিন ডুমিট্রেস্কু

1
@ ইরাভানচি, "অ্যাসিঙ্ক" পদ্ধতির কাছে, অনুরোধ প্রেরণ এবং প্রতিক্রিয়া হ্যান্ডলিং আলাদাভাবে সম্পাদন করা হয়। আপনার যদি প্রচুর কল হয়, সমস্ত অনুরোধগুলি খুব দ্রুত প্রেরণ করা হবে এবং তারা পৌঁছালে প্রতিক্রিয়াগুলি হ্যান্ডেল করা হবে। যেহেতু আপনি কেবলমাত্র সংযোগগুলি তাদের প্রতিক্রিয়াগুলি আসার পরে তা নিষ্পত্তি করতে পারবেন, তাই প্রচুর পরিমাণে একযোগে সংযোগগুলি আপনার সংক্ষিপ্ত বন্দরগুলি সংগ্রহ করতে এবং হ্রাস করতে পারে। সার্ভিসপয়েন্ট ম্যানেজ.ডেফল্ট সংযোগ-লিমিট ব্যবহার করে আপনার সর্বাধিক সংখ্যার সাম্প্রতিক সংযোগ সীমাবদ্ধ করা উচিত।
ফ্লোরিন ডুমিট্রেস্কু

1
@ ফ্লোরিনডুমিট্রেস্কু, আমি এই নেটওয়ার্ক কলগুলিতে যোগ করব প্রাকৃতিকভাবে অনাকাঙ্ক্ষিত। 10 মিমি 90 মিনিটে যে জিনিসগুলি চলতে থাকে সেগুলি যখন সেই নেটওয়ার্ক সংস্থানটি যানজট করা হয় বা অন্য 10% সময় উপলভ্য থাকে না তখন অবরুদ্ধ সমস্যা তৈরি করতে পারে।
টিম পি

27

আপনার ফলাফলগুলিকে প্রভাবিত করতে পারে এমন একটি বিষয় বিবেচনা করার বিষয় হ'ল এইচটিটিপিওয়েবরেস্টের সাহায্যে আপনি প্রতিক্রিয়াপ্রবাহ পাচ্ছেন না এবং সেই স্ট্রিমটি গ্রাস করছেন না। HTTPClient এর সাথে, ডিফল্টরূপে এটি নেটওয়ার্ক স্ট্রিমটিকে একটি মেমরি প্রবাহে অনুলিপি করবে। আপনি বর্তমানে HTTPWebRquest ব্যবহার করছেন ঠিক তেমনভাবে HTTPClient ব্যবহার করার জন্য আপনাকে যা করতে হবে

var requestMessage = new HttpRequestMessage() {RequestUri = URL};
Task<HttpResponseMessage> getTask = httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead);

অন্য জিনিসটি হ'ল আমি সত্যই নিশ্চিত নই যে আসল পার্থক্যটি কী, কোনও থ্রেডিং দৃষ্টিকোণ থেকে আপনি আসলে পরীক্ষা করছেন। আপনি যদি এইচটিটিপিপ্লায়েন্টহ্যান্ডলারের গভীরতায় খনন করেন তবে এটি অসম্পূর্ণ অনুরোধটি সম্পাদন করার জন্য কেবল টাস্ক.ফ্যাক্টরি.স্টার্টনউ করে। থ্রেডিং আচরণটি সিঙ্ক্রোনাইজেশন প্রসঙ্গে ঠিক একই ভাবে হস্তান্তর করা হয় যেমন HTTPWebRequest উদাহরণ সহ আপনার উদাহরণটি সম্পন্ন হয়েছে।

নিঃসন্দেহে, এইচটিটিপিএক্লিয়েন্ট ডিফল্ট হিসাবে কিছু ওভারহেড যুক্ত করে এটি HTTPWebRequestটিকে তার পরিবহণ গ্রন্থাগার হিসাবে ব্যবহার করে। সুতরাং আপনি সর্বদা HttpClientHandler ব্যবহার করার সময় সরাসরি একটি HTTPWebRequest দিয়ে আরও ভাল পারফেক্ট করতে সক্ষম হবেন। এইচটিটিপি ক্লিনেন্ট যে সুবিধাগুলি নিয়ে আসে তা হ'ল এইচটিটিপিআরস্পোনমেসেজ, এইচটিপিআরকুয়েস্টমেসেজ, এইচটিটিপি কনটেন্ট এবং সমস্ত দৃ strongly়ভাবে টাইপ করা শিরোনামের মতো স্ট্যান্ডার্ড ক্লাস। নিজেই এটি কোনও পারফেক্ট অপটিমাইজেশন নয়।


(পুরানো উত্তর, তবে) HttpClientব্যবহার করা সহজ বলে মনে হয়েছে এবং আমি ভেবেছিলাম যে অ্যাসিনক্রোনাসটিই চলার উপায় ছিল, তবে এর চারপাশে অনেকগুলি "বুট এবং আইএফ" রয়েছে বলে মনে হয়। সম্ভবত এটি HttpClientআবার লিখতে হবে যাতে এটি ব্যবহার করার জন্য আরও স্বজ্ঞাত হয়? বা ডকুমেন্টেশনটি কীভাবে এটি সবচেয়ে দক্ষতার সাথে ব্যবহার করতে হয় সে সম্পর্কে গুরুত্বপূর্ণ বিষয়গুলিতে সত্যই চাপ দিচ্ছিল?
মার্টব

@ মর্টব, ফ্লারল.এইচটিটিপি ফ্লুরল.ইও এইচটিপিপ্লিয়েন্টের মোড়ক ব্যবহার করতে আরও স্বজ্ঞাত
মাইকেল ফ্রেইজিম

1
@ মিশেলফ্রিজেম: ধন্যবাদ, যদিও আমি এই মুহুর্তে এইচটিপিপ্লিনেন্টের সাথে থাকতে শিখেছি ...
মার্টব

17

যদিও এটি ওপি-র প্রশ্নের 'অ্যাসিঙ্ক' অংশটির সরাসরি উত্তর দেয় না, এটি তিনি ব্যবহার করছেন এমন বাস্তবায়নের একটি ত্রুটি সম্বোধন করে।

আপনি যদি নিজের অ্যাপ্লিকেশনটি স্কেল করতে চান তবে ইনস্ট্যান্স-ভিত্তিক এইচটিটিপি ক্লিনেন্টগুলি এড়িয়ে চলুন। পার্থক্যটি বিশাল! লোডের উপর নির্ভর করে আপনি খুব আলাদা পারফরম্যান্সের নম্বর দেখতে পাবেন। এইচটিটিপিপ্লায়েন্টটি অনুরোধগুলি জুড়ে আবার ব্যবহার করার জন্য ডিজাইন করা হয়েছিল। এটি ছাত্রলীগের যারা লিখেছেন তাদের দ্বারা এটি নিশ্চিত হয়েছিল।

আমার একটি সাম্প্রতিক প্রকল্পটি ছিল কিছু নতুন সিস্টেমের জন্য ব্ল্যাক ফ্রাইডে / হলিডে ট্র্যাফিকের জন্য খুব বড় এবং সুপরিচিত অনলাইন কম্পিউটার খুচরা বিক্রেতার স্কেল সহায়তা করা। আমরা HTTPClient ব্যবহারের চারপাশে কিছু কার্য সম্পাদন সংক্রান্ত সমস্যার মধ্যে পড়েছি। যেহেতু এটি প্রয়োগ করে IDisposable, ডেভসগুলি সাধারণত একটি কাজ তৈরি করে এবং কোনও using()বিবৃতিতে রাখার মাধ্যমে আপনি সাধারণত যা করবেন তা করেছেন। একবার আমরা লোড টেস্টিং শুরু করে অ্যাপটি সার্ভারকে তার হাঁটুতে এনেছিল - হ্যাঁ, সার্ভারটি কেবল অ্যাপ্লিকেশন নয়। কারণটি হ'ল এইচটিপিপি্লিয়েন্টের প্রতিটি উদাহরণ সার্ভারে একটি আই / ও সমাপ্তি পোর্ট খোলে। জিসির অ-বিবাদ-চূড়ান্তকরণের কারণে এবং আপনি একাধিক ওএসআই স্তর জুড়ে থাকা কম্পিউটার সংস্থাগুলির সাথে কাজ করছেন এই কারণে , নেটওয়ার্ক বন্দরগুলি বন্ধ করতে কিছুটা সময় নিতে পারে। আসলে উইন্ডোজ ওএস নিজেইএকটি পোর্ট বন্ধ করতে 20 সেকেন্ড পর্যন্ত সময় নিতে পারে (মাইক্রোসফ্ট প্রতি)। সেগুলি বন্ধ হওয়ার চেয়ে আমরা দ্রুত পোর্টগুলি খুলছিলাম - সার্ভার পোর্ট ক্লান্তি যা সিপিইউকে 100% করে দিয়েছে। আমার ফিক্সটি ছিল এইচটিপিপ্লেইন্টটিকে স্থির উদাহরণে পরিবর্তন করা যা সমস্যার সমাধান করেছে। হ্যাঁ, এটি একটি নিষ্পত্তিযোগ্য সংস্থান, তবে কোনও ওভারহেড পারফরম্যান্সের পার্থক্যের দ্বারা বিস্তৃত হয়। আপনার অ্যাপটি কীভাবে আচরণ করে তা দেখতে আমি আপনাকে কিছু লোড টেস্টিং করতে উত্সাহিত করি।

নীচের লিঙ্কেও উত্তর দেওয়া হয়েছে:

কোনও ওয়েবএপিআই ক্লায়েন্টে কল প্রতি নতুন এইচটিপিপিলেট তৈরির ওভারহেড কী?

https://www.asp.net/web-api/overview/advanced/calling-a-web-api-from-a-net-client


আমি ক্লায়েন্টের টিসিপি পোর্ট ক্লান্তি তৈরি করতে ঠিক একই সমস্যাটি পেয়েছি। সমাধানটি হ'ল এইচটিপিপি্লিয়েন্ট উদাহরণটি দীর্ঘ সময়ের জন্য ইজারা দেওয়া ছিল যেখানে প্রতিটি কলের জন্য তৈরি এবং নিষ্পত্তি করা হয় না ite আমি যে সিদ্ধান্তে পৌঁছেছি তা হ'ল "এটি ডিসপোজ প্রয়োগ করে কেবল তার অর্থ এটি নিষ্পত্তি করা সস্তা" নয়।
ফিলিপএইচ

সুতরাং যদি এইচটিটিপিপ্লায়েন্ট স্থির হয়, এবং পরবর্তী অনুরোধে আমাকে একটি শিরোনাম পরিবর্তন করতে হবে, এটি প্রথম অনুরোধে কী করে? এইচটিপিপিপ্লিয়েন্ট স্থিতিশীল হওয়ার পর থেকে এটির কোনও পরিবর্তন আছে কি - যেমন এইচটিটিপিপ্লাইয়েন্ট জোগানো ef ডিফল্টরেকুয়েস্টহাইডার্স ceptএসিপ্টেপ.ক্রিয়ার (); ? উদাহরণস্বরূপ, যদি আমার এমন ব্যবহারকারী থাকে যা টোকেনের মাধ্যমে প্রমাণীকরণ করে তবে সেই টোকেনগুলিকে এপিআই-র অনুরোধে শিরোনাম হিসাবে যুক্ত করা দরকার, যার মধ্যে বিভিন্ন টোকেন রয়েছে। এইচটিটিপিপ্লিনেন্টকে স্ট্যাটিক হিসাবে না রাখার পরে এইচটিডিপিপ্লিনেন্টে এই শিরোনামটি পরিবর্তন করা কি বিরূপ প্রভাব ফেলবে?
ক্রিজওয়াল্ড

যদি আপনাকে এইচটিপিপি্লিয়েন্ট উদাহরণস্বরূপ সদস্য যেমন শিরোনাম / কুকিজ ইত্যাদির প্রয়োজন হয় তবে আপনার কোনও স্ট্যাটিক এইচটিটিপিপ্লিনেন্ট ব্যবহার করা উচিত নয়। অন্যথায়, আপনার উদাহরণ ডেটা (শিরোনাম, কুকিজ) প্রতিটি অনুরোধের জন্য একই হবে - আপনি যা চান তা অবশ্যই নয় NOT
ডেভ ব্ল্যাক

যেহেতু এই ঘটনাটি ... আপনি নিজের পোস্টে যা বর্ণনা করছেন তার বোঝা বিরুদ্ধে আপনি কীভাবে আটকাবেন? ব্যালেন্সার লোড করুন এবং এটিতে আরও সার্ভার নিক্ষেপ করবেন?
ক্রিজওয়াল্ড

@ ক্রিজওয়াল্ড - আমার পোস্টে আমি ব্যবহৃত সমাধানটি লক্ষ্য করেছি। HttpClient এর একটি স্থির উদাহরণ ব্যবহার করুন। যদি আপনাকে এইচটিপিপিপ্লায়েন্টে শিরোনাম / কুকিজ ব্যবহার করতে হয় তবে আমি বিকল্পটি ব্যবহার করব।
ডেভ ব্ল্যাক
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.