تطوير مخططات #C لـ Apache Storm باستخدام أدوات Data Lake لبرنامج Visual Studio

تعرف على كيفية إنشاء مخطط C# Apache Storm باستخدام Azure Data Lake (Apache Hadoop) لبرنامج Visual Studio. يستعرض هذا المستند عملية إنشاء مشروع Storm في Visual Studio واختباره محليّاً وتوزيعه في Apache Storm على مجموعة Azure HDInsight.

ستتعلم أيضاً كيفية إنشاء مخطط مختلط يستخدم مكونات #C وJava.

مخططات #C تستخدم NET 4.5. كما تستخدم Mono للتشغيل على مجموعة HDInsight. للحصول على معلومات حول حالات عدم التوافق المحتملة، راجع توافق Mono. لاستخدام مخطط #C، يجب تحديث حزمة Microsoft.SCP.Net.SDK NuGet التي يستخدمها مشروعك إلى الإصدار 0.10.0.6 أو أحدث. يجب أن يتطابق إصدار الحزمة أيضاً مع الإصدار الرئيسي من Storm المثبَّت على HDInsight.

نسخة HDInsight إصدار Apache Storm إصدار SCP.NET نسخة Mono الافتراضية
3.4 0.10.0.x 0.10.0.x 3.2.8
3.5 1.0.2.x 1.0.0.x 4.2.1
3.6 1.1.0.x 1.0.0.x 4.2.8

المتطلب الأساسي

نظام مجموعة Apache Storm على HDInsight. راجعإنشاء نظام مجموعة Apache Hadoop باستخدام مدخل Microsoft Azure وحدد Storm لنوع Cluster type.

تثبيت Visual Studio

يمكنك تطوير مخطط #C باستخدام SCP.NET باستخدام Visual Studio. الإرشادات الواردة هنا تستخدم Visual Studio 2019، لكن يمكنك أيضاً استخدام الإصدارات السابقة من Visual Studio.

تثبيت أدوات Data Lake لبرنامج Visual Studio

لتثبيت أدوات Data Lake لبرنامج Visual Studio، اتبع الخطوات الواردة في البدء في استخدام أدوات Data Lake لبرنامج Visual Studio.

تثبيت Java

عند إرسال مخطط Storm من Visual Studio، يقوم SCP.NET بإنشاء ملف مضغوط يحتوي على المخطط والتبعيات. تُستخدم Java لإنشاء هذه الملفات المضغوطة؛ لأنها تستخدم تنسيقاً أكثر توافقاً مع المجموعات المستندة إلى Linux.

  1. قم بتثبيت Java Developer Kit (JDK) 7 أو إصدار لاحق في بيئة التطوير الخاصة بك. يمكنك الحصول على Oracle JDK من Oracle. يمكنك أيضاً استخدام توزيعات Java أخرى .

  2. قم بتعيين متغير البيئة JAVA_HOME إلى الدليل الذي يحتوي على Java.

  3. قم بتعيين متغير البيئة PATH ليشمل الدليل %JAVA_HOME%\bin.

يمكنك إنشاء وتشغيل تطبيق وحدة التحكم #C التالي للتحقق من تثبيت Java وJDK بشكل صحيح:

using System;
using System.IO;
namespace ConsoleApplication2
{
   class Program
   {
       static void Main(string[] args)
       {
           string javaHome = Environment.GetEnvironmentVariable("JAVA_HOME");
           if (!string.IsNullOrEmpty(javaHome))
           {
               string jarExe = Path.Combine(javaHome + @"\bin", "jar.exe");
               if (File.Exists(jarExe))
               {
                   Console.WriteLine("JAVA Is Installed properly");
                    return;
               }
               else
               {
                   Console.WriteLine("A valid JAVA JDK is not found. Looks like JRE is installed instead of JDK.");
               }
           }
           else
           {
             Console.WriteLine("A valid JAVA JDK is not found. JAVA_HOME environment variable is not set.");
           }
       }  
   }
}

قوالب Apache Storm

توفر أدوات Data Lake لبرنامج Visual Studio القوالب التالية:

نوع المشروع توضيحات
تطبيق Storm مشروع مخطط Storm فارغ.
نموذج Storm Azure SQL Writer كيفية الكتابة إلى Azure SQL Database.
نموذج Storm Azure Cosmos DB Reader كيف تقرأ من Azure Cosmos DB.
نموذج كاتب Storm Azure Cosmos DB كيفية الكتابة إلى Azure Cosmos DB.
نموذج Storm EventHub Reader كيف تقرأ من مراكز الأحداث.
نموذج Storm EventHub Writer كيف تكتب إلى Azure Event Hubs.
نموذج Storm HBase Reader كيف تقرأ من HBase على مجموعات HDInsight.
نموذج Storm HBase Writer كيف تكتب إلى HBase على مجموعات HDInsight.
نموذج Storm Hybrid كيفية استخدام مكون Java.
نموذج Storm مخطط أساسي لعدد الكلمات.

تحذير

لا تعمل جميع القوالب مع HDInsight المستند إلى Linux. قد لا تكون حزم NuGet المستخدمة بواسطة القوالب متوافقة مع Mono. لتحديد المشكلات المحتملة، راجع توافق Mono واستخدم NET Portability Analyzer.

في الخطوات الواردة في هذا المستند، يمكنك استخدام نوع مشروع Storm Application الأساسي لإنشاء مخطط.

قوالب Apache HBase

قوالب كاتب وقارئ HBase تستخدم واجهة برمجة تطبيقات HBase REST، وليس HBase Java API، للتواصل مع HBase على مجموعة HDInsight.

قوالب EventHub

هام

قد لا يعمل مكون دفق EventHub المستند إلى Java والمضمن في نموذج EventHub Reader مع Storm على HDInsight الإصدار 3.5 أو أحدث. يتوفر إصدار محدث من هذا المكون على GitHub.

للحصول على مثال للمخطط الذي يستخدم هذا المكون ويعمل مع Storm على HDInsight 3.5، راجع GitHub.

إنشاء مخطط #C

لإنشاء مشروع مخطط #C في Visual Studio:

  1. افتح Visual Studio.

  2. من نافذة Start، اختر Create a new project.

  3. في نافذة Create a new project، مرر إلى واختر Storm Application، ثم حدد Next.

  4. في نافذة Configure your new project، أدخل Project name من WordCount، انتقل إلى مسار دليل الموقع أو أنشئه للمشروع، ثم حدد Create.

    Storm application, Configure your new project dialog box, Visual Studio

بعد إنشاء المشروع، يجب أن يكون لديك الملفات التالية:

  • Program.cs: تعريف المخطط لمشروعك. يتم إنشاء المخطط الافتراضي الذي يتكون من دفق واحد ومثبِّت واحد بشكل افتراضي.

  • Spout.cs: مثال على دفق يرسل أرقاماً عشوائية.

  • Bolt.cs: مثال على مثبِّت يحتفظ بعدد الأرقام الصادرة عن الدفق.

عند إنشاء المشروع، تقوم NuGet بتنزيل أحدث حزمة SCP.NET.

تنفيذ الدفق

بعد ذلك، أضف التعليمة البرمجية للدفق والذي يُستخدم لقراءة البيانات في المخطط من مصدر خارجي. ينبعث من هذا الدفق بشكل عشوائي جملة تنتقل إلى المخطط.

  1. افتح Spout.cs. المكونات الرئيسية للدفق هي:

    • NextTuple: يتم استدعاؤه بواسطة Storm عندما يُسمح للدفق بإصدار مجموعات جديدة.

    • Ack (مخطط المعاملات فقط): إقرارات المقابض التي بدأت بواسطة مكونات أخرى في المخطط الخاص بالمجموعات المرسلة من الدفق. يتيح التعرف على مجموعة تتيح للدفق معرفة أنه تمت معالجتها بنجاح بواسطة المكونات النهائية.

    • Fail (مخطط المعاملات فقط): تتعامل مع المجموعات التي تعالج المكونات الأخرى في المخطط بالفشل. يتيح لك تنفيذ طريقة Fail إعادة إرسال المجموعة بحيث يمكن معالجتها مرة أخرى.

  2. استبدل محتويات فئة Spout بالنص التالي:

    private Context ctx;
    private Random r = new Random();
    string[] sentences = new string[] {
        "the cow jumped over the moon",
        "an apple a day keeps the doctor away",
        "four score and seven years ago",
        "snow white and the seven dwarfs",
        "i am at two with nature"
    };
    
    public Spout(Context ctx)
    {
        // Set the instance context
        this.ctx = ctx;
    
        Context.Logger.Info("Generator constructor called");
    
        // Declare Output schema
        Dictionary<string, List<Type>> outputSchema = new Dictionary<string, List<Type>>();
        // The schema for the default output stream is
        // a tuple that contains a string field
        outputSchema.Add("default", new List<Type>() { typeof(string) });
        this.ctx.DeclareComponentSchema(new ComponentStreamSchema(null, outputSchema));
    }
    
    // Get an instance of the spout
    public static Spout Get(Context ctx, Dictionary<string, Object> parms)
    {
        return new Spout(ctx);
    }
    
    public void NextTuple(Dictionary<string, Object> parms)
    {
        Context.Logger.Info("NextTuple enter");
        // The sentence to be emitted
        string sentence;
    
        // Get a random sentence
        sentence = sentences[r.Next(0, sentences.Length - 1)];
        Context.Logger.Info("Emit: {0}", sentence);
        // Emit it
        this.ctx.Emit(new Values(sentence));
    
        Context.Logger.Info("NextTuple exit");
    }
    
    public void Ack(long seqId, Dictionary<string, Object> parms)
    {
        // Only used for transactional topologies
    }
    
    public void Fail(long seqId, Dictionary<string, Object> parms)
    {
        // Only used for transactional topologies
    }
    

تنفيذ المثبتات

الآن قم بإنشاء اثنين من البراغي Storm في هذا المثال:

  1. احذف ملف Bolt.cs الموجود من المشروع.

  2. في Solution Explorer، انقر بزر الماوس الأيمن فوق المشروع، وحدد Add>New item. من القائمة، حدد Storm Bolt، وأدخل Splitter.cs كاسم. في التعليمة البرمجية للملف الجديد، قم بتغيير اسم مساحة الاسم إلىWordCount. ثم كرر هذه العملية لإنشاء المثبِّت الثاني باسم Counter.cs.

    • Splitter.cs: ينفذ التعليمة البرمجية المثبِّت الذي يقسم الجمل إلى كلمات فردية، ويصدر دفقاً جديداً من الكلمات.

    • Counter.cs: ينفذ المثبِّت الذي يعد كل كلمة ويصدر دفقاً جديداً من الكلمات وعدد كل كلمة.

      ملاحظة

      تقرأ هذه المثبتات التدفقات وتكتبها، ولكن يمكنك أيضاً استخدام المثبِّت للتواصل مع مصادر مثل قاعدة بيانات أو خدمة.

  3. افتح Splitter.cs. لديها طريقة واحدة فقط بشكل افتراضي: Execute. يتم استدعاء طريقة Execute عندما يتلقى المثبِّت مجموعة للمعالجة. هنا، يمكنك قراءة المجموعات الواردة ومعالجتها، وإصدار المجموعات الصادرة.

  4. استبدل محتويات فئة Splitter بالتعليمة البرمجية التالية:

    private Context ctx;
    
    // Constructor
    public Splitter(Context ctx)
    {
        Context.Logger.Info("Splitter constructor called");
        this.ctx = ctx;
    
        // Declare Input and Output schemas
        Dictionary<string, List<Type>> inputSchema = new Dictionary<string, List<Type>>();
        // Input contains a tuple with a string field (the sentence)
        inputSchema.Add("default", new List<Type>() { typeof(string) });
        Dictionary<string, List<Type>> outputSchema = new Dictionary<string, List<Type>>();
        // Outbound contains a tuple with a string field (the word)
        outputSchema.Add("default", new List<Type>() { typeof(string) });
        this.ctx.DeclareComponentSchema(new ComponentStreamSchema(inputSchema, outputSchema));
    }
    
    // Get a new instance of the bolt
    public static Splitter Get(Context ctx, Dictionary<string, Object> parms)
    {
        return new Splitter(ctx);
    }
    
    // Called when a new tuple is available
    public void Execute(SCPTuple tuple)
    {
        Context.Logger.Info("Execute enter");
    
        // Get the sentence from the tuple
        string sentence = tuple.GetString(0);
        // Split at space characters
        foreach (string word in sentence.Split(' '))
        {
            Context.Logger.Info("Emit: {0}", word);
            //Emit each word
            this.ctx.Emit(new Values(word));
        }
    
        Context.Logger.Info("Execute exit");
    }
    
  5. افتح Counter.cs، واستبدل محتويات الفئة بالتعليمة البرمجية التالي:

    private Context ctx;
    
    // Dictionary for holding words and counts
    private Dictionary<string, int> counts = new Dictionary<string, int>();
    
    // Constructor
    public Counter(Context ctx)
    {
        Context.Logger.Info("Counter constructor called");
        // Set instance context
        this.ctx = ctx;
    
        // Declare Input and Output schemas
        Dictionary<string, List<Type>> inputSchema = new Dictionary<string, List<Type>>();
        // A tuple containing a string field - the word
        inputSchema.Add("default", new List<Type>() { typeof(string) });
    
        Dictionary<string, List<Type>> outputSchema = new Dictionary<string, List<Type>>();
        // A tuple containing a string and integer field - the word and the word count
        outputSchema.Add("default", new List<Type>() { typeof(string), typeof(int) });
        this.ctx.DeclareComponentSchema(new ComponentStreamSchema(inputSchema, outputSchema));
    }
    
    // Get a new instance
    public static Counter Get(Context ctx, Dictionary<string, Object> parms)
    {
        return new Counter(ctx);
    }
    
    // Called when a new tuple is available
    public void Execute(SCPTuple tuple)
    {
        Context.Logger.Info("Execute enter");
    
        // Get the word from the tuple
        string word = tuple.GetString(0);
        // Do we already have an entry for the word in the dictionary?
        // If no, create one with a count of 0
        int count = counts.ContainsKey(word) ? counts[word] : 0;
        // Increment the count
        count++;
        // Update the count in the dictionary
        counts[word] = count;
    
        Context.Logger.Info("Emit: {0}, count: {1}", word, count);
        // Emit the word and count information
        this.ctx.Emit(Constants.DEFAULT_STREAM_ID, new List<SCPTuple> { tuple }, new Values(word, count));
        Context.Logger.Info("Execute exit");
    }
    

حدد المخطط

يتم ترتيب التدفقات والمثبتات في رسم بياني يحدد كيفية تدفق البيانات بين المكونات. بالنسبة لهذا المخطط، يكون الرسم البياني كما يلي:

Spout and bolt component arrangement diagram, Storm topology

الدفق يُصدِر الجمل التي يتم توزيعها على مثيلات المثبِّت الفاصل. يقسم المثبِّت الفاصل الجمل إلى كلمات، والتي يتم توزيعها على المثبِّت المضاد.

نظراً لأن مثيل Counter يحتوي على عدد الكلمات محليّاً، فأنت تريد التأكد من أن كلمات معينة تتدفق إلى نفس مثيل مثبت Counter. كل مثيل يتتبع كلمات معينة. نظراً لأن المثبِّت الفاصل لا يحتفظ بأي حالة، فلا يهم حقّاً مثيل الخائن الذي يتلقى الجملة.

افتح Program.cs. الطريقة المهمة هي GetTopologyBuilder، والتي تُستخدم لتحديد المخطط الذي تم إرساله إلى Storm. استبدل محتويات GetTopologyBuilder بالتعليمة البرمجية التالية لتنفيذ المخطط الموضح سابقاً:

// Create a new topology named 'WordCount'
TopologyBuilder topologyBuilder = new TopologyBuilder(
    "WordCount" + DateTime.Now.ToString("yyyyMMddHHmmss"));

// Add the spout to the topology.
// Name the component 'sentences'
// Name the field that is emitted as 'sentence'
topologyBuilder.SetSpout(
    "sentences",
    Spout.Get,
    new Dictionary<string, List<string>>()
    {
        {Constants.DEFAULT_STREAM_ID, new List<string>(){"sentence"}}
    },
    1);
// Add the splitter bolt to the topology.
// Name the component 'splitter'
// Name the field that is emitted 'word'
// Use suffleGrouping to distribute incoming tuples
//   from the 'sentences' spout across instances
//   of the splitter
topologyBuilder.SetBolt(
    "splitter",
    Splitter.Get,
    new Dictionary<string, List<string>>()
    {
        {Constants.DEFAULT_STREAM_ID, new List<string>(){"word"}}
    },
    1).shuffleGrouping("sentences");

// Add the counter bolt to the topology.
// Name the component 'counter'
// Name the fields that are emitted 'word' and 'count'
// Use fieldsGrouping to ensure that tuples are routed
//   to counter instances based on the contents of field
//   position 0 (the word). This could also have been
//   List<string>(){"word"}.
//   This ensures that the word 'jumped', for example, will always
//   go to the same instance
topologyBuilder.SetBolt(
    "counter",
    Counter.Get,
    new Dictionary<string, List<string>>()
    {
        {Constants.DEFAULT_STREAM_ID, new List<string>(){"word", "count"}}
    },
    1).fieldsGrouping("splitter", new List<int>() { 0 });

// Add topology config
topologyBuilder.SetTopologyConfig(new Dictionary<string, string>()
{
    {"topology.kryo.register","[\"[B\"]"}
});

return topologyBuilder;

أرسل المخطط

أنت الآن جاهز لإرسال المخطط إلى مجموعة HDInsight الخاصة بك.

  1. انتقل إلى View>Server Explorer.

  2. انقر بزر الماوس الأيمن فوق Azure، وحدد Connect to Microsoft Azure Subscription... ، وأكمل عملية تسجيل الدخول.

  3. في Solution Explorer، انقر بزر الماوس الأيمن فوق المشروع واختر إرسال إلى Storm على HDInsight.

  4. في مربع الحوار Submit Topology، ضمن القائمة المنسدلة Storm Cluster، اختر Storm على مجموعة HDInsight، ثم حدد Submit. يمكنك التحقق مما إذا كان الإرسال ناجحاً من خلال عرض جزء Output.

    عندما يتم إرسال المخطط بنجاح، يجب أن تظهر نافذة Storm Topologies View للمجموعة. اختر مخطط WordCount من القائمة لعرض معلومات حول المخطط الجاري.

    Storm topology view window, HDInsight cluster, Visual Studio

    ملاحظة

    يمكنك أيضاً عرض Storm Topologies من Server Explorer. قم بتوسيع Azure>HDInsight، وانقر بزر الماوس الأيمن فوق Storm على مجموعة HDInsight، ثم اختر View Storm Topologies.

    لعرض معلومات حول المكونات في المخطط، حدد مكوناً في الرسم التخطيطي.

  5. في قسم Topology Summary، حدد Kill لإيقاف المخطط.

    ملاحظة

    يستمر مخطط Storm في العمل حتى يتم إلغاء تنشيطه أو حذف المجموعة.

مخطط المعاملات

المخطط السابق غير متعلق بالمعاملات. لا تنفذ المكونات الموجودة في المخطط وظائف إعادة تشغيل الرسائل. للحصول على مثال لمخطط المعاملات، قم بإنشاء مشروع وحدد Storm Sample كنوع المشروع.

يقوم مخطط المعاملات بتنفيذ ما يلي لدعم إعادة تشغيل البيانات:

  • التخزين المؤقت لبيانات التعريف: يجب أن يخزن الدفق بيانات التعريف حول البيانات المنبعثة، بحيث يمكن استرداد البيانات وانبعاثها مرة أخرى في حالة حدوث فشل. نظراً لأن البيانات المنبعثة من النموذج صغيرة، يتم تخزين البيانات الأولية لكل مجموعة في قاموس لإعادة التشغيل.

  • Ack: يمكن لكل مثبت في المخطط استدعاء this.ctx.Ack(tuple) للإقرار بأنه قد عالج مجموعة بنجاح. عندما تتعرف جميع المثبتات على المجموعة، يتم استدعاء طريقة الدفقAck. تسمح الطريقة Ack للدفق بإزالة البيانات التي تم تخزينها مؤقتاً لإعادة التشغيل.

  • Fail: يمكن لكل مثبت استدعاء this.ctx.Fail(tuple) للإشارة إلى فشل معالجة المجموعة. ينتشر الفشل إلى طريقة الدفق Fail، حيث يمكن إعادة تشغيل المجموعة باستخدام بيانات التعريف المخزنة مؤقتاً.

  • Sequence ID: عند إصدار مجموعة، يمكن تحديد معرف تسلسل فريد. تحدد هذه القيمة المجموعة الخاصة بمعالجة إعادة التشغيل (AckوFail). على سبيل المثال، يستخدم الدفق في مشروع Storm Sample استدعاء الطريقة التالي عند إصدار البيانات:

    this.ctx.Emit(Constants.DEFAULT_STREAM_ID, new Values(sentence), lastSeqId);

    يرسل هذه التعليمة البرمجية مجموعة تحتوي على جملة إلى التدفق الافتراضية، مع قيمة معرف التسلسل المضمنة في lastSeqId. في هذا المثال، يتم زيادة lastSeqId لكل مجموعة يتم إصدارها.

كما هو موضح في مشروع Storm Sample، يمكن تعيين ما إذا كان المكون معاملاً في وقت التشغيل، بناءً على التكوين.

مخطط مختلط مع #C وJava

يمكنك أيضاً استخدام أدوات Data Lake لبرنامج Visual Studio لإنشاء مخطط مختلط، حيث تكون بعض المكونات عبارة عن #C والبعض الآخر Java.

للحصول على مثال للمخطط المختلط، قم بإنشاء مشروع وحدد Storm Hybrid Sample. يوضح هذا النوع من النماذج المفاهيم التالية:

  • Java spout و #C bolt: محدد في الفئة HybridTopology_javaSpout_csharpBolt.

    يتم تحديد إصدار المعاملات في فئة HybridTopologyTx_javaSpout_csharpBolt.

  • C# spout وJava bolt: محدد في الفئة HybridTopology_csharpSpout_javaBolt.

    يتم تحديد إصدار المعاملات في فئة HybridTopologyTx_csharpSpout_javaBolt.

    ملاحظة

    يوضح هذا الإصدار أيضاً كيفية استخدام كود Clojure من ملف نصي كمكون Java.

لتبديل المخطط المستخدم عند إرسال المشروع، انقل العبارة [Active(true)] إلى المخطط الذي تريد استخدامه، قبل إرساله إلى المجموعة.

ملاحظة

يتم توفير جميع ملفات Java المطلوبة كجزء من هذا المشروع في المجلد JavaDependency.

ضع في اعتبارك ما يأتي عند إنشاء مخطط مختلط وإرساله:

  • استخدم JavaComponentConstructor لإنشاء مثيل لفئة Java لدفق أو مثبِّت.

  • استخدم microsoft.scp.storm.multilang.CustomizedInteropJSONSerializer لتسلسل البيانات داخل أو خارج مكونات Java من كائنات Java إلى JSON.

  • عند إرسال المخطط إلى الخادم، يجب عليك استخدام خيار Additional configurations لتحديد Java File paths. يجب أن يكون المسار المحدد هو الدليل الذي يحتوي على ملفات JAR التي تحتوي على فئات Java الخاصة بك.

مراكز أحداث Azure

يقدم الإصدار 0.9.4.203 من SCP.NET فئة وطريقة جديدة خصوصاً للعمل مع صنبور Event Hub (صنبور Java يقرأ من Event Hubs). عند إنشاء مخطط يستخدم صنبور Event Hub (على سبيل المثال، باستخدام نموذج Storm EventHub Reader Sample)، استخدم واجهات برمجة التطبيقات التالية:

  • EventHubSpoutConfig class: إنشاء كائن يحتوي على تكوين مكون spout.

  • طريقة TopologyBuilder.SetEventHubSpout: إضافة مكون صنبور Event Hub إلى المخطط.

ملاحظة

لا يزال يتعين عليك استخدام CustomizedInteropJSONSerializer لتسلسل البيانات التي ينتجها الدفق.

استخدم ConfigurationManager

لا تستخدم ConfigurationManager لاسترداد قيم التكوين من المثبِّت ومكونات الدفق. يمكن أن يؤدي القيام بذلك إلى استثناء مؤشر فارغ. بدلاً من ذلك، قم بتمرير التكوين الخاص بمشروعك إلى مخطط Storm كزوج من المفاتيح والقيمة في سياق المخطط. يجب أن يقوم كل مكون يعتمد على قيم التكوين باستردادها من السياق أثناء التكوين.

توضح التعليمة البرمجية التالية كيفية استرداد هذه القيم:

public class MyComponent : ISCPBolt
{
    // To hold configuration information loaded from context
    Configuration configuration;
    ...
    public MyComponent(Context ctx, Dictionary<string, Object> parms)
    {
        // Save a copy of the context for this component instance
        this.ctx = ctx;
        // If it exists, load the configuration for the component
        if(parms.ContainsKey(Constants.USER_CONFIG))
        {
            this.configuration = parms[Constants.USER_CONFIG] 
                as System.Configuration.Configuration;
        }
        // Retrieve the value of "Foo" from configuration
        var foo = this.configuration.AppSettings.Settings["Foo"].Value;
    }
    ...
}

إذا كنت تستخدم طريقة Get لإرجاع مثيل للمكون الخاص بك، فيجب عليك التأكد من أنه يمرر كلّاً من معلمات Context وDictionary<string, Object> إلى المنشئ. المثال التالي هو طريقة Get أساسية تمرر هذه القيم بشكل صحيح:

public static MyComponent Get(Context ctx, Dictionary<string, Object> parms)
{
    return new MyComponent(ctx, parms);
}

كيفية تحديث SCP.NET

الإصدارات الأخيرة من ترقية حزمة دعم SCP.NET من خلال NuGet. عند توفر تحديث جديد، ستتلقى إشعاراً بالترقية. للتحقق يدويّاً من وجود ترقية، اتبع الخطوات التالية:

  1. في Solution Explorer، انقر بزر الماوس الأيمن فوق المشروع وحدد Manage NuGet Packages.

  2. من مدير الحزمة، حدد Updates. في حالة توفر تحديث لحزمة دعم SCP.NET، يتم سردها. حدد Update للحزمة، ثم في مربع الحوار Preview Changes، حدد OK لتثبيتها.

هام

إذا تم إنشاء مشروعك باستخدام إصدار سابق من SCP.NET لا يستخدم NuGet، فيجب عليك تنفيذ الخطوات التالية للتحديث إلى إصدار أحدث:

  1. في Solution Explorer، انقر بزر الماوس الأيمن فوق المشروع وحدد Manage NuGet Packages.
  2. باستخدام حقل Search، ابحث عن، ثم أضف Microsoft.SCP.Net.SDK إلى المشروع.

استكشاف المشكلات الشائعة المتعلقة بالمخطط وإصلاحها

استثناءات المؤشر الفارغة

عند استخدام مخطط #C مع مجموعة HDInsight المستندة إلى Linux، فإن مكونات المثبِّت والصنبور التي تستخدم ConfigurationManager لقراءة إعدادات التكوين في وقت التشغيل قد ترجع استثناءات مؤشر فارغ.

يتم تمرير التكوين الخاص بمشروعك إلى مخطط Storm كزوج من المفاتيح والقيمة في سياق المخطط. يمكن استرجاعها من كائن القاموس الذي تم تمريره إلى مكوناتك عند تهيئتها.

لمزيد من المعلومات، راجع قسم Use ConfigurationManager من هذا المستند.

System.TypeLoadException

عندما تستخدم مخطط #C مع مجموعة HDInsight المستندة إلى Linux، فقد تصادف الخطأ الآتي:

System.TypeLoadException: Failure has occurred while loading a type.

يحدث هذا الخطأ عند استخدام ثنائي غير متوافق مع إصدار .NET الذي يدعمه Mono.

بالنسبة لمجموعات HDInsight المستندة إلى Linux، تأكد من أن مشروعك يستخدم ثنائيات مجمعة لـ .NET 4.5.

اختبر المخطط محليّاً

على الرغم من أنه من السهل نشر المخطط في كتلة، فقد تحتاج في بعض الحالات إلى اختبار المخطط محليّاً. استخدم الخطوات التالية لتشغيل واختبار مثال المخطط في هذه المقالة محليّاً في بيئة التطوير الخاصة بك.

تحذير

يعمل الاختبار المحلي فقط للمخطط الأساسي #C فقط. لا يمكنك استخدام الاختبار المحلي للمخطط المختلط أو الهياكل التي تستخدم تدفقات متعددة.

  1. في Solution Explorer، انقر بزر الماوس الأيمن فوق المشروع وحدد Properties. في خصائص المشروع. ثم قم بتغيير Output type إلى Console Application.

    HDInsight Storm application, project properties, Output type

    ملاحظة

    تذكر تغيير Output type مرة أخرى إلى Class Library قبل نشر المخطط في مجموعة.

  2. في Solution Explorer، انقر بزر الماوس الأيمن فوق المشروع، ثم حدد Add>New Item. حدد Class، وأدخل LocalTest.cs كاسم للفئة. أخيراً، حدد Add.

  3. افتح LocalTest.cs، وأضف عبارة using التالية في الأعلى:

    using Microsoft.SCP;
    
  4. استخدم التعليمة البرمجية التالي كمحتويات لفئة LocalTest:

    // Drives the topology components
    public void RunTestCase()
    {
        // An empty dictionary for use when creating components
        Dictionary<string, Object> emptyDictionary = new Dictionary<string, object>();
    
        #region Test the spout
        {
            Console.WriteLine("Starting spout");
            // LocalContext is a local-mode context that can be used to initialize
            // components in the development environment.
            LocalContext spoutCtx = LocalContext.Get();
            // Get a new instance of the spout, using the local context
            Spout sentences = Spout.Get(spoutCtx, emptyDictionary);
    
            // Emit 10 tuples
            for (int i = 0; i < 10; i++)
            {
                sentences.NextTuple(emptyDictionary);
            }
            // Use LocalContext to persist the data stream to file
            spoutCtx.WriteMsgQueueToFile("sentences.txt");
            Console.WriteLine("Spout finished");
        }
        #endregion
    
        #region Test the splitter bolt
        {
            Console.WriteLine("Starting splitter bolt");
            // LocalContext is a local-mode context that can be used to initialize
            // components in the development environment.
            LocalContext splitterCtx = LocalContext.Get();
            // Get a new instance of the bolt
            Splitter splitter = Splitter.Get(splitterCtx, emptyDictionary);
    
            // Set the data stream to the data created by the spout
            splitterCtx.ReadFromFileToMsgQueue("sentences.txt");
            // Get a batch of tuples from the stream
            List<SCPTuple> batch = splitterCtx.RecvFromMsgQueue();
            // Process each tuple in the batch
            foreach (SCPTuple tuple in batch)
            {
                splitter.Execute(tuple);
            }
            // Use LocalContext to persist the data stream to file
            splitterCtx.WriteMsgQueueToFile("splitter.txt");
            Console.WriteLine("Splitter bolt finished");
        }
        #endregion
    
        #region Test the counter bolt
        {
            Console.WriteLine("Starting counter bolt");
            // LocalContext is a local-mode context that can be used to initialize
            // components in the development environment.
            LocalContext counterCtx = LocalContext.Get();
            // Get a new instance of the bolt
            Counter counter = Counter.Get(counterCtx, emptyDictionary);
    
            // Set the data stream to the data created by splitter bolt
            counterCtx.ReadFromFileToMsgQueue("splitter.txt");
            // Get a batch of tuples from the stream
            List<SCPTuple> batch = counterCtx.RecvFromMsgQueue();
            // Process each tuple in the batch
            foreach (SCPTuple tuple in batch)
            {
                counter.Execute(tuple);
            }
            // Use LocalContext to persist the data stream to file
            counterCtx.WriteMsgQueueToFile("counter.txt");
            Console.WriteLine("Counter bolt finished");
        }
        #endregion
    }
    

    خذ لحظة للقراءة من خلال تعليقات التعليمات البرمجية. يستخدم هذه التعليمة البرمجية LocalContext لتشغيل المكونات في بيئة التطوير. يستمر تدفق البيانات بين المكونات إلى ملفات نصية على محرك الأقراص المحلي.

  5. افتح Program.cs، وأضف التعليمة البرمجية التالية إلى طريقة Main:

    Console.WriteLine("Starting tests");
    System.Environment.SetEnvironmentVariable("microsoft.scp.logPrefix", "WordCount-LocalTest");
    // Initialize the runtime
    SCPRuntime.Initialize();
    
    //If we are not running under the local context, throw an error
    if (Context.pluginType != SCPPluginType.SCP_NET_LOCAL)
    {
        throw new Exception(string.Format("unexpected pluginType: {0}", Context.pluginType));
    }
    // Create test instance
    LocalTest tests = new LocalTest();
    // Run tests
    tests.RunTestCase();
    Console.WriteLine("Tests finished");
    Console.ReadKey();
    
  6. احفظ التغييرات، ثم حدد F5 أو اختر تصحيح>بدء التصحيح لبدء المشروع. يجب أن تظهر نافذة وحدة التحكم، وتسجيل الحالة مع تقدم الاختبارات. عندما يظهر Tests finished، حدد أي مفتاح لإغلاق النافذة.

  7. استخدم Windows Explorer لتحديد موقع الدليل الذي يحتوي على مشروعك. (على سبيل المثال: C:\Users\your_user_name>\source\repos\WordCount\<WordCount.) ثم في هذا الدليل ، افتح سلة المهملات ، ثم حدد تصحيح. يجب أن تشاهد الملفات النصية التي تم إنتاجها عند إجراء الاختبارات: rases.txt وcounter.txt وsplitter.txt. افتح كل ملف نصي وافحص البيانات.

    ملاحظة

    تستمر بيانات السلسلة كمصفوفة من القيم العشرية في هذه الملفات. على سبيل المثال، يمثل [[97,103,111]] في ملف splitter.txt الكلمة ago.

ملاحظة

تأكد من إعادة تعيين Project type إلى Class Library في خصائص المشروع قبل النشر إلى Storm على مجموعة HDInsight.

معلومات السجل

يمكنك بسهولة تسجيل المعلومات من مكونات المخطط الخاص بك باستخدام Context.Logger. على سبيل المثال، يقوم الأمر التالي بإنشاء إدخال سجل إعلامي:

Context.Logger.Info("Component started");

يمكن عرض المعلومات المسجلة من Hadoop Service Log، الموجود في Server Explorer. قم بتوسيع إدخال Storm على مجموعة HDInsight، ثم قم بتوسيع سجل خدمة Hadoop. أخيراً، حدد ملف السجل لعرضه.

ملاحظة

يتم تخزين السجلات في حساب تخزين Azure الذي يستخدمه نظام المجموعة الخاص بك. لعرض السجلات في Visual Studio، يجب عليك تسجيل الدخول إلى اشتراك Azure الذي يمتلك حساب التخزين.

عرض معلومات الخطأ

لعرض الأخطاء التي حدثت في مخطط قيد التشغيل، استخدم الخطوات التالية:

  1. من Server Explorer، انقر بزر الماوس الأيمن فوق Storm على مجموعة HDInsight، وحدد View Storm Topologies.

    بالنسبة إلى Spout وBolts، يحتوي عمود Last Error على معلومات عن الخطأ الأخير.

  2. حدد Spout ID أو Bolt ID للمكون الذي يحتوي على خطأ مدرج. تعرض صفحة التفاصيل معلومات خطأ إضافية في قسم الأخطاء أسفل الصفحة.

  3. للحصول على مزيد من المعلومات، حدد Port من قسم Executors بالصفحة، لمشاهدة سجل عمال Storm خلال الدقائق القليلة الماضية.

أخطاء إرسال المخطط

إذا صادفت أخطاء أثناء إرسال المخطط إلى HDInsight، فيمكنك العثور على سجلات لمكونات جانب الخادم التي تتعامل مع إرسال المخطط على مجموعة HDInsight الخاصة بك. لتنزيل هذه السجلات، استخدم الأمر التالي من سطر الأوامر:

scp sshuser@clustername-ssh.azurehdinsight.net:/var/log/hdinsight-scpwebapi/hdinsight-scpwebapi.out .

استبدال sshuser بحساب مستخدم SSH للمجموعة. استبدال clustername باسم مجموعة HDInsight. لمزيد من المعلومات حول استخدام scp وssh مع HDInsight، راجع استخدام SSH مع HDInsight .

يمكن أن تفشل عمليات الإرسال لأسباب متعددة:

  • لم يتم تثبيت JDK أو أنه ليس في المسار.
  • لا يتم تضمين تبعيات Java المطلوبة في الإرسال.
  • التبعيات غير متوافقة.
  • يتم تكرار أسماء المخطط.

إذا كان ملف السجل hdinsight-scpwebapi.out يحتوي على FileNotFoundException، فقد يكون سبب الاستثناء هو الشروط التالية:

  • JDK ليس في مسار بيئة التطوير. تحقق من تثبيت JDK في بيئة التطوير، وأن %JAVA_HOME%/bin موجود في المسار.
  • أنت تفتقد تبعية Java. تأكد من تضمين أي ملفات .jar مطلوبة كجزء من الإرسال.

الخطوات التالية

للحصول على مثال لمعالجة البيانات من Event Hubs، راجع معالجة الأحداث من مراكز الأحداث باستخدام Storm على HDInsight .

للحصول على مثال لمخطط #C التي تقسم بيانات الدفق إلى تدفقات متعددة، راجع مثال #C Storm .

لاكتشاف المزيد من المعلومات حول إنشاء مخطط #C، راجع GitHub.

لمزيد من طرق العمل مع HDInsight والمزيد من Storm على عينات HDInsight، راجع المستندات التالية:

Microsoft SCP.NET

Apache Storm على HDInsight

Apache Hadoop على HDInsight

Apache HBase على HDInsight