Zero-Copy, Multi-Protocol Storage: The Architecture Pattern Data Pipelines Are Missing

작성자

카테고리:

← 피드로
DEV Community · Varun Seth · 2026-08-27 개발(SW)

Every cloud architecture diagram you’ve ever drawn for a “modernize the legacy system” project probably has the same box in it: a sync job. Something that watches an old file share and copies what it finds into S3, so the new, shiny, event-driven, AI-powered part of the stack has something to read.

That box is a lie we tell ourselves. It says “the data is now in the cloud.” What it actually means is: there are now two copies of the data, and something has to keep them the same.

This post is about a pattern that gets rid of that box entirely — zero-copy, multi-protocol storage — and a proof of concept I built on Amazon FSx for NetApp ONTAP (FSxN) that uses it to turn an insurance claims intake pipeline into something that reacts in seconds instead of on the next scheduled sweep.

The concept: one copy, reached two ways

“Multi-protocol” storage means the same underlying data can be accessed through more than one protocol — SMB, NFS, and the S3 API, in this case — without translation, replication, or a gateway service in between. “Zero-copy” means that when a second consumer reads the data through a different protocol, it isn’t reading a copy. It’s reading the same bytes, through a different door.

That distinction sounds academic until you draw the two architectures next to each other.

The bridge pattern (what most teams build):

flowchart LR
    A[Legacy system<br/>writes over SMB/NFS] --> B[File share]
    B --> C[Sync job / gateway]
    C --> D[S3 bucket]
    D --> E[Cloud-native processing]

The zero-copy pattern:

flowchart LR
    A[Legacy system<br/>writes over SMB/NFS] --> B[(Same volume)]
    B -- "S3 Access Point<br/>(no copy)" --> E[Cloud-native processing]

In the bridge pattern, every file exists twice, on two different consistency models, and something — a Lambda, a cron job, a Kafka Connect worker — is responsible for making sure copy two matches copy one. That something adds latency (the sync interval), cost (storage twice over, plus the compute to move it), and a new failure mode: drift. When copy two is wrong, is it a bug in the sync job, a race condition, a partial failure that never retried? Now you’re debugging a distributed consistency problem to answer a question that shouldn’t have existed.

Amazon FSx for NetApp ONTAP removes the sync job because ONTAP volumes are natively multi-protocol. The same volume can be exported as an NFS share, a CIFS/SMB share, and fronted by an S3 Access Point that serves GetObject calls straight off the underlying blocks. No object gets written to S3 — the Access Point is a read path into the existing volume. One copy of the data. Two (or three) ways to reach it, chosen by whatever’s most convenient for the consumer: a legacy Windows app keeps mapping a network drive; a Lambda function calls boto3.client("s3").get_object().

Why this matters more than it sounds like it should

The obvious win is cost and reduced operational surface — no second storage tier, no reconciliation logic, one less system that pages someone at 2am. But the bigger win is architectural: it changes what “real-time” means for systems that were never designed to be real-time.

Legacy file-based systems don’t emit events. They write files. If your AI/analytics layer only exists downstream of a sync job, your event is “the sync job ran,” not “the document arrived.” You’ve inherited the legacy system’s batch cadence even though you built a completely event-driven pipeline on top of it.

Zero-copy access solves the read side of that problem — cloud compute can see the file the instant it exists, with no propagation delay. But you still need something to solve the notification side: how does anything know to look? That’s where the second piece of this pattern comes in, and it’s the part that took empirical testing, not documentation reading, to get right.

The business use case: First Notice of Loss (FNOL) intake

Insurance claims intake is a good stress test for this pattern because it has all three of the constraints that make the bridge pattern painful:

  1. The producers can’t change. Adjusters, body shops, and legacy claims-management systems attach photos and PDFs over SMB, because that’s what their software has spoken for twenty years. Nobody is rewriting a claims system’s file-attach code to call an S3 SDK.
  2. The consumer wants to be modern. You want Bedrock reading damage photos and extracting claim data the moment they land, not on a nightly batch — fraud gets easier to hide the longer extraction is delayed, and customers notice slow claims.
  3. The evidence has to survive a legal challenge. A claim’s supporting documents may end up in a dispute or a fraud investigation years later. “Our database says this file was received at this time” is a much weaker claim than “our storage system created an immutable, undeletable snapshot of this exact file at this exact time” — the former can be edited by anyone with database access; the latter cannot, by construction.

I built a proof of concept — fsx-ontap-fnol-poc — around exactly this: a simulated claims system writes a photo and a claim form over SMB to an FSxN volume, and from that single write, a serverless pipeline does real-time AI extraction and creates tamper-evident audit evidence, with zero code or workflow changes on the writer’s side.

How the pieces fit together

flowchart TD
    subgraph client["Claims system (simulated)"]
        EC2["EC2 demo client<br/>SMB write"]
    end

    subgraph fsxn["Amazon FSx for NetApp ONTAP"]
        VOL["Claim intake volume<br/>(NTFS security, AD-joined SVM)"]
        SNAP["Snapshots / SnapLock WORM"]
        S3AP["S3 Access Point<br/>(zero-copy read)"]
    end

    subgraph events["Event-driven automation"]
        FPOL["FPolicy engine"]
        ECS["ECS Fargate<br/>FPolicy TCP server"]
        SQS["SQS queue"]
    end

    subgraph compute["Serverless processing"]
        CP["claim_processor Lambda<br/>Bedrock AI extraction"]
        DDB["DynamoDB<br/>claims table"]
        STREAM["DynamoDB Streams"]
        ES["evidence_stamper Lambda"]
    end

    DASH["Streamlit dashboard"]

    EC2 -- "1. write claim files" --> VOL
    VOL -- "2. file_close event" --> FPOL
    FPOL -- "3. TCP notify" --> ECS
    ECS -- "4. normalize + enqueue" --> SQS
    SQS -- "5. trigger" --> CP
    CP -- "6. zero-copy read" --> S3AP
    S3AP -.-> VOL
    CP -- "7. extracted JSON + fraud score" --> DDB
    DDB -- "8. change event" --> STREAM
    STREAM --> ES
    ES -- "9. snapshot / SnapLock" --> SNAP
    DDB -- "live claims + timing" --> DASH

Four things do the load-bearing work here:

  • The write itself is the trigger. ONTAP’s FPolicy mechanism fires a file_close event the instant a claim document finishes writing over SMB. An ECS-hosted TCP server receives that notification and drops a normalized message on SQS. There’s no polling, no bucket-notification workaround — the pipeline starts within seconds of the document landing.
  • Reading is zero-copy. The Lambda that calls Bedrock for damage assessment and fraud scoring never touches the SMB share. It reads the file through the S3 Access Point — same bytes, S3 API. No second copy exists anywhere in this pipeline.
  • Evidence is storage, not a database row. The moment a claim is processed, an ONTAP Snapshot captures its directory — a point-in-time, storage-level record of exactly what was submitted, independent of any application’s audit log. Claims the AI flags as high fraud-risk get promoted further, to a SnapLock WORM volume, making that evidence legally undeletable rather than merely access-controlled.
  • None of the enterprise storage properties disappear. AD-integrated access control, existing backup/DR posture, multi-protocol NAS — it’s all still the same ONTAP volume underneath. The AI and serverless layer is additive. This is a migration nobody has to notice.

The finding that mattered: not every protocol triggers events

Here’s the part that separates “read the docs and build it” from “actually validate the thing you’re relying on.” The natural assumption going in was that any write to the volume — over SMB, NFS, or the S3 Access Point — would fire an FPolicy event, since it’s the same underlying volume regardless of which door you walked through.

That assumption is wrong, and it only cost nothing to find out because it was tested empirically against a live deployment before the architecture was locked in: writes through the S3 Access Point never generate an FPolicy notification, regardless of security style or which ONTAP file operations are enabled. FPolicy is wired to the NAS protocol stack (SMB/NFS), not to the S3 gateway path. That’s why this pipeline uses SMB as the sole ingestion trigger and keeps the S3 Access Point strictly for zero-copy reads on the compute side — the two protocols play different roles in the same architecture, and conflating them would have quietly broken the “process within seconds” promise for any client that happened to write through S3 instead.

The lesson generalizes past this one POC: multi-protocol storage gives you multiple ways to read and write the same data — it does not mean every protocol has identical semantics. If your architecture depends on an event, a lock, or a consistency guarantee, verify it against the actual protocol you’re using for that operation, not against “the storage layer” in the abstract.

What this pattern is actually worth

Numbers from the working POC: a live end-to-end run — SMB write, FPolicy notification, SQS, Bedrock extraction, DynamoDB write, ONTAP snapshot — consistently completes in a few seconds from SQS receipt to the DynamoDB write, with Bedrock inference dominating that latency. The S3 Access Point read is visible immediately after the SMB write completes, with no measurable consistency delay found across single or concurrent (20-way) writes on either SMB or NFS.

Compare that to the bridge-pattern alternative: a sync job on some interval (5 minutes if you’re aggressive, an hour if you’re not), a second S3 bucket to secure and pay for, and a reconciliation process to catch the writes that didn’t sync. The zero-copy version isn’t a faster version of that pipeline — it’s a different pipeline that doesn’t have that failure mode to begin with.

Where this generalizes beyond insurance

FNOL intake is the use case in this POC, but the underlying shape — legacy protocol writers, cloud-native readers, one copy of the data, an audit trail that can’t be edited after the fact — shows up anywhere a regulated or slow-moving system produces files that a modern pipeline needs to react to quickly:

  • Healthcare document intake (HL7/DICOM writers, AI triage readers)
  • Legal e-discovery (case-management systems writing over SMB, cloud search/classification reading over S3)
  • Manufacturing/quality systems dropping inspection images from shop-floor NAS shares
  • Any compliance-heavy workflow where “the database says we received it” isn’t a strong enough claim

The pattern is the point, not the insurance angle. If you’ve got a bridge-pattern sync job in your architecture today, it’s worth asking whether the storage underneath it is actually capable of serving both sides directly — because the box you’re trying to eliminate might not need to exist at all.

The full proof of concept — Terraform for the FSxN/ECS/Lambda/DynamoDB stack, the FPolicy TCP server, the Bedrock-backed claim processor, and the empirical protocol tests referenced above — is on GitHub at varunrai/fsx-ontap-fnol-poc

원문에서 계속 ↗