Data Engineering

إتقان البيانات في الوقت الفعلي: غوص عميق في بنية وتنفيذ Apache Flink

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

لماذا يبرز Apache Flink؟

على عكس Apache Spark، الذي يركز بشكل أساسي على المعالجة الدفعية مع إضافات للتدفق، تم بناء Flink من الصميم كمحرك تدفق أصلي. يسمح هذا القرار المعماري لـ Flink بمعالجة وقت الحدث، ومعالجة الأحداث المعقدة (CEP)، والحسابات ذات الحالة بدقة استثنائية. تضمن قدرته على إدارة الحالات الكبيرة بكفاءة من خلال آليات أخذ لقطات (Checkpointing) دلالات التنفيذ مرة واحدة بالضبط (Exactly-once semantics)، حتى في مواجهة الأعطال. بالنسبة لمهندسي البيانات الذين يتعاملون مع المعاملات المالية، أو بيانات مستشعرات إنترنت الأشياء، أو تحليلات المستخدمين في الوقت الفعلي، فإن ترتيب المعالجة الحتمي وقدرات زمن الاستجابة المنخفض في Flink لا مثيل لها.

البنية الأساسية: الوظائف والمهام والمشغلات

يعد فهم نموذج التنفيذ في Flink أمراً حاسماً للتحسين. يتم ترجمة برنامج المستخدم المكتوب بلغة Java أو Scala إلى برنامج DataStream أو DataSet. ثم يتم تحويل هذا التدفق المنطقي للبيانات إلى JobGraph، الذي يمثل خطة التنفيذ. يقوم مدير الوظائف (JobManager) أو مكونات مدير الموارد ومدير الوظائف الأحدث في الإصدارات الجديدة بجدولة هذه المهام عبر مشغلات المهام (TaskManagers). يشغل كل مشغل مهام عدداً محدداً من فتحات المهام، مما يسمح بالتنفيذ المتوازي وعزل الموارد. يتيح هذا التصميم المعياري لـ Flink التوسع الأفقي عبر العناقيد بسلاسة، ومعالجة ملايين الأحداث في الثانية بزمن استجابة أقل من ثانية.

التطبيق العملي: عد الكلمات في Flink

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

import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.windowing.time.Time;
import org.apache.flink.api.common.functions.FlatMapFunction;
import org.apache.flink.util.Collector;

public class WordCount {
    public static void main(String[] args) throws Exception {
        // Set up the execution environment
        final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();

        // Get the input data by connecting to a socket
        DataStream<String> text = env.socketTextStream("localhost", 9999);

        // Parse the data, group it, window it, and aggregate the counts
        DataStream<WordCount> windowCounts = text
                .flatMap(new Tokenizer())
                .keyBy(value -> value.word)
                .timeWindow(Time.seconds(5))
                .sum("count");

        // Print the results with a single thread, instead of in parallel
        windowCounts.print().setParallelism(1);

        // Execute program
        env.execute("Streaming WordCount");
    }

    public static class WordCount {
        public String word;
        public long count;

        public WordCount() {}

        public WordCount(String word, long count) {
            this.word = word;
            this.count = count;
        }

        @Override
        public String toString() {
            return word + ": " + count;
        }
    }

    public static class Tokenizer implements FlatMapFunction<String, WordCount> {
        @Override
        public void flatMap(String value, Collector<WordCount> out) {
            for (String word : value.toLowerCase().split("\\W+")) {
                out.collect(new WordCount(word, 1));
            }
        }
    }
}

يبرز هذا الجزء المفاهيم الرئيسية في Flink: flatMap للتحويل، وkeyBy لتقسيم الحالة، وtimeWindow للتجميع القائم على الوقت. تتيح طريقة collect إصدار سجلات إخراج متعددة لسجل إدخال واحد، وهي ميزة قوية لتصفية أو إثراء تدفقات البيانات.

إدارة الحالة وتحمل الأخطاء

إحدى أهم ميزات Flink هي الخلفية الخاصة بإدارة الحالة (State Backend). على عكس أنظمة المعالجة عديمة الحالة، يحافظ Flink على حالة حساباتك محلياً داخل مشغلات المهام. لمنع فقدان البيانات، يستخدم Flink خوارزمية لقطات موزعة تستند إلى Chandy-Lamport. من خلال أخذ لقطات متسقة بشكل دوري للحالة وتسجيل تدفق السجلات إلى تخزين دائم (مثل HDFS أو S3)، يمكن لـ Flink التعافي من الأعطال دون فقدان البيانات أو معالجة السجلات خارج الترتيب. يضمن ذلك بقاء لوحات المعلومات في الوقت الفعلي دقيقة وموثوقة، حتى أثناء فشل عقد العنقود.

الخاتمة

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

Share: