سرد موارد تخزين Azure في C++
عمليات إدخال القوائم مفتاح العديد من سيناريوهات التطوير باستخدام Azure Storage. توضح هذه المقالة كيفية تعداد العناصر في Azure Storage باستخدام واجهات برمجة التطبيقات لإدخال القوائم المتوفرة في Microsoft Azure Storage Client Library لـ C++.
ملاحظة
يستهدف هذا الدليل Microsoft Azure Storage Client Library لـ C++ الإصدار 2.x، والذي يتوفر عبر NuGet أو GitHub.
توفر Storage Client Library مجموعة متنوعة من أساليب سرد أو الاستعلام عن العناصر في Azure Storage. تتناول هذه المقالة السيناريوهات التالية:
- سرد الحاويات في حساب
- سرد الكائنات الثنائية الكبيرة الحجم في حاوية أو دليل كائن ثنائي كبير الحجم ظاهري
- سرد قوائم الانتظار في حساب
- سرد الجداول في حساب
- الاستعلام عن الكيانات في جدول
تُوضح كل من هذه الطرق باستخدام التحميلات الزائدة المختلفة للسيناريوهات المختلفة.
غير المتزامن مقابل المتزامن
بما أن Storage Client Library لـ C++ تعتمد على مكتبة C++ REST، فإننا طبيعياً ندعم العمليات غير المتزامنة باستخدام pplx::task. على سبيل المثال:
pplx::task<list_blob_item_segment> list_blobs_segmented_async(continuation_token& token) const;
تتضمن العمليات المتزامنة العمليات غير المتزامنة المقابلة:
list_blob_item_segment list_blobs_segmented(const continuation_token& token) const
{
return list_blobs_segmented_async(token).get();
}
إذا كنت تعمل باستخدام خدمات أو تطبيقات ذات مؤشرات ترابط متعددة، فمن المستحسن استخدام واجهات برمجة التطبيقات غير المتزامنة مباشرة بدلاً من إنشاء مؤشر ترابط لاستدعاء واجهات برمجة التطبيقات المتزامنة، ما قد يؤثر بشكل كبير على أدائك.
إدخال قائمة مجزأ
يتطلب تغيير سعة التخزين على السحابة إدخالاً مجزأً. على سبيل المثال، يمكنك الحصول على أكثر من مليون كائن ثنائي كبير الحجم في حاوية Azure blob أو عن طريق أكثر من مليار كائن في Azure Table. هذه ليست أرقام نظرية، ولكن حالات استخدام العملاء في الوقت الحقيقي.
لذلك، فإنه ليس من العملي سرد كل العناصر في استجابة واحدة. وبدلاً من ذلك، يمكنك سرد العناصر باستخدام الترحيل. تحتوي كل API لإدخال قائمة على حمل زائد .
تتضمن الاستجابة لعملية إدخال القوائم المُجزأ ما يلي:
- _segment، الذي يحتوي على مجموعة النتائج التي تم إرجاعها لاستدعاء واحد لواجهة برمجة تطبيقات إدخال القوائم.
- continuation_token، الذي يرسل إلى الاستدعاء التالي من أجل الحصول على الصفحة التالية من النتائج. في حالة عدم وجود أي نتائج أخرى لإرجاعها، يكون الرمز المميز للمتابعة فارغاً.
على سبيل المثال، قد يبدو الاستدعاء النموذجي لسرد كافة الكائنات الثنائية الكبيرة الحجم في حاوية مثل التعليمات البرمجية المتكررة التالية. تتوفر التعليمة البرمجية في عيناتنا:
// List blobs in the blob container
azure::storage::continuation_token token;
do
{
azure::storage::list_blob_item_segment segment = container.list_blobs_segmented(token);
for (auto it = segment.results().cbegin(); it != segment.results().cend(); ++it)
{
if (it->is_blob())
{
process_blob(it->as_blob());
}
else
{
process_directory(it->as_directory());
}
}
token = segment.continuation_token();
}
while (!token.empty());
لاحظ أنه يمكن التحكم في عدد النتائج التي يتم إرجاعها من الصفحة بواسطة المعلّمة max_results في الحمل الزائد لكل واجهة برمجة تطبيقات، على سبيل المثال:
list_blob_item_segment list_blobs_segmented(const utility::string_t& prefix, bool use_flat_blob_listing,
blob_listing_details::values includes, int max_results, const continuation_token& token,
const blob_request_options& options, operation_context context)
إذا لم تحدد المعلمة max_results، فسيتم إرجاع القيمة القصوى الافتراضية التي تصل إلى 5000 في صفحة واحدة.
لاحظ أيضاً أن استعلام بالمقارنة مع تخزين Azure Table قد لا يُرجع أي سجلات، أو قد يُرجع سجلات أقل من قيمة معلّمة max_results التي حددتها، حتى إذا لم يكن الرمز المميز للاستمرار فارغاً. قد يكون أحد الأسباب أن الاستعلام لم يكتمل في خمس ثوان. طالما أن الرمز المميز للمتابعة ليس فارغاً، يجب أن يستمر الاستعلام، ويجب ألا تفترض التعليمة البرمجية حجم نتائج المقطع.
نمط الترميز الموصى به لمعظم السيناريوهات هو الإدخال المُجزأ للقوائم، والذي يتيح التقدم الصريح لإدخال القوائم أو الاستعلام، وكيفية استجابة الخدمة لكل طلب. خاص بخدمات أو تطبيقات C++، قد يساعد التحكم في تقدم إدخال القوائم على مستوى أقل على التحكم في الذاكرة والأداء.
إدخال القوائم الذي يتطلب معالجة حاسوبية فائقة
الإصدارات السابقة من Storage Client Library لـ C++(الإصدارات من 0.5.0 معاينة والإصدارات السابقة) بما في ذلك واجهات برمجة التطبيقات لإدخال قائمة غير مُجزأ للجداول وقوائم الانتظار، كما في المثال التالي:
std::vector<cloud_table> list_tables(const utility::string_t& prefix) const;
std::vector<table_entity> execute_query(const table_query& query) const;
std::vector<cloud_queue> list_queues() const;
تم تطبيق هذه الطرق كبرامج تضمين لواجهات برمجة التطبيقات المقسمة. لكل استجابة إدخال قوائم مُجزأ، تلحق التعليمة البرمجية النتائج بخط متجه وترجع جميع النتائج بعد مسح الحاويات بالكامل.
قد ينجح هذا الأسلوب عندما يحتوي حساب storage أو table على عدد صغير من العناصر. لكن، مع زيادة عدد العناصر، ستزيد الذاكرة المطلوبة بدون حد؛ حيث إن كل النتائج تبقى في الذاكرة. يمكن أن تستغرق عملية إدخال القائمة الواحدة وقتاً طويلاً جداً، وهو شيء لم يكن صاحب الاستدعاء على علم به.
واجهات برمجة تطبيقات إدخال القوائم الذي يتطلب معالجة حاسوبية فائقة في SDK غير موجودة في C # أو Java أو بيئة JavaScript Node.js. لتجنب حدوث أي مشاكل ممكنة لاستخدام واجهات برمجة تطبيقات إدخال القوائم الذي يتطلب معالجة حاسوبية فائقة هذه، قمنا بإزالتها في الإصدار 0.6.0 (معاينة).
إذا كانت التعليمة البرمجية تستدعي واجهات برمجة التطبيقات التي تتطلب معالجة حاسوبية فائقة هذه، فلاحظ التالي:
std::vector<azure::storage::table_entity> entities = table.execute_query(query);
for (auto it = entities.cbegin(); it != entities.cend(); ++it)
{
process_entity(*it);
}
بعد ذلك، يجب تعديل التعليمة البرمجية لاستخدام واجهات برمجة التطبيقات للإدخال المُجزأ للقوائم:
azure::storage::continuation_token token;
do
{
azure::storage::table_query_segment segment = table.execute_query_segmented(query, token);
for (auto it = segment.results().cbegin(); it != segment.results().cend(); ++it)
{
process_entity(*it);
}
token = segment.continuation_token();
} while (!token.empty());
بتحديد المعلّمة max_results للجزء، يمكنك الموازنة بين عدد الطلبات واستخدام الذاكرة لتلبية اعتبارات الأداء لتطبيقك.
بجانب ذلك، إذا كنت تستخدم واجهات برمجة تطبيقات للإدخال المُجزأ للقوائم، ولكنك تخزن البيانات في مجموعة محلية بأسلوب "المعالجة الحاسوبية الفائقة"، فإننا نوصي بشدة أيضاً بإعادة بناء التعليمات البرمجية للتعامل مع تخزين البيانات في مجموعة محلية بعناية على نطاق واسع.
إدخال غير محدود للقوائم
على الرغم من الإدخال غير المحدود للقوائم قد أثار مشكلات محتملة، فإنه يلائم الحالات حيث لا يوجد الكثير من العناصر في الحاوية.
إذا كنت تستخدم أيضاً C# أو Oracle Java SDKs، فيجب أن تكون على دراية بنموذج البرمجة Enumerable، الذي يقدم أسلوب الإدخال غير المحدود للقوائم، حيث يتم إحضار البيانات في إزاحة معينة فقط إذا كان ذلك مطلوباً. في C++، يوفر القالب القائم على العداد أيضا نهجاً مماثلاً.
تبدو واجهة برمجة تطبيقات الإدخال غير المحدود للقوائم، والتي تستخدم list_blobs كمثال، كما يلي:
list_blob_item_iterator list_blobs() const;
قد تبدو القصاصة البرمجية النموذجية التي تستخدم نمط الإدخال غير المحدود للقوائم كما يلي:
// List blobs in the blob container
azure::storage::list_blob_item_iterator end_of_results;
for (auto it = container.list_blobs(); it != end_of_results; ++it)
{
if (it->is_blob())
{
process_blob(it->as_blob());
}
else
{
process_directory(it->as_directory());
}
}
لاحظ أن الإدخال غير المحدود للقوائم متوفر فقط في وضع التزامن.
بالمقارنة مع إدخال القوائم الذي يتطلب معالجة حاسوبية فائقة، ويحضر الإدخال غير المحدود للقوائم البيانات فقط عند الضرورة. إنه يُحضر البيانات من Azure Storage في الخلفية فقط عندما يتحرك العداد التالي إلى الجزء الذي يليه. لذلك، يتم التحكم في استخدام الذاكرة بحجم محدد، والعملية سريعة.
يتم تضمين واجهات برمجة التطبيقات للإدخال غير المحدود للقوائم في Storage Client Library for C++ في الإصدار 2.2.0.
الختام
في هذه المقالة، ناقشنا التحميلات الزائدة المختلفة لواجهات برمجة تطبيقات إدخال القوائم للعناصر المختلفة في Storage Client Library لـ C++ . للتلخيص:
- يوصى بشدة بـواجهات برمجة التطبيقات غير المتزامنة للسيناريوهات ذات مؤشرات ترابط المتعددة.
- يوصى بالإدخال المُجزأ للقوائم لمعظم السيناريوهات.
- يتوفر الإدخال غير المحدود للقوائم في المكتبة كبرنامج تضمين ملائم في سيناريوهات متزامنة.
- لا ينصح بالإدخال الذي يتطلب معالجة حاسوبية فائقة وتمت إزالته من المكتبة.
الخطوات التالية
لمزيد من المعلومات حول Azure Storage وClient Library لـ C++، راجع الموارد التالية.