تست Big Data با شمردن رکوردها، اجرای موفق Job یا دیدن یک نمودار سبز تمام نمیشود. پرسش اصلی این است: آیا از یک ورودیِ مشخص و نسخهدار، با همان منطق و همان سیاست زمان، خروجیِ مورد انتظار و قابلبازتولید ساخته شده است؛ و اگر Duplicate، دادهٔ دیررس، تغییر Schema، Retry، Backfill یا خرابی میان Commit رخ دهد، تصمیم کسبوکار هنوز درست میماند؟ این راهنما روش آزمون Data Pipeline را از Source Contract تا Replay و Reconciliation توضیح میدهد.
هدف، تبلیغ Hadoop، Spark، Kafka یا هر Vendor دیگری نیست. «Big Data» نیز آستانهٔ جهانیِ ثابتی از تعداد رکورد ندارد. یک Pipeline کوچک اما تصمیمساز میتواند پرریسکتر از یک Dataset بزرگ و کماثر باشد. بنابراین واحد طراحی تست در این مقاله Data Product Claim است: ادعایی نسخهدار دربارهٔ منبع، تبدیل، زمان، کلید، خروجی و مصرفکننده که بتوان برایش Oracle و Evidence ساخت.
خلاصهٔ اجرایی: مسیر تست خط لوله داده
- مصرفکننده و تصمیمی را که داده پشتیبانی میکند مشخص کنید.
- Source، Dataset، Job، Run، Code، Config و Output را هویتگذاری کنید.
- برای Schema، Key، Null، Unit، Time، Duplicate، Error و Retention قرارداد بنویسید.
- تبدیل را با Oracle مستقل، مثالهای کوچک و Propertyها بررسی کنید.
- Batch و Stream را در برابر Retry، Late data، Reorder، Backfill و Replay بیازمایید.
- بین «تحویل پیام»، «پردازش رکورد» و «اثر کسبوکار» مرز بگذارید.
- Reconciliation را با Count تنها انجام ندهید؛ Key set، Hash، Sum و State transition را هم بسنجید.
- نتیجه را با Run identity، Input snapshot، Lineage، Quality measurements و Exceptionها ثبت کنید.
این مقاله مالک کدام Intent است؟
مالکیت این صفحه «صحت و قابلیت بازپخش خط لولهٔ دادهٔ Batch/Streaming» است. برای طراحی SQL و کنترلهای Data Warehouse/ETL به راهنمای تست ETL و انبار داده، برای Workload و Freshness و Skew به تست عملکرد Big Data، و برای IAM، Encryption و Data Lake threat model به امنیت دریاچه داده مراجعه کنید.
| Intent | مالک | این مقاله چه چیزی اضافه میکند؟ |
|---|---|---|
| Database constraint، Transaction، Migration | تست پایگاه داده | صحت میان چند Dataset/Job/Run |
| Synthetic، Masking، Provision و Reset | مدیریت داده تست | Fixture و Snapshot مخصوص Pipeline |
| Failure mode و Recovery | تست تابآوری | Replay/Backfill و Output reconciliation |
| Expected result و Comparator | Test Oracle | Oracleهای دادهای و Metamorphic relation |
| Ordering، Partition و Distributed failure | تست سیستم توزیعشده | قرارداد end-to-end خط داده |
Big Data Testing دقیقاً چیست؟
تست Big Data مجموعهای از بررسیهای نسخهدار برای اثبات محدودِ Fitness for Purpose یک Data Product است: آیا Dataset ورودیِ اعلامشده، با Transform و Policy اعلامشده، خروجیِ مناسبِ مصرف مشخص را تولید میکند؟ این تعریف هم داده و هم کد را در بر میگیرد. تفاوت اصلی با تست یک UI، «تمرکز بر داده به جای کد» نیست؛ بلکه گستردگی State، زمان، Lineage، توزیع، Reprocessing و مصرفهای متعدد است.
Volume، Velocity و Variety میتوانند در Risk model حضور داشته باشند، اما 3V یک Test Strategy نیست. حجم زیاد بهتنهایی صحت را تعریف نمیکند؛ سرعت ورود، Event-time semantics را نمیگوید؛ و تنوع Format جای Schema evolution contract را نمیگیرد. Veracity، Value یا Vهای دیگر نیز فقط برچسباند مگر آنکه به Requirement، Metric، Threshold، Population و Owner تبدیل شوند.
از «Pipeline سبز» تا «ادعای دادهٔ پشتیبانیشده»
| سیگنال | چه چیزی را نشان میدهد؟ | چه چیزی را ثابت نمیکند؟ |
|---|---|---|
| Exit code=0 | Runner خطای اعلامشده ندیده است | Transform درست یا ورودی کامل است |
| Input count=Output count | تعداد در دو مرز برابر است | کلیدها، مقادیر یا نسخهها برابرند |
| Schema valid | ساختار با قرارداد انتخابی سازگار است | معنا، واحد یا Accuracy درست است |
| No null | فیلد تهی نیست | مقدار واقعی، معتبر یا بهروز است |
| Checkpoint recovered | پردازش از State ثبتشده ادامه یافته | Sink اثر تکراری ندارد |
| Dashboard looks right | یک View قابلرندر است | عدد، Population و Filter درستاند |
نقشهٔ محصول داده را قبل از تست رسم کنید
Producer → Source contract → Ingestion → Raw/immutable zone
→ Validate/Quarantine → Transform/Join/Aggregate
→ Curated dataset → Serving/API/BI/ML consumer
→ Decision/Action
Control plane: Code + Config + Schema + Schedule + Access
Evidence plane: Run + Snapshot + Lineage + Metrics + Exceptions
هر فلش یک مرز شکست است. ممکن است Producer درست بنویسد اما Ingestion بخشی از Partition را نخواند؛ Raw سالم باشد اما Join fan-out ایجاد کند؛ Curated درست باشد اما BI timezone اشتباه اعمال کند؛ یا محاسبه درست باشد اما مصرفکننده Dataset نسخهٔ دیگری را بخواند. E2E یعنی ادعای تصمیم را تا منبع قابلردیابی کنید، نه اینکه فقط بزرگترین Job را اجرا کنید.
Data Product Claim Contract
claim_id: paid-orders-daily-v3 consumer_decision: settlement review population: eligible marketplace orders source_datasets: orders-v7, payment-events-v4 identity: tenant_id + order_id + payment_attempt_id time_semantics: payment event_time; Asia/Tehran reporting day transform_version: git_sha + config_hash late_policy: update until T+48h; later → exception/backfill duplicate_policy: event_id has one business effect output: curated_paid_orders_v3 oracle: order + attempt + ledger + fake-PSP reconciliation freshness_slo: declared per reporting use owner: Data Product Owner decision_owner: Finance Operations known_limits: refunds after close, disputed callbacks, clock quality
Claim باید آنقدر محدود باشد که Fail شدنش یک تصمیم بسازد. «دادهها دقیقاند» قابلتست نیست؛ «برای سفارشهای واجدشرایطِ snapshot S، هر PaymentAttempt موفق دقیقاً یک Ledger effect دارد و جمع روز تهران با Reconciliation منطبق است» قابلبررسی است.
هویتها: پایهٔ Replay و مقایسه
| هویت | نمونه | چرا لازم است؟ |
|---|---|---|
| Dataset | namespace + name | تفکیک جدول/Topic/File collection |
| Snapshot | version/commit/manifest/hash | ثابتکردن Population ورودی |
| Job | namespace + job name | تعریف منطقی پردازش |
| Run | run_id + attempt | تفکیک Retry از اجرای تازه |
| Code/Config | git SHA + image digest + config hash | تکرار منطق دقیق |
| Record/Event | business key + event ID + version | Dedup و State ordering |
| Partition/Offset | topic/partition/offset یا file manifest | مرز دریافت و Replay |
| Output | table snapshot/commit/report version | اتصال Evidence به مصرفکننده |
مدل شیء OpenLineage میان Dataset، Job و Run تفکیک میگذارد و Run event را یک مشاهده در چرخهٔ اجرا میداند. این مدل میتواند واژگان مفیدی برای Lineage باشد، اما نصب ابزار Lineage بهتنهایی کاملبودن، صحت یا Freshness داده را تضمین نمیکند؛ نامگذاری و Instrumentation نیز باید آزموده شوند.
Data Contract فقط Schema نیست
| بُعد قرارداد | پرسش آزمون | Failure نمونه |
|---|---|---|
| Structure | Field/type/cardinality چیست؟ | عدد به String تبدیل شده |
| Meaning | تعریف business field چیست؟ | gross بهجای net |
| Identity | کلید و دامنهٔ یکتایی چیست؟ | order_id میان Tenantها collide |
| Unit/Currency | ریال، تومان، ثانیه یا میلیثانیه؟ | ۱۰× amount |
| Time | event/ingest/process time و timezone؟ | روز گزارش جابهجا |
| Null/Default | Missing، unknown و zero چه تفاوتی دارند؟ | null به صفر تبدیل شده |
| Evolution | Compatibility و deprecation window؟ | Consumer قدیمی field جدید را رد میکند |
| Delivery | duplicate/order/retry/lateness؟ | دو اثر برای یک event |
| Error | reject/quarantine/default/stop؟ | رکورد بد بیصدا حذف میشود |
| Service | Freshness/availability/retention؟ | Dataset درست اما دیر |
کیفیت داده وابسته به Fitness for Purpose است
W3C Data Quality Vocabulary یک تعریف رسمی و کامل از «کیفیت» تحمیل نمیکند؛ چارچوبی برای Dimension، Metric، Measurement، Policy و Provenance فراهم میکند تا مصرفکننده دربارهٔ تناسب داده با هدف قضاوت کند. بنابراین Accuracy یا Completeness بدون Consumer، Population، Formula، Window و Threshold یک برچسب مبهم است.
quality_measurement: claim_id: paid-orders-daily-v3 dataset_snapshot: curated_paid_orders@commit-884 dimension: completeness metric: eligible payment attempts represented numerator: unique eligible attempts in output denominator: unique eligible attempts in authoritative source snapshot exclusions: declared test/cancelled-before-payment attempts window: 1405-05-21 Asia/Tehran threshold: consumer-approved result: value + unknown_count provenance: run_id + query_hash + comparator_version
ابعاد کیفیت را به Measurement تبدیل کنید
| Dimension | Metric نمونه | Oracle/محدودیت |
|---|---|---|
| Completeness | درصد کلیدهای واجدشرایط حاضر | منبع مرجع و Exclusion لازم است |
| Validity | درصد مطابق Schema/domain rule | Validity برابر Reality نیست |
| Uniqueness | کلیدهای دارای بیش از یک Current row | دامنهٔ کلید باید روشن باشد |
| Consistency | نقض rule میان Datasetها | ممکن است هر دو منبع اشتباه باشند |
| Accuracy | اختلاف با Reference مستقل | Reference uncertainty ثبت شود |
| Timeliness | event-to-available lag distribution | Clock و Population مشخص باشد |
| Freshness | age of latest complete snapshot | Latest record با complete بودن فرق دارد |
| Integrity | orphan/invalid transition rate | eventual consistency window لحاظ شود |
Golden Dataset لازم است، اما کافی نیست
Golden Dataset کوچک برای Ruleهای دشوار، Boundary، Null، Unicode و State transition مفید است؛ ولی نمیتواند Skew، Cardinality واقعی، تعامل Partitionها، دیررسبودن طولانی یا تحول Schema را نمایندگی کند. نسخهٔ Golden data، منبع Expected result، Reviewer، تاریخ و Known blind spot باید ثبت شود. بهروزرسانی خودکار Expected با همان کد Target، Oracle مستقل را از بین میبرد.
نمونهگیری کجا مفید و کجا خطرناک است؟
| روش | کاربرد مناسب | Blind spot |
|---|---|---|
| Random sample | بررسی گستردهٔ توزیعهای رایج | Rare critical case حذف میشود |
| Stratified | Tenant/region/version/status strata | Strata ناشناخته پوشش ندارد |
| Risk-based | مبلغ بالا، مسیر حساس، Schema جدید | برای برآورد Population بیطرف نیست |
| Boundary fixture | Null/max/min/timezone/Unicode | فراوانی Production را نشان نمیدهد |
| Full reconciliation | Count/hash/sum/key-set قابلمحاسبه | Comparator معیوب میتواند false pass دهد |
«داده زیاد است، پس نمونه میگیریم» سیاست قابلقبولی نیست. ابتدا Claim تعیین میکند کدام کنترل باید Full-population باشد و کدام میتواند آماری باشد. Sampling frame، Seed، Method، Inclusion probability، Confidence/uncertainty و Exclusionها باید قابلبازتولید باشند.
Test Basis و Oracle برای Transform
Expected output نباید از حافظهٔ تستر یا از همان Dashboard هدف ساخته شود. Test Basis میتواند Specification نسخهدار، جدول تصمیم، فرمول تأییدشده، State model، Ledger invariant یا Reference implementation مستقل باشد. اگر یک SQL query و کد Production هر دو از همان برداشت اشتباه Rule ساخته شده باشند، تطابقشان شاهد مستقل نیست.
| Oracle | کاربرد | ریسک |
|---|---|---|
| Hand-calculated fixture | منطق کوچک و حساس | خطای انسانی/پوشش کم |
| Independent query | Reconciliation و Aggregate | منطق مشترک پنهان |
| Source invariant | حفظ مبلغ/کلید/تعداد واجدشرایط | قانون ممکن است استثنا داشته باشد |
| Differential | Old vs New engine/implementation | نسخهٔ قدیمی حقیقت نیست |
| Metamorphic | وقتی خروجی دقیق دشوار است | Relation ناقص میتواند باگ را عبور دهد |
| Consumer reconciliation | اثر تصمیمساز end-to-end | Consumer ممکن است دیر یا ناسازگار باشد |
Property و Invariantهای مفید خط لوله
- افزودن Duplicate با Event ID یکسان، اثر جاری را تغییر ندهد.
- تغییر ترتیب Arrival، در صورت تعریف Event/Version order، Current state را تغییر ندهد.
- Partition کردن و سپس Union کردن ورودی، نتیجهٔ Transform مستقل از Partition را حفظ کند.
- Replay همان Snapshot با همان Code/Config، Output digest یا Semantic result یکسان بدهد.
- مجموع اجزای mutually exclusive با Total منطبق باشد.
- هیچ Output current row بیش از یک کلید کسبوکار نداشته باشد.
- هر رکورد Reject/Quarantine دلیل، Source identity و مسیر اصلاح داشته باشد.
- Backfill بازهٔ هدف، دادهٔ خارج از Scope را تغییر ندهد.
property_id: P-DUP-01 given: snapshot S + event E transform: version V / config C mutation: append an exact redelivery of E expected_relation: current_business_state(S + E + E) = current_business_state(S + E) allowed_difference: delivery_attempt_count may increase forbidden_difference: ledger_effect, paid_total, current_status evidence: input manifests + output key/hash/sum diff + run IDs
Reconciliation چندلایه؛ Count کافی نیست
| لایه | کنترل | چه خطایی را میگیرد؟ |
|---|---|---|
| Population | eligible/excluded/unknown counts | مخرج مبهم یا Scope drift |
| Key set | missing/extra/duplicate keys | یک حذف و یک اضافه با count برابر |
| Field | typed/hash/sample diff | تحریف مقدار |
| Aggregate | sum/min/max/distribution by stratum | Scale/unit/filter خطا |
| Relation | foreign key/state transition | Orphan یا transition نامعتبر |
| Temporal | event/valid/system time interval | stale overwrite یا overlap |
| Business effect | Order/Ledger/Settlement match | Pipeline درست اما تصمیم نادرست |
reconciliation_result: source_snapshot: S-2026-08-12-01 target_snapshot: T-884 eligible_source_keys: 10000 target_current_keys: 9998 missing_keys: 3 extra_keys: 1 duplicate_current_keys: 0 amount_delta_irr: -240000 unknown_keys: 2 verdict: FAIL note: equal-looking dashboard total is not the comparator
تست Ingestion: مرز دریافت را قابلاثبات کنید
| ریسک | Fault/Fixture | Oracle |
|---|---|---|
| Partial file | upload ناتمام/بدون atomic publish | فایل مصرف نشود یا Quarantine شود |
| Duplicate file | همان Manifest با نام دیگر | policy روشن؛ zero extra effect |
| Missing partition | حذف یک date/tenant partition | Completeness gate با unknown |
| Offset gap | range ناقص | gap detection و توقف/Exception |
| Poison record | type/encoding/schema خراب | نه crash loop، نه silent drop |
| Compressed corruption | checksum mismatch | reject + source evidence |
| Producer retry | event یکسان چند بار | delivery و business-effect جدا |
تست Transform: Filter، Map و Cast
برای Filter، هر Rule را به included/excluded/unknown تفکیک کنید؛ حذف بیصدای unknown معمولاً نتیجه را خوشبینانه میکند. برای Cast، overflow، rounding، precision، scientific notation، Persian/Arabic digits، whitespace، Unicode normalization و invalid values را پوشش دهید. برای مبلغ، Currency و Unit باید همراه عدد حرکت کند؛ تبدیل تومان/ریال با حدس از بزرگی مقدار مجاز نیست.
| ورودی | Rule | Expected disposition |
|---|---|---|
| amount_irr=120000 | canonical IRR | accept |
| display_amount=12000, unit=toman | explicit conversion | 120000 IRR + provenance |
| amount=12000, unit missing | unit required | quarantine/unknown، نه حدس |
| digits=«۱۲٬۰۰۰» | locale parser version | parse or declared reject |
| status=”” | empty ≠ null ≠ unknown | طبق Contract |
Join Testing: Fan-out و Orphan را آشکار کنید
موفقیت Join فقط به اجرای Query وابسته نیست. Grain هر Dataset، Cardinality مورد انتظار، Null-key policy، effective-time condition و برخورد با چند Match باید صریح باشد. Join سفارش با چند PaymentAttempt اگر پیش از Aggregate بدون Grain مشخص انجام شود، مبلغ را چند برابر میکند.
| کنترل | Measurement | Gate نمونه |
|---|---|---|
| Left key uniqueness | duplicate key count | طبق declared grain |
| Right match cardinality | 0/1/many distribution | unexpected many = fail |
| Orphan | left/right unmatched by reason | unknown جدا از allowed |
| Fan-out factor | rows after / eligible before | Claim-specific threshold |
| Temporal match | valid_from ≤ event < valid_to | no overlap/gap unless declared |
| Amount preservation | sum before/after by key stratum | declared non-transforming join |
Aggregation Testing: مخرج، Window و Rounding
- Grain خروجی را بنویسید: روز/تهران + Tenant + Currency، نه فقط «daily».
- Distinct subject و distinct event را جدا کنید.
- Null در SUM/AVG/COUNT و denominator را صریح کنید.
- Rounding را در انتها یا هر ردیف طبق Rule نسخهدار اعمال کنید.
- Cancelled، test، disputed، late و unknown را در مخرج پنهان نکنید.
- Window boundary، DST احتمالی، UTC و Asia/Tehran را با زمان ثابت تست کنید.
- Average را بدون Distribution و Population بهعنوان سلامت Pipeline گزارش نکنید.
Batch Pipeline: Snapshot، Incremental و Backfill
| حالت | Claim لازم | Fault مهم |
|---|---|---|
| Full snapshot | Population و replace semantics | half-published snapshot |
| Incremental | high-water mark/change identity | boundary miss/duplicate |
| CDC | insert/update/delete/order semantics | tombstone loss/reorder |
| Retry | attempt identity/idempotent publish | double append |
| Backfill | scope/code/schema/output isolation | current data overwritten |
| Rebuild | declared snapshot → deterministic state | unversioned dependency |
backfill_contract: request_id: BF-42 reason: late source correction target_range: [1405-05-01, 1405-05-07] source_snapshots: immutable manifests code/config/schema: pinned destination: isolated candidate dataset compare: key set + field diff + sums + consumer queries publish: atomic alias/snapshot switch rollback: previous output pointer owner/approver: named outside_range_expected_delta: zero
Stream Pipeline: سه نوع زمان را قاطی نکنید
| زمان | معنا | آزمون |
|---|---|---|
| Event time | زمان رخداد در Domain | clock quality، timezone، late/reorder |
| Ingest time | ورود به Platform | queue/network delay |
| Processing time | زمان اجرای Operator | backpressure/retry/recovery |
| Valid time | زمان اعتبار Business fact | correction/temporal join |
| System time | زمان ثبت نسخه در Storage | audit/as-of reconstruction |
مستندات جاری Structured Streaming Event time را زمان نهفته در خود داده میداند و توضیح میدهد که Watermark برای تعیین دیررسبودن و پاکسازی State استفاده میشود. این مفهوم را با «همهٔ دادههای دیررس حتماً حذف میشوند» یکی نکنید؛ تنظیم و Operator و Output mode بر رفتار اثر دارند.
Watermark Contract و تست Late Data
watermark_contract: event_time_field: occurred_at clock_source/quality: declared allowed_lateness: 48h for this claim operator: windowed aggregate + dedup output_mode: declared state_retention: bounded too_late_disposition: quarantine + correction queue correction_policy: versioned backfill consumer_visibility: provisional until close metrics: late-within / too-late / unknown-clock
| Test | ورودی | Expected |
|---|---|---|
| On time | event پیش از Watermark | طبق Window وارد شود |
| Late within policy | دیر اما داخل آستانه | update/retract/append طبق mode |
| Too late | پشت state retention | disposition قابلمشاهده |
| Clock future | event time دور از آینده | Watermark بیمحابا جلو نرود |
| Idle partition | یک Stream متوقف | global policy مطابق Contract |
| No new batch | آخرین window بدون input بعدی | finalization semantics آزموده شود |
Exactly-once را همیشه با Scope بخوانید
عبارت «Exactly-once» بدون Source، Processor، State، Sink و Failure model مبهم است. طراحی جاری Kafka ۴.۳ میان publish و consume semantics فرق میگذارد و تصریح میکند نوشتن به Destination خارجی به همکاری آن سیستم نیاز دارد. مستندات Spark نیز تضمین end-to-end خود را به Source قابل Replay، Checkpoint/WAL و Sink idempotent پیوند میدهد. این ادعاها را به ایمیل، Ledger، API خارجی یا اثر فیزیکی خارج از Scope تعمیم ندهید.
| لایه | پرسش | Evidence |
|---|---|---|
| Producer | Retry چگونه dedup میشود؟ | producer/event identity |
| Broker/Source | Commit و retention چه معنایی دارد؟ | partition/offset/transaction |
| Processor | State و checkpoint چگونه بازیابی میشود؟ | run/restart trace |
| Sink | Upsert/append/transaction/idempotency؟ | target key/commit |
| Business effect | یک event چند Ledger/notification/action میسازد؟ | domain reconciliation |
آزمایش قطعی: Replay خام چگونه خروجی را دوبرابر میکند؟
یک Fixture مستقل با Node.js ۲۴.۱۸.۰ و دادههای کاملاً ساختگی ساختیم. چهار Delivery اولیه شامل دو Payment، یک Redelivery دقیق و Refund نسخهٔ سوم بود. سپس Snapshot پنجDelivery شامل یک Event دیررس نسخهٔ دوم را Replay کردیم. Consumer ساده همهچیز را Append کرد؛ Consumer قراردادمحور Event ID را Dedup و Current state را با Version/Event time تعیین کرد.
NAIVE APPEND first run: rows=4, paidIrr=280000 append full replay: rows=9, paidIrr=560000 unjustified replay delta: +5 rows, +280000 IRR CONTRACT-AWARE REBUILD unique events in replay snapshot: 4 current O1: version=3, status=REFUNDED current O2: version=1, status=PAID current paidIrr: 80000 D2-RETRY: DUPLICATE_NO_EFFECT D3-LATE: HISTORICAL_NO_CURRENT_OVERWRITE
این خروجی فقط مکانیک Duplicate amplification، جلوگیری از stale overwrite و بازسازی قطعی از Snapshot اعلامشده را نشان میدهد. تمام IDها، زمانها، Versionها، Statusها، مبالغ و Ruleها ساختهٔ نویسندهاند. آزمایش، Spark/Kafka/Flink/Hadoop/Database یا trace واقعی نیست و Partition، Offset، Checkpoint، Transaction، Watermark، Schema registry، همزمانی، خرابی و Distributed state را مدل نمیکند. Rule ترتیب از پیش تعریف شده و برای Domain دیگر الزاماً درست نیست؛ این نتیجه Benchmark کارایی، مقیاس، کیفیت داده، مالی، امنیت، تابآوری یا Exactly-once نیست.
Replay Test Contract
replay_test:
claim: rebuild current paid-order state
input_snapshot: manifest + hash + schema versions
code/config/image: pinned
initial_state: empty or declared checkpoint
side_effects: isolated/fake/disabled
output_candidate: new immutable snapshot
comparators:
- business key set
- current version/status per key
- aggregate by currency/day/tenant
- reject/unknown set
- semantic digest
expected_delta: declared corrections only
verdicts: PASS / FAIL / ERROR / INCONCLUSIVE
cleanup/rollback: explicit
Schema Evolution را با ماتریس Producer/Consumer تست کنید
| تغییر | ریسک | تست |
|---|---|---|
| Optional field اضافه | Consumer strict fail | old/new producer × old/new consumer |
| Required field اضافه | old data unreadable | default/migration/reject policy |
| Rename | دو معنا یا silent null | dual-read/deprecation window |
| Type widen/narrow | overflow/precision loss | boundary and round-trip |
| Enum value اضافه | unknown mapped incorrectly | unknown disposition |
| Semantic change same name | schema-valid but wrong | contract version and consumer claim |
| Unit/timezone change | ۱۰× یا day shift | explicit unit/time fixtures |
| Delete field | downstream break | usage/lineage + staged removal |
Mixed-version Dataset و Historical Replay
فقط latest producer با latest consumer را تست نکنید. در Storage بلندمدت، یک Rebuild ممکن است Schemaهای v1 تا v7 را همزمان بخواند. Fixture باید old-only، new-only، mixed، missing-field، unknown-enum و semantic-version boundary داشته باشد. هر Adapter باید Provenance نسخهٔ اولیه را حفظ کند؛ تبدیل همهچیز به latest schema بدون ثبت loss یا assumption، قابلیت Audit را کاهش میدهد.
compatibility_matrix: P1 → C1: baseline P1 → C2: backward-read claim P2 → C1: forward-read or declared reject P2 → C2: current mixed(P1,P2) → C2: historical rebuild malformed/unknown → quarantine with source identity
Delete، Tombstone و حق اصلاح تاریخچه
Delete در Pipeline میتواند physical delete، Tombstone، redaction، legal hold، logical inactive یا correction باشد. هر کدام اثر متفاوتی بر Aggregate، Snapshot، Cache، Export و Backup دارد. تست کنید Tombstone گم نمیشود، رکورد حذفشده در Rebuild زنده نمیشود، downstreamهای دیررس تغییر را میبینند و Evidence لازم بدون نگهداری بیضابطهٔ PII باقی میماند.
Test Data: واقعگرایی بدون کپی Production
دادهٔ Production را بهصورت پیشفرض به محیط تست نبرید. Fixtureهای کوچک و دستی برای Oracle، Generatorهای Seedدار برای حجم/ترکیب، Synthetic relational data برای Constraint، و Datasetهای Masked/Subsetting فقط با مبنای مجاز و کنترل Re-identification استفاده شوند. Secret، PAN، CVV2، OTP، Token، Cookie و کلید واقعی جایی در Fixture مقاله یا CI ندارند.
| Data set | هدف | Evidence لازم |
|---|---|---|
| Micro golden | Rule/Oracle دقیق | نسخه و hand-reviewed expected |
| Boundary pack | Null/type/time/Unicode/unit | case inventory |
| Relationship graph | Join/cardinality/orphan | declared grain |
| Generated scale | volume/skew/partition shape | seed/generator/distribution |
| Fault stream | duplicate/late/reorder/gap | event identity and schedule |
| Historical schemas | evolution/rebuild | producer/schema versions |
Environment و Dependency Fidelity
| سطح | برای چه Claim مناسب است؟ | چه چیزی را اثبات نمیکند؟ |
|---|---|---|
| Pure function/local | Transform rule/property | Serialization/distribution |
| Container/component | format/schema/connector behavior | managed-service differences |
| Mini cluster | partition/state/restart mechanics | Production topology/scale |
| Shared integration | real dependencies/contracts | isolation and full workload |
| Staging-like | E2E run/publish/consumer | Production data/traffic truth |
| Shadow/canary | observed distribution/compatibility | safe business effect unless isolated |
Fidelity باید متناسب با Claim باشد. Local DataFrame برای Formula عالی است، اما Failover یا connector transaction را ثابت نمیکند. Production shadow میتواند Distribution واقعی را نشان دهد، اما اگر Side effect یا دادهٔ شخصی کنترل نشده باشد، «واقعیتر» بودن توجیه اخلاقی یا امنیتی ایجاد نمیکند.
Fault Injection برای Data Pipeline
| Fault | Injection point | Evidence مورد انتظار |
|---|---|---|
| Duplicate delivery | Producer/Source | delivery↑، business effect ثابت |
| Crash before sink commit | Processor | safe retry/recovery |
| Crash after sink commit before checkpoint | boundary | idempotent replay |
| Partial partition unavailable | Input | fail/unknown، نه publish کاملنما |
| Schema registry unavailable | Decode | bounded error policy |
| Late/reordered event | Stream | watermark/version rule |
| Sink throttling | Output | backpressure/no silent loss |
| Corrupt checkpoint | State | declared rebuild/restore path |
| Backfill overlap | Batch/Serving | isolated candidate + atomic publish |
Observability باید Claim و Identity را دنبال کند
- Run/attempt، Code، Config، Image، Schema و Input/Output snapshot ثبت شود.
- Received، accepted، rejected، quarantined، duplicate، late، too-late و unknown جدا باشند.
- Lag را با event-to-ingest، ingest-to-process و process-to-available تفکیک کنید.
- Missing partition، stalled watermark، skew، state size و sink retry قابلمشاهده باشند.
- Quality measurement به Claim، Dataset snapshot، Query/comparator version و Population متصل باشد.
- Lineage instrumentation itself با fixture و failure آزموده شود؛ فقدان event برابر نبودن dependency نیست.
run_evidence: run_id / attempt / trigger job_name / code_sha / config_hash / image_digest input datasets + snapshots + schemas + manifests output dataset + candidate commit counts by disposition key/hash/sum/state reconciliation quality measurements + thresholds + unknowns fault/retry/checkpoint/backfill evidence lineage completeness check exceptions + owner + expiry verdict + consumer/decision impact
Alert و Incident دادهای
Incident داده فقط Job failure نیست. Silent null inflation، stale snapshot، duplicate amplification، wrong-day report و schema-valid semantic drift نیز Incident هستند. Runbook باید Contain، stop publish، mark data provisional، identify affected Dataset/Run/Consumer، reconstruct lineage، compare authoritative source، choose correction/backfill، notify decision owners و verify downstream repair را پوشش دهد.
data_incident: incident_id / detected_at / detector affected claims / datasets / snapshots / consumers first_bad_run / last_known_good population and decision impact: known + unknown containment: pause alias/report/action correction: rebuild/backfill/tombstone/manual review downstream notification and acknowledgement verification: source-to-consumer reconciliation prevention: contract/test/monitor/runbook change
Release Gate خط لوله داده
| Gate | PASS | HOLD/Exception |
|---|---|---|
| Claim/contract | versioned and approved | meaning/key/time unknown |
| Compatibility | producer/consumer matrix supported | undeclared breaking change |
| Transform | examples/properties pass | oracle absent/error |
| Reconciliation | declared deltas only | missing/extra/unknown unexplained |
| Replay/backfill | isolated, deterministic for scope | unversioned input/dependency |
| Failure/recovery | critical boundaries evidenced | double effect/silent loss |
| Consumer | serving/report decision validated | pipeline-only proof |
| Evidence | run/snapshot/lineage retained safely | green screenshot only |
Exception باید Owner، Risk، affected population/consumer، compensating control، monitoring، expiry و revalidation داشته باشد. PASS خط لوله مجوز خودکار برای تصمیم مالی، پزشکی، حقوقی یا عملیاتی نیست؛ Decision Owner باید محدودیت Evidence را بداند.
سناریوی ایرانی ساختگی: خط دادهٔ پرداخت Marketplace
یک آزمایشگاه کاملاً مصنوعی برای Marketplace فرضی بسازید: Order، PaymentAttempt، Callback از PSP جعلی، Ledger، Refund و Settlement report. هیچ بانک، PSP، مشتری، فروشنده یا پول واقعی در کار نیست. داده شامل شناسههای ساختگی است و نام، موبایل، نشانی، PAN، CVV2، OTP، Token، Cookie یا Secret واقعی ندارد؛ Notificationها به Sink جعلی میروند.
| Contract | Fixture | Oracle |
|---|---|---|
| Money | canonical IRR + explicit displayed toman | no magnitude guessing/10× drift |
| Identity | tenant/order/attempt/event/run | one event → one ledger effect |
| Digits | Persian/Arabic/Latin | declared parse/reject |
| Text | Unicode/RTL labels | no key normalization collision |
| Time | UTC event + Asia/Tehran report + Jalali view | day boundary correct |
| Delivery | retry/duplicate/late/reorder | versioned current state |
| Recovery | timeout before/after fake commit | replay/reconcile, no double credit |
| Connectivity | interruption/cache/mirror/offline input | resume with manifest/checksum |
در محیط ایران، دسترسی به Artifact registry، Cloud region، Vendor SaaS، Documentation، Package mirror یا شبکه ممکن است ناپایدار باشد. Dependencyها را Pin و Cache کنید، checksum و provenance نگه دارید، مسیر Mirror/Offline restore و زمانبندی UTC/تهران را تمرین کنید و هر محدودیت تحریم/پرداخت/قرارداد را با متخصص مربوط بررسی کنید. این سناریو مشاورهٔ بانکی، مالیاتی، حقوقی، ارزی یا تحریمی نیست.
نقشها و حق تصمیم
| نقش | مسئولیت | تصمیم |
|---|---|---|
| Producer owner | source semantics/contract/evolution | producer change readiness |
| Data engineer | pipeline/state/publish/recovery | implementation remediation |
| QA/Data quality engineer | claim-to-test/oracle/evidence/faults | test verdict، نه business sign-off تنها |
| Data Product Owner | fitness/consumer/SLO/priorities | claim and exception ownership |
| Consumer/Analyst | decision semantics and validation | fit for declared use |
| Security/Privacy | access/minimization/retention | risk/authorization in scope |
| Operations | monitor/incident/backfill execution | contain/recover per runbook |
متریکهایی که تصمیم میسازند
| Metric | تعریف لازم | Countermetric |
|---|---|---|
| Claim support rate | claims with required evidence / in-scope claims | claim criticality/unknown |
| Reconciliation defects | missing/extra/wrong by population | comparator error |
| Duplicate business effect | same identity with extra effect | legitimate revisions |
| Late/too-late distribution | by source/stratum/window | clock-quality unknown |
| Freshness SLO | complete snapshot availability | correctness defects |
| Replay reproducibility | semantic match for pinned input/code | declared nondeterminism |
| Schema incident | consumer-impacting evolution | changes safely absorbed |
| Time to containment/repair | data incident milestones | impact and recurrence |
Row count، Job pass rate، تعداد تست یا Dataset size را هدف افراد نکنید. این شاخصها بهآسانی بازی میشوند و Fitness را نمیسنجند. متریک باید برای بهبود سیستم و تصمیم دربارهٔ Claim استفاده شود، نه رتبهبندی Data engineer، Analyst یا QA.
برنامهٔ ۳۰روزهٔ پیادهسازی
| بازه | کار | خروجی |
|---|---|---|
| روز ۱–۵ | یک Consumer decision و یک Claim پرریسک انتخاب کنید | map + Claim Contract |
| روز ۶–۱۰ | Dataset/Job/Run/Schema/Key/Time identity را تثبیت کنید | Data Contract + lineage map |
| روز ۱۱–۱۵ | Golden/Boundary/Relation fixtures و Oracle بسازید | transform/property tests |
| روز ۱۶–۲۰ | duplicate/late/reorder/crash/retry inject کنید | fault and recovery evidence |
| روز ۲۱–۲۵ | Replay/Backfill candidate و reconciliation اجرا کنید | semantic diff + rollback proof |
| روز ۲۶–۳۰ | Release gate، alert، incident drill و review | Evidence Pack + next risks |
ضدالگوهای رایج تست Big Data
- Big Data را فقط با 3V تعریفکردن.
- سبز بودن Job را صحت داده دانستن.
- Count برابر را Reconciliation کامل دانستن.
- Schema valid را Accuracy دانستن.
- Golden Dataset بدون نسخه و blind spot.
- Random sample بدون Population و Seed.
- ساخت Expected با همان Transform هدف.
- نداشتن Grain و Cardinality برای Join.
- تبدیل Null/Unknown به صفر بیصدا.
- حدس ریال/تومان از بزرگی عدد.
- Arrival time را Event time دانستن.
- Watermark را تضمین حذف همهٔ late data دانستن.
- Exactly-once پلتفرم را اثر کسبوکار دانستن.
- Retry/Replay با Append خام به Sink.
- Backfill مستقیم روی Output جاری.
- تست فقط latest schema pair.
- Lineage نصبشده را Lineage کامل دانستن.
- کپی Production برای «واقعگرایی».
- Alert فقط روی Job failure.
- استفاده از حجم/Pass rate برای رتبهبندی افراد.
چکلیست آمادگی انتشار Data Pipeline
- ☐ Consumer، Decision و Claim نسخهدار است.
- ☐ Source/Output Dataset و Snapshot هویت دارند.
- ☐ Job/Run/Attempt/Code/Config/Image ثبت میشوند.
- ☐ Grain، Business key، Event ID و Version روشناند.
- ☐ Schema، Meaning، Unit، Time و Null policy قرارداد دارند.
- ☐ Error/Reject/Quarantine قابلمشاهده است.
- ☐ Producer/Consumer compatibility matrix آزموده شده است.
- ☐ Golden/Boundary/Mixed-version fixture نسخهدار است.
- ☐ Oracle مستقل و blind spot ثبت شده است.
- ☐ Join cardinality/fan-out/orphan کنترل میشود.
- ☐ Aggregate denominator/window/rounding روشن است.
- ☐ Count + key + field + sum + state reconciliation اجرا میشود.
- ☐ Duplicate/late/reorder/gap fault پوشش دارد.
- ☐ Watermark/too-late/correction policy روشن است.
- ☐ Source replay و Sink idempotency جدا اثبات شدهاند.
- ☐ Replay/Backfill در Candidate جدا و با Rollback است.
- ☐ PII/Secret/Production data در تست کنترل شده است.
- ☐ Observability به Claim/Run/Snapshot وصل است.
- ☐ Incident و downstream repair تمرین شده است.
- ☐ PASS/FAIL/ERROR/INCONCLUSIVE و Exception expiry تعریف شدهاند.
جمعبندی
تست Big Data هنر اجرای ابزارهای بزرگ نیست؛ مهندسی شواهد برای یک ادعای دادهای محدود است. وقتی Source Contract، هویت Dataset/Run، Oracle مستقل، سیاست زمان و Duplicate، Reconciliation چندلایه و Replay قابلبازتولید دارید، Job موفق معنای قابلاستفاده پیدا میکند. بدون این زنجیره، حتی سریعترین Pipeline ممکن است عددی دقیقنما اما نامناسب برای تصمیم تولید کند.
پرسشهای متداول تست Big Data
۱. تفاوت تست Big Data با تست ETL چیست؟
تست ETL معمولاً بر استخراج، تبدیل و بارگذاری و Data Warehouse تمرکز دارد. تست Big Data در این مقاله دامنهٔ وسیعتر Batch/Streaming، Event time، Duplicate، Late data، State، Schema evolution، Replay و Consumer decision را پوشش میدهد. مرز به معماری وابسته است و این دو میتوانند همپوشانی داشته باشند.
۲. آیا برابری تعداد رکورد Source و Target کافی است؟
خیر. یک رکورد گم و یک رکورد اضافه Count را برابر نگه میدارد. Key set، Duplicate، Field diff، Aggregate، Relation، Temporal state و Business effect نیز باید متناسب با Claim مقایسه شوند.
۳. Watermark چه چیزی را تضمین میکند؟
Watermark یک سیاست Event-time برای نهاییسازی Window و محدودکردن State است؛ جزئیات تضمین به Engine، Operator، Output mode، چند Stream و Configuration وابسته است. آن را وعدهٔ عمومیِ دریافت یا حذف همهٔ دادههای دیررس ندانید و too-late/correction policy را جدا تعریف کنید.
۴. آیا Exactly-once یعنی اثر کسبوکار فقط یکبار است؟
نه لزوماً. باید Scope دقیق Source، Processor، State، Sink و Failure model را خواند. نوشتن به Database، Ledger، API، Email یا Actuator خارجی ممکن است Idempotency، Transaction یا Reconciliation جدا بخواهد.
۵. تیم کوچک تست Data Pipeline را از کجا شروع کند؟
یک Consumer decision و یک Claim پرریسک را انتخاب کند؛ سپس Data Contract، یک Golden/Boundary fixture، یک Oracle مستقل، Reconciliation کلید/مبلغ، Duplicate/late fault و Replay از Snapshot ثابت را بسازد. پوشش کوچک اما تصمیممحور از فهرست ابزارهای بزرگ ارزشمندتر است.

