c# شرح - أفضل الممارسات لتنفيذ تغذية البيانات المالية الحية الكمون منخفضة باستخدام WCF؟




tutorial cat (7)

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

كنت أفكر في استخدام نوع من موفر بيانات الدفق ، واحد يستخدم في الصوت أو الفيديو ، ولكن إرسال تحديثات الموجز بدلاً من ذلك.

سوف نقدر أي فكرة حول هذا الموضوع ، أو أي أمثلة في العالم الحقيقي

تحديث:

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


Answers

في الماضي كنت تستخدم Tibco rv أو مآخذ الخام لتدفق الأسعار / الأسعار ، حيث يتوقع تحديثات عالية التردد. في هذه الحالة ، غالبًا ما يكون العميل (أو في الواقع المستخدم) هو الحد (نظرًا لأن هناك العديد من التحديثات التي يمكن للمستخدم معالجتها) ، وهذا بالتالي مثال على المكان الذي يمكنك "فقده" للبيانات. في هذه الحالة ، يمكن استخدام وسيط خدمة جانب العميل لخنق التحديثات.

إذا تم استخدام النظام للتداول الآلي أو HFT ، فقد ثبت أن منتجات مثل 29West LatencyBuster تعمل بشكل جيد وتقدم خدمة الرسائل المضمونة.


ما مدى انخفاض "الكمون المنخفض" ومدى انشغال "المكثف"؟ يجب أن تكون لديك فكرة عن ما تسعى إليه لاختيار المقاربة الصحيحة.

يمكنني تزويدك ببعض الأجهزة التي تستجيب إلى 100٪ من جميع الطلبات داخل ، على سبيل المثال ، 20 وحدة حتى تصل إلى الحد الأقصى من قدرة جهاز الشبكة الخاص بك ، ولكنها لن تستخدم WCF كثيرًا على الإطلاق.

لتقريب عريض جدا ، أود أن أقول أن أشياء مثل WCF هي عالية المستوى للغاية ، وسهولة الاستخدام ، والتجريد من أجل المنفعة للمبرمج مقابل الأداء (الكمون / الإنتاجية). سواء أكان يتاجرون به كثيرًا حتى يحتاج تطبيقك إلى أرقام حقيقية.

الحد الأدنى لبروتوكول بروتوكول الإنترنت (الكمون) الأدنى ، والحد الأدنى من الحمل في الاستخدام واسع النطاق هو UDP - وهذا هو السبب في استخدامه لأشياء مثل DNS و NTP. إنه قابل للتحجيم للغاية على الخادم ، لأن الخادم لا يحتاج إلى الاحتفاظ بأي حالة ، وهو سهل التطبيق على أي نظام أساسي تقريبًا. ولكنك تحتاج إلى التفكير في حزم الشبكة بدلاً من كائنات .NET. هل يمكنك الحصول على برنامج العميل النهائي أيضًا؟


تسأل تحديدًا عن "خلاصة المستخدم منخفضة الكمون". ما الذي تريده حقًا مع زمن انتقال منخفض ، لـ "Feed Only" (وخاصة إذا لم يولد إيرادات) ، هل يمكن للمستخدمين الانتظار ثانية؟ هذا ليس الكمون المنخفض.

إذا كنت ترغب في المتاجرة في FAST ، فعليك التحرك فعليًا عبر الشارع من Exchange (أو قريبًا باستخدام رابط بصري). بعد ذلك تحتاج إلى "تداول على البطاقة" ؛ إن بطاقة الإيثرنت هي "ذكية" ويتم تغذيتها "معادلات التجارة" التي تبرمج بطاقة الشبكة لإجراء تبادل مبرمج مسبقًا استنادًا إلى البيانات المستلمة (دون إزعاج الكمبيوتر الخاص بك).

انظر: http://intelligenttradingtechnology.com/article/groundbreaking-results-high-performance-trading-fpga-and-x86-technologies

تعلم التلاعب بأن البيئة سوف تشتري لك أكثر من إعادة اختراع العجلة.

إن الكمون المنخفض للغاية أمر مكلف ، لكن المليارات معرضة للخطر. الرهانات الخاصة بك (والسعي إلى أقل الكمون) مع اختناقها من قبل دولار.


كلما زادت الافتراضات التي تقوم بها والميزات التي تقطعها بشكل أسرع ، يمكنك جعل النظام الخاص بك. كلما حاولت أن تجعل الأشياء أكثر قوة ومرونة ، كلما كان أداؤك سيعاني أكثر. أود أن اقترح عددًا قليلاً من الأشخاص الأساسيين:

  1. تنسيق تبادل البيانات الثنائية. لا تستخدم XML أو أي طريقة أخرى مقروءة من قبل الإنسان لتمرير بياناتك.
  2. تنسيق قوي متسلسل للبيانات بشكلٍ كافٍ يمكنه دعم النهايات المتقاطعة للهندسة عبر المشتركة. BER يتبادر إلى الذهن - يبدو أن C # لديها الدعم
  3. بروتوكول نقل يضمن التسليم وسلامة البيانات. إذا كان أي نوع من الخوارزمية المالية سيستخدم هذه البيانات ، فحتى في حالة عدم وجود علامة واحدة قد يعني أن الفارق بين الطلبية يتم تشغيلها أو فقدانها على السعر. حتى إذا كنت ستقوم بجمع القراد في خادمك ، فإنك لا تزال تريد التحكم في كيفية تقديم المعلومات إلى عملائك. يعمل TCP للأنظمة الموزعة. ومع ذلك ، هناك بدائل أسرع بكثير إذا كان عملائك على نفس الجهاز مثل الخادم الخاص بك. UDP لن حتى النظام garauntee ، والتي يمكن أن تكون مشكلة (على الرغم من أنه لا يمكن التغلب عليها).

فيما يتعلق بالمعالجة الداخلية:

  1. تجنب السلاسل والصفوف الأخرى التي تضيف مقدار كبير من الحمل إلى مهام بسيطة. استخدم صفائف الأحرف الأساسية بدلاً من ذلك. لست متأكدًا من الخيارات الموجودة في C # أو إذا كان لديك بدائل خفيفة الوزن. إذا كان الأمر كذلك ، استخدمها. هذا ينطبق على هياكل البيانات كذلك.
  2. كن على دراية بأخطاء المقارنة المزدوجة / الطافية. استخدم المقارنات التي تحقق فقط من مستوى الدقة اللازم. إن أمكن تحويل كل شيء إلى الأعداد الصحيحة داخليًا وتوفير بيانات وصفية كافية لتحويلها مرة أخرى إلى الطرف الآخر.
  3. استخدم شيئًا مشابهًا للمخصصين المجمعين في C ++. إن عدم معرفتي بـ C # يمنعني من أن أكون أكثر تحديدًا. مرة أخرى C # ربما ليس أفضل خيار هنا. خلاصة القول هي أنك سوف تخلق وتدمر الكثير من كائنات التجزئة وليس هناك سبب لطلب نظام التشغيل للذاكرة في كل مرة.
  4. فقط إرسال deltas ، لا ترسل المعلومات التي لديك بالفعل العملاء الخاصة بك. هذا يفترض أنك تستخدم النقل مع التسليم المضمون. إن لم يكن يمكنك في نهاية المطاف عرض البيانات التي لا معنى لها لفترة طويلة.

البيانات المالية الحية؟ لا تعتمد أبداً على WCF على ذلك. بدلا من ذلك ، انتقل مع ما تستخدمه الصناعات الأخرى. أي يستخدم NASDAQ في الوقت الحقيقي الابتكارات - خدمة توزيع البيانات لتقديم القراد الأسهم الحية للمستخدمين. أنها توفر C / C ++ / C # api لمكتبات الاتصالات الخاصة بهم ، وهو سهل للغاية الإعداد والاستخدام (مقارنة WCF).

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

على العقدة الجانبية ، يمكنك تقديم حزم الصوت والفيديو في الوقت الحقيقي باستخدام مكتبة RTI-DDS ، حسب علمي ، تستخدم المركبات الجوية غير المأهولة مثل MQ-9 هذه المكتبة مرة أخرى لتقديم معلومات فيديو وموقع جغرافي مباشر على الأرض محطات التحكم.

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

تحرير : أقوم حاليًا بتصوير بعض برامج HMI (واجهة الآلة البشرية) التي تستخدم مكتبات RTI-DDS المذكورة آنفاً جنبا إلى جنب مع مكتبتين أخريين لهما معمارية موجهة للرسالة ، والتي عملت على حل الخيط حتى الآن لجميع احتياجات الاتصال في الوقت الحقيقي . في ما يلي عرض تجريبي: http://epics.codeplex.com/ (سيتم استخدامه في التحكم عن بُعد في منشأة الأبحاث النووية الجديدة تمامًا)


الإفصاح الكامل: أعمل في Informatica (29West سابقًا) وأنا في الفريق الهندسي المسؤول عن منتجات الرسائل الخاصة بهم . أنا منحاز. ومع ذلك ، فأنا أفهم جيدًا من الرسائل ذات الكمون المنخفض في السوق المالية.

إذا كانت أسعار الرسائل حوالي 60 رسالة / ثانية. (كما ورد في تعليق على إجابة ويل دين) ، ويتم تسليمها إلى واجهة المستخدم الرسومية مع وجود إنسان يجلس أمامها والتفاعل مع السوق بسرعة بشرية ، لا يهم بصراحة ما هي البرامج كنت تستخدم من منظور الكمون. قد تكون قادراً على الابتعاد عن استخدام WCF (على الرغم من أنني كنت لا أزال أوصي ضده ، ففكرنا في دعمه مرة واحدة وقمنا بتهيئة مهايئ له بشكل أولي ، كما أنه خفف من فترات الانتظار بسبب حجم الضخامة - قررنا عدم إزعاجه في الموعد).

الآن ، يمكن لبرنامج المراسلة في Informatica تمرير الرسائل بين العمليات على نفس الجهاز في أقل من ميكروثانية ، وإذا كنت ترغب في شراء بعض NIC 10 gig-E nice with passer kernel أو InfiniBand ، يمكنك تمرير ملايين الرسائل في الثانية الواحدة بين الأجهزة مع microseconds من رقم واحد من زمن الوصول. وسنقوم قريبًا أيضًا بإصدار مكتبة تسلسل بيانات جديدة مدعومة في C / C ++ و Java و .NET كجزء من منتج المراسلة الذي يكون في بعض الحالات أسرع من مخازن البروتوكول (على الرغم من أن مخازن البروتوكول تستخدم على نطاق واسع وكذلك إختيار جيد جدا). لدينا واجهات برمجة التطبيقات .NET و Java على حد سواء لديها ميزة تسمى "ZOD" لـ "Zero Object Delivery" ، وهي طريقة مضحكة نوعًا ما للقول أنها لا تولد أي كائنات جديدة أثناء تسليم الرسائل ، مما يعني عدم وجود أي إيقاف مؤقت لجمع البيانات المهملة وامتدادات / فترات الانتظار المرتبطة. لقد حصلنا على منتج آخر يسمى UMDS مصمم خصيصًا لتوجيه حركة مرور البيانات الأساسية عالية السرعة إلى تطبيقات سطح المكتب الأبطأ دون إبطاء العمود الفقري أو العملاء الآخرين.

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

  • إذا كان لديك الكثير من العملاء الذين يتلقون نفس البيانات ، فستحتاج إلى بعض النكهات الخاصة بـ UDP multicast. ستحتاج غالبًا إلى نقل موثوق متعدد البث من نوع ما - بروتوكول الإرسال المتعدد الموثوق به (والمجاني) الموثوق به هو PGM. يتضمن Windows تطبيق PGM القابل للاستخدام في C #؛ سأشيرك إلى مشاركة مدونة مايك ريتيج الممتازة حول كيفية استخدامها إذا كنت تريد تجربتها. (أنا أعرف مايك - إنه رجل ذكي.) اختيار البروتوكول هو مجال تحصل فيه على ما تدفعه مقابل ؛ تتضمن رسالة Informatica بروتوكولًا موثوقًا للبث المتعدد يعتمد بشكل فضفاض على PGM (مهندسنا المعماري الذي صممه شارك في كتابة PGM RFC منذ فترة طويلة) ، ولكن مع الكثير من التحسينات الرئيسية. قد يكون PGM سهل على ما تحتاجه ، مع ذلك.

  • تريد أن تذهب مع بنية بدون اتصال / بدون ملقم. اطلب من التطبيقات التواصل مع نظير إلى نظير دون أي شيء في المنتصف. تجنب القفزات الإضافية في مسار الرسالة (وهو ما يعني عادةً تجنب معظم تطبيقات JMS ، وتجنب أي شيء تقريبًا مع "طابور" في الاسم في مكان ما ، وما إلى ذلك).

  • ضع في اعتبارك كيفية تصرف النظام الخاص بك عندما يقوم عميل فردي بإساءة التصرف. هل يمكن أن يبطئ المستهلك البطيء الجميع؟

  • هناك الكثير من خيارات ضبط نظام الويندوز و BIOS التي يمكن أن تستفيد من أي نوع من الرسائل منخفضة الكمون أو محلية أو مشتريات - أشياء مثل التقاطع بين المقاطعات وربط NIC المقاطعات إلى وحدة المعالجة المركزية الأساسية وقياس الجانب المستقبلي (والذي كان تاريخياً رهيباً عند استخدامه مع UDP على Windows ، ولكن يجب أن يكون أفضل في المستقبل) ، تعطيل بعض حالات طاقة وحدة المعالجة المركزية ، إلخ.

  • قاوم إغراء استخدام التسلسل المدمج للكائنات في .NET لإرسال كائنات كاملة عبر السلك - وهي أوامر ذات حجم أبطأ من استخدام تنسيق ثنائي بسيط (مثل "Buffers Buffers" ، أو مكتبة التسلسل في Informatica ، أو نسختك الثنائية الخاصة ، إلخ. .).

إذا كانت لديك أسئلة محددة أو تحتاج إلى مزيد من التفاصيل حول أي من نصيحتي ، فيرجى إبلاغي بذلك!


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

هنا بعض التعليمات البرمجية (اختبار):

public static T DeepClone<T>(this T original, params Object[] args)
{
    return original.DeepClone(new Dictionary<Object, Object>(), args);
}

private static T DeepClone<T>(this T original, Dictionary<Object, Object> copies, params Object[] args)
{
    T result;
    Type t = original.GetType();

    Object tmpResult;
    // Check if the object already has been copied
    if (copies.TryGetValue(original, out tmpResult))
    {
        return (T)tmpResult;
    }
    else
    {
        if (!t.IsArray)
        {
            /* Create new instance, at this point you pass parameters to
                * the constructor if the constructor if there is no default constructor
                * or you change it to Activator.CreateInstance<T>() if there is always
                * a default constructor */
            result = (T)Activator.CreateInstance(t, args);
            copies.Add(original, result);

            // Maybe you need here some more BindingFlags
            foreach (FieldInfo field in t.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy | BindingFlags.Instance))
            {
                /* You can filter the fields here ( look for attributes and avoid
                    * unwanted fields ) */

                Object fieldValue = field.GetValue(original);

                // Check here if the instance should be cloned
                Type ft = field.FieldType;

                /* You can check here for ft.GetCustomAttributes(typeof(SerializableAttribute), false).Length != 0 to 
                    * avoid types which do not support serialization ( e.g. NetworkStreams ) */
                if (fieldValue != null && !ft.IsValueType && ft != typeof(String))
                {
                    fieldValue = fieldValue.DeepClone(copies);
                    /* Does not support parameters for subobjects nativly, but you can provide them when using
                        * a delegate to create the objects instead of the Activator. Delegates should not work here
                        * they need some more love */
                }

                field.SetValue(result, fieldValue);
            }
        }
        else
        {
            // Handle arrays here
            Array originalArray = (Array)(Object)original;
            Array resultArray = (Array)originalArray.Clone();
            copies.Add(original, resultArray);

            // If the type is not a value type we need to copy each of the elements
            if (!t.GetElementType().IsValueType)
            {
                Int32[] lengths = new Int32[t.GetArrayRank()];
                Int32[] indicies = new Int32[lengths.Length];
                // Get lengths from original array
                for (int i = 0; i < lengths.Length; i++)
                {
                    lengths[i] = resultArray.GetLength(i);
                }

                Int32 p = lengths.Length - 1;

                /* Now we need to iterate though each of the ranks
                    * we need to keep it generic to support all array ranks */
                while (Increment(indicies, lengths, p))
                {
                    Object value = resultArray.GetValue(indicies);
                    if (value != null)
                       resultArray.SetValue(value.DeepClone(copies), indicies);

                }
            }
            result = (T)(Object)resultArray;
        }
        return result;
    }
}

private static Boolean Increment(Int32[] indicies, Int32[] lengths, Int32 p)
{
    if (p > -1)
    {
        indicies[p]++;
        if (indicies[p] < lengths[p])
        {
            return true;
        }
        else
        {
            if (Increment(indicies, lengths, p - 1))
            {
                indicies[p] = 0;
                return true;
            }
            else
            {
                return false;
            }
        }
    }
    return false;
}

تحديث

إضافة المزيد من التعليمات البرمجية ، يمكنك الآن استخدام الطريقة لنسخ الكائنات المعقدة (حتى المصفوفات ذات الأبعاد المتعددة). لاحظ أن المندوبين لا تزال غير مطبقة.

إذا كنت تريد تنفيذًا كاملاً ، ISerializable عليك معالجة واجهة ISerializable التي ليست صعبة حقًا ولكنها تستغرق بعض الوقت للتفكير في الشفرة الحالية. فعلت هذا مرة واحدة للتنفيذ عن بعد.





c# .net wcf