OTel Arrow and Columnar Encoding in OpenTelemetry
A deep, plain-English guide to how OpenTelemetry Protocol with Apache Arrow rearranges telemetry from rows into columns, why that shrinks network traffic so dramatically for busy pipelines, how it works in the Collector, and when it is, and is not, worth using.
Imagine you run a school and must send the exam results of ten thousand students to the head office. The simple way is to send one sheet per student: name, class, subject, score, name, class, subject, score, and so on, over and over. The head office receives a mountain of paper, and most of it repeats itself: the same class names, the same subject names, the same dates. Now imagine a smarter way. You send one list of class names, one list of subject names, and then a compact table that just says “student 17, class number 3, subject number 5, score 82”. Almost nothing repeats, and the package is a fraction of the size. That change, from repeating everything row by row to organising information column by column, is the heart of OTel Arrow.
This guide explains that idea in the world of OpenTelemetry. We begin with why moving telemetry is expensive, build up the vocabulary of rows, columns, and Apache Arrow, then look closely at how the OpenTelemetry Protocol with Apache Arrow encodes and streams data, how it appears in the Collector, how to size and deploy it, and what it costs. No prior knowledge is assumed.
1The Problem: Moving Telemetry Is Expensive
Before we meet any new protocol, we need to feel the cost that it tries to reduce.
Telemetry is a lot of data
Telemetry is the information that software produces about itself: traces that follow requests, metrics that count and measure, and logs that record events. A modern system with hundreds of services can produce millions of these records every minute. Each record carries many details: names, labels, timestamps, identifiers, and values. When you add them all up, the volume is enormous.
All of that data must travel. It leaves applications, passes through collectors and gateways, crosses networks, and reaches a backend where it is stored and queried. Every step of that journey costs something.
Think of shipping goods between two cities. The cost depends not only on what you ship but on how you pack it. A truck full of loosely packed boxes, each with its own wrapping and its own label, costs far more than the same goods packed tightly on pallets. Telemetry is the same: how you pack it decides what it costs to move.
Where the cost shows up
Network egress charges
Cloud providers often charge for data that leaves a region or a cloud. Telemetry sent across regions or to an external vendor can become a surprisingly large line on the bill.
Bandwidth limits
Remote sites, edge locations, and shared links have limited capacity. Telemetry competes with business traffic for the same pipe.
Processing time
Every byte must be encoded, sent, received, decoded, and often copied. The processor time spent on these steps adds up across a large fleet.
Vendor ingestion limits
Some backends limit or charge for the volume received. Shrinking the bytes on the wire can ease limits and lower charges.
Reducing telemetry has two very different strategies. You can send less data, by sampling and filtering, or you can send the same data in a smaller package. OTel Arrow belongs to the second family: same information, fewer bytes.
Why simply compressing is not the whole answer
The standard way to shrink data on the network is compression, using general-purpose tools that look for repeated patterns in a stream of bytes. Compression helps a great deal and is already widely used. But a general-purpose compressor sees only a stream of bytes. It does not know that one stretch of bytes is a service name and another is a timestamp. If the data is arranged in a way that scatters similar values far apart, even a good compressor misses many chances to shrink it. Arranging the data so that similar values sit side by side gives the compressor a much better starting point, and that is the opportunity columnar encoding creates.
2Foundations You Need First
A short, friendly refresher on the pieces of OpenTelemetry that OTel Arrow builds on.
OpenTelemetry in one paragraph
OpenTelemetry, often shortened to OTel, is an open standard and a set of tools for producing and moving telemetry. Applications use SDKs to create traces, metrics, and logs. A separate program called the Collector receives that telemetry, processes it, and forwards it to backends. The standard format used between these pieces is called the OpenTelemetry Protocol, or OTLP.
The building blocks
OTLP
The native language of OpenTelemetry, a description of how traces, metrics, and logs are laid out when they are sent.
Protocol Buffers
A compact way to turn structured records into bytes. OTLP messages are described and encoded with it.
gRPC
A common way for programs to call each other over a network. OTLP is carried by gRPC or by plain web requests.
Collector
The program that receives, processes, and exports telemetry using receivers, processors, and exporters.
Batch
A group of many records sent together in a single message, which is more efficient than sending them one at a time.
Compression
A general technique that shrinks bytes on the wire, commonly applied on top of OTLP.
How OTLP lays out data: a nested tree
OTLP organises telemetry as a tree. At the top is a resource, which describes where the data came from, such as a particular service running on a particular machine. Under each resource are one or more scopes, which describe the library that produced the data. Under each scope are the actual records: spans for traces, data points for metrics, and log records for logs. Each record carries its own list of attributes, which are named labels such as “http method” or “customer region”.
flowchart TD
R["Resource: service and host details"] --> S1["Scope: instrumentation library A"]
R --> S2["Scope: instrumentation library B"]
S1 --> A1["Span 1 with its own attributes"]
S1 --> A2["Span 2 with its own attributes"]
S2 --> A3["Span 3 with its own attributes"]
This tree is natural and easy to understand, and it already saves some repetition, because details about the resource and the scope are written once instead of on every record. But inside each record, the attribute names and many values still repeat again and again.
Many people think OTel Arrow replaces OpenTelemetry’s data model. It does not. The meaning of the data, spans, metrics, logs, resources, and attributes, stays exactly the same. Only the way the data is arranged for transport changes.
3Rows Versus Columns: The Big Idea
The whole story of OTel Arrow rests on one simple choice: how to arrange a table of information.
Row-oriented layout
Picture a spreadsheet of spans. Each row is one span, and the columns are fields such as service name, operation name, start time, duration, and status. A row-oriented layout writes the data row by row: all the fields of span one, then all the fields of span two, then span three, and so on. This is how most people naturally think about records, and it is how OTLP encodes data inside each batch.
Column-oriented layout
A column-oriented layout writes the same table column by column: first every service name from every span, then every operation name, then every start time, then every duration. Nothing about the information changes. You can rebuild any row by reading the same position in each column. But the bytes sit in a very different order.
flowchart LR
subgraph ROW["Row layout"]
R1["span 1: checkout, pay, 10:00, 120ms"]
R2["span 2: checkout, pay, 10:01, 95ms"]
R3["span 3: checkout, cart, 10:01, 40ms"]
end
subgraph COL["Column layout"]
C1["service: checkout, checkout, checkout"]
C2["operation: pay, pay, cart"]
C3["start: 10:00, 10:01, 10:01"]
C4["duration: 120, 95, 40"]
end
Why columns compress so well
Look at the column layout above. The service column contains “checkout” three times in a row. The operation column contains “pay” twice. The start times are close together. Values in the same column tend to be similar to each other, because they all describe the same kind of thing. When similar values sit side by side, simple tricks can shrink them enormously.
Dictionary encoding
Store each distinct value once in a list, and replace every occurrence with a small number pointing into the list.
Run-length encoding
When the same value repeats many times in a row, store the value once and say how many times it repeats.
Delta encoding
For numbers that grow steadily, such as timestamps, store the first number and then only the small differences between neighbours.
Better byte compression
After these tricks, the general compressor still runs, and it finds even more patterns because similar bytes are now adjacent.
Imagine packing a suitcase. If you throw in one item after another as you pick them up, socks end up scattered among shirts and shoes, and the suitcase is lumpy and wasteful. If you pack by category, all socks together, all shirts folded in a stack, all shoes in a row, everything fits tightly. Columnar layout is packing by category.
Columns also help computers read faster
Columns are friendly to computer hardware as well. Processors work best when they handle long runs of the same kind of value, because they can process several values in one step. Many analytical databases store data by column for exactly this reason. OTel Arrow borrows that long-proven idea and applies it to telemetry in motion.
Columnar layout pays off most when batches are large and the data is repetitive. A tiny batch with all-different values has little repetition to exploit. That is why this approach shines on busy links and large batches rather than on single small messages.
4Apache Arrow in Plain Words
The “Arrow” in OTel Arrow is a well-known open standard for columnar data. Knowing what it is makes the rest easy.
What Apache Arrow is
Apache Arrow is an open standard for representing tables of data in columnar form. It defines exactly how each column is laid out in memory, how missing values are marked, how text and nested values are stored, and how groups of columns are packaged together. It is used widely in data analysis tools, databases, and data engineering pipelines, and it has libraries in many programming languages.
Key ideas in Arrow
Columnar memory
Each column’s values sit together in one block, making scans and compression efficient.
Record batch
A group of equal-length columns that together represent a chunk of a table, the basic unit that is sent and processed.
Schema
A description of the columns in a record batch: their names, their types, and whether they may be missing.
Dictionary arrays
A column type that stores distinct values once and refers to them by number, built into the standard.
Streaming format
A way to send a schema once, followed by a sequence of record batches, which suits long-lived connections.
Language neutrality
Because the layout is standardised, a program written in one language can read data produced by another without translation.
Arrow is like the standard shipping container of data. Before containers, every port handled cargo differently. After containers, any ship, crane, and truck could move the same box. Arrow gives data tools a shared box format, so they can pass tables to each other without unpacking and repacking.
Why Arrow suits streaming telemetry
Three Arrow features line up well with telemetry. The streaming format lets a sender transmit the description of the columns once and then keep sending batches that follow it. Dictionary arrays let repeated names and values be sent once and reused. And the whole design favours long runs of similar values, which is exactly what telemetry from a busy service looks like.
Apache Arrow is a general data standard that existed long before this project. OTel Arrow is the OpenTelemetry project’s way of using Arrow for telemetry transport. They are related but not the same thing.
5What OTel Arrow Really Is
Now we can state the idea precisely and place it in the OpenTelemetry world.
A working definition
OTel Arrow is the name of an OpenTelemetry project that defines and implements a way of sending the same traces, metrics, and logs as OTLP, but encoded with Apache Arrow in columnar form and sent over long-lived streaming connections. The protocol is often called OTAP, the OpenTelemetry Protocol with Apache Arrow. It is designed as a companion to OTLP, not a replacement for it.
What stays the same and what changes
| Aspect | OTLP | OTel Arrow |
|---|---|---|
| Meaning of the data | Resources, scopes, spans, metrics, logs, attributes | The same |
| Layout on the wire | Nested tree, row by row | Related tables, column by column |
| Connection style | Separate request for each batch | Long-lived stream of batches |
| Repeated names and values | Repeated in each record | Stored once in dictionaries and referred to by number |
| Typical network size | Larger | Smaller for large, repetitive batches |
| Processor effort to encode | Lower | Higher |
| Support in backends | Very broad | Narrow, usually converted back to OTLP |
A bridge, not a rewrite
The most important design choice is that OTel Arrow is meant to live alongside OTLP. Applications keep using the normal SDKs and OTLP. The savings are collected at the hops between Collectors, especially long or expensive ones. A sender converts OTLP data into Arrow form, ships it compactly, and a receiver at the other end converts it back to OTLP. Every other part of your system sees ordinary OTLP and never needs to know that Arrow was used in the middle.
flowchart LR
APP["Applications with standard SDKs"] -->|"OTLP"| E["Edge Collector"]
E -->|"OTel Arrow, compact"| G["Gateway Collector"]
G -->|"OTLP"| BE["Backend"]
Think of an international flight between two cities. Before and after the flight, you travel by ordinary roads. The aircraft is the fast, efficient section for the long, expensive distance. OTel Arrow is the aircraft for the long hop of your telemetry journey. The roads at each end stay as they were.
Where the project came from
The work began as a collaboration between engineers at observability companies who were looking for ways to cut the cost of moving very large volumes of telemetry. They published the design and the first implementations openly, and the work was contributed to the OpenTelemetry community, where it is developed in its own repository alongside the main project. The first implementation focuses on Collector components written in Go. Later work explores a more native Arrow-based processing engine, so the project continues to evolve.
The components, their stability levels, and even some design details of OTel Arrow have been changing as the project matures. Treat the descriptions in this guide as a map of the ideas, and confirm exact settings and stability with the project’s current documentation before you depend on them.
6How OTel Arrow Arranges Telemetry
The tree of OTLP becomes a small family of related tables. Understanding this step explains most of the savings.
From a tree to related tables
OTLP stores telemetry as a nested tree. Columnar formats like Arrow work with flat tables, so OTel Arrow first reorganises the tree into several tables that point to each other. This is the same idea that relational databases use: instead of copying details into every row, you keep each kind of detail in its own table and connect them with short identifiers.
For traces, the main table holds one row per span, with columns such as trace identifier, span identifier, name, start time, duration, and status. Separate tables hold the pieces that vary in size: the attributes of the resource, the attributes of the scope, the attributes of each span, the events that happened inside spans, the links between spans, and the attributes of those events and links. Each of these side tables refers back to its parent row with a small number.
flowchart TD
SP["Spans table: one row per span"]
RA["Resource attributes table"]
SA["Scope attributes table"]
PA["Span attributes table"]
EV["Span events table"]
EA["Event attributes table"]
LK["Span links table"]
LA["Link attributes table"]
SP --- RA
SP --- SA
SP --- PA
SP --- EV
EV --- EA
SP --- LK
LK --- LA
Why side tables help
Take the attributes of a span, such as the HTTP method, the route, and the status code. In OTLP, each span carries its own list of named attributes, so the name “http.method” is written again for every span. In the columnar form, all attributes go into one attributes table with three kinds of columns: the owner (which span), the key (the attribute name), and the value. The key column then contains the same few names repeated, which dictionary encoding turns into tiny numbers. The value column can be stored by type, with separate columns for text, whole numbers, decimals, and true or false values, so that each column holds values of one kind.
Main signal table
One row per span, data point, or log record, holding the fields that every record has.
Attribute tables
Rows of owner, key, and typed value. They replace the repeated named labels inside each record.
Child record tables
Events, links, exemplars, and similar sub-records, each in its own table pointing back to its parent.
Resource and scope tables
Descriptions of where data came from, stored once and referenced by number rather than copied.
Sorting to create runs
The sender can also reorder rows within a batch before encoding, because telemetry records within a batch do not depend on their order. Sorting by fields such as resource, scope, or name puts identical values next to each other, lengthening runs of repeats. Longer runs mean better compression. This is a classic trick from the world of analytical databases, applied here to telemetry in transit.
Imagine a library moving ten thousand books. If every book is shipped with a full description card stapled inside, the same publisher address is repeated ten thousand times. If instead you ship a separate card index of publishers and write only a small publisher number on each book, the shipment is much lighter. Sorting books by publisher makes the shipping manifest shorter still.
The same idea for metrics and logs
Metrics follow the same pattern with their own tables. There is a table of metric descriptions, and tables for the different kinds of data points, such as plain numbers, histograms, and summaries, each with its own attribute table and, where relevant, a table of exemplars, which are sample traces linked to a metric value. Logs use a main table of log records and an attribute table. The principle is identical: keep each kind of detail in a tidy column, and refer to shared pieces by number.
The exact names of tables and columns, and the fine points of the encoding, are defined in the project’s specification and may change between versions. The structure described here is the stable idea. For exact details, consult the current specification.
7The Streaming Protocol
OTel Arrow does not just change the layout. It also changes how batches travel, using long-lived streams that remember what has already been sent.
From many requests to one stream
With classic OTLP over gRPC, each batch is a separate request and response. Every request is independent, so nothing is remembered between them. OTel Arrow instead opens a bidirectional stream: a single long-lived connection over which the sender keeps pushing batches, and the receiver keeps sending back acknowledgements. Because the stream stays open, both sides can keep shared state.
Schemas and dictionaries are sent once
The first message on a stream carries the description of the columns, the schema, and the initial contents of the dictionaries, the lists of distinct values such as service names and attribute keys. Later messages carry only what is new: the actual rows, plus any dictionary entries that were not seen before. A value that has already been sent is referred to by its number. This is the delta idea, and it is where much of the long-run saving comes from.
sequenceDiagram
participant S as Sender
participant R as Receiver
S->>R: Open stream
S->>R: Batch 1 with schema and full dictionaries
R-->>S: Acknowledge batch 1
S->>R: Batch 2 with rows and only new dictionary entries
R-->>S: Acknowledge batch 2
S->>R: Batch 3 with rows and few new entries
R-->>S: Acknowledge batch 3
Note over S,R: Each later batch is smaller because shared values are already known
Acknowledgements keep delivery honest
For every batch the sender transmits, the receiver replies with a status that says whether the batch was accepted, whether it failed temporarily so that it can be retried, or whether it failed permanently. This gives the sender the same kind of reliability signal it gets from separate request and response calls in classic OTLP, while still using one long connection. The sender also learns when the receiver is overloaded and can slow down.
State has a price
Because both ends remember dictionaries and schemas, each open stream occupies memory on the receiver. If the stream breaks, that remembered state is lost, and the sender must open a new stream and start again with a full schema and dictionaries. Well-designed senders also close streams on purpose after a chosen lifetime and open fresh ones, which keeps the remembered state from growing without limit and helps spread load across receivers.
Convert
The sender takes a batch of OTLP data and rearranges it into columns and tables.
Encode with dictionaries
Repeated names and values are replaced with numbers, and only new dictionary entries are included.
Send on the stream
The encoded batch is transmitted on an open stream, usually with general compression applied on top.
Decode and rebuild
The receiver applies the dictionaries, reads the tables, and rebuilds ordinary OTLP data.
Acknowledge
The receiver reports success or failure for the batch so the sender can retry or move on.
Graceful fallback to OTLP
A sender that tries to use OTel Arrow with a receiver that does not understand it must not simply fail. The design allows a sender to detect that Arrow is not supported and fall back to standard OTLP, so that data keeps flowing, only at the normal size. This makes it safe to roll out gradually, and it protects you from outages caused by mismatched versions.
Because of the fallback, you can upgrade senders and receivers in any order. During the transition some traffic will flow as plain OTLP. Watch the metrics that report fallbacks so you know when the transition is complete.
8Why It Compresses So Well: A Worked Example
Numbers make the idea concrete. The figures below are illustrative, chosen to show the mechanism rather than to promise a particular result.
The batch
Suppose a batch holds 1,000 spans from one service. The spans share the same resource and scope. There are only 5 different service operations in the batch. Each span has 8 attributes, and the names of those attributes, such as the method, the route, the region, and the status code, are the same set of 8 names for every span. The start times are all within a one-second window, and the durations are small whole numbers.
Row by row
In a row-oriented layout, the operation name is written 1,000 times, once per span. The 8 attribute names are written 8,000 times in total. Every start time is written as a full-size number. Even with a good general compressor, which will notice many repeats, the compressor must discover these patterns while scanning a mix of different kinds of bytes.
Column by column
| Column | What it holds | Technique | Effect |
|---|---|---|---|
| Operation name | 1,000 values from only 5 distinct names | Dictionary plus sorting | Five names stored once, then 1,000 tiny numbers in long runs |
| Attribute key | 8,000 values from only 8 distinct names | Dictionary | Eight names stored once, then 8,000 tiny numbers |
| Start time | 1,000 close-together numbers | Delta encoding | One full number, then 999 small differences |
| Duration | 1,000 small whole numbers | Compact integer storage | Few bytes per value |
| Status code | 1,000 values, mostly identical | Run-length encoding | A handful of runs instead of 1,000 entries |
| Resource and scope | Identical for all spans | Stored once and referenced | Written a single time |
The effect grows with scale and repetition
Savings rise with the size of the batch, because the one-off cost of the dictionary is spread over more rows. They also rise with repetition: the more the same names and values appear, the more the dictionaries pay off. And they continue to improve over the life of a stream, because later batches can reuse dictionary entries that were sent earlier.
A phone book that prints every person’s full city name on each line is long. A phone book that prints “city 3” next to each name and lists the cities once at the front is far shorter. The more people live in the same few cities, the bigger the saving.
When the saving is small
Conditions that favour large savings
- Large batches with thousands of records
- Many repeated names, labels, and values
- Long-lived streams that reuse dictionaries
- Data from a few services with consistent attributes
- Steady timestamps and small numeric values
Conditions that reduce the saving
- Very small batches with little to share
- Attributes full of unique values, such as identifiers
- Large free-text fields, such as long log messages
- Short-lived streams that keep restarting
- Data that was already heavily reduced by sampling
Published benchmarks show that the size reduction can be large for suitable data, but results depend strongly on your own telemetry. Test with a sample of your real traffic before you plan around any number you read, including those in this guide.
9OTel Arrow in the Collector
In practice, you meet OTel Arrow as a pair of Collector components: one that sends and one that receives.
The two components
OTel Arrow exporter
Takes data inside the Collector, converts it to Arrow form, and sends it on streams to a receiver that understands the protocol. It can fall back to plain OTLP when needed.
OTel Arrow receiver
Accepts Arrow streams, rebuilds ordinary telemetry, and hands it to the pipeline. It can also accept plain OTLP on the same endpoint.
Both components handle traces, metrics, and logs. They are distributed in the community contributions collection, so they are present in the contrib distribution and can be added to a custom build. Their stability level has been evolving, so check the component documentation for your version.
Where they sit in a pipeline
flowchart LR
subgraph EDGE["Edge Collector"]
R1["OTLP receiver"] --> P1["Processors and batching"] --> X1["OTel Arrow exporter"]
end
subgraph CENTRAL["Gateway Collector"]
R2["OTel Arrow receiver"] --> P2["Processors"] --> X2["OTLP exporter"]
end
X1 -->|"Arrow streams"| R2
X2 --> BE["Backend"]
The settings that matter, in plain words
Number of streams
How many parallel streams the exporter keeps open. More streams spread load and increase throughput, at the cost of more memory on both sides.
Stream lifetime
How long a stream may live before it is closed and replaced. Shorter lifetimes help rebalance across receivers and limit remembered state.
Fallback behaviour
Whether the exporter may fall back to plain OTLP if the receiver does not support Arrow. Allowing it is safer during rollout.
Stream prioritisation
How the exporter chooses which stream receives the next batch, for example the one with least work waiting.
Receiver memory limits
How much memory the receiver may use for stream state and incoming data, so that busy or hostile senders cannot exhaust it.
Admission control
Limits on how much data may be accepted or wait to be accepted at one time, protecting the receiver under load.
Working with the rest of the Collector
The batch processor, placed before the Arrow exporter, decides how large the batches are. Bigger batches give the encoder more repetition to exploit, so tuning batch size is one of the most effective ways to improve the saving. The memory limiter protects the Collector from running out of memory, and works alongside the Arrow receiver’s own limits. If you use a persistent queue on the exporter, the queued items are stored in the Collector’s ordinary form and converted to Arrow as they are sent.
Start with defaults and measure. Change one setting at a time, such as batch size or number of streams, and compare network bytes, processor use, and delay before and after each change.
The savings only happen when the sender uses the Arrow exporter and the receiver runs the Arrow receiver. If only one end is upgraded, traffic quietly falls back to plain OTLP, and your bill stays the same. Verify with metrics that Arrow streams are really in use.
10Architecture Patterns
The savings appear where data crosses long or expensive links. Choosing the right place for the Arrow hop matters more than anything else.
Pattern A: Edge to gateway over a limited link
Collectors at remote sites, branch offices, or factories send to a central gateway across a slow or costly connection. An Arrow hop on that link reduces the bytes crossing it, leaving more capacity for other traffic and making the telemetry arrive sooner during busy periods.
Pattern B: Across regions or clouds
Cloud providers often charge for data that moves between regions or leaves the cloud. A Collector in each region can compress telemetry with Arrow before sending it to a central region, cutting the charge for the cross-region hop.
flowchart LR
subgraph R1["Region 1"]
A1["Services"] --> C1["Regional Collector"]
end
subgraph R2["Region 2"]
A2["Services"] --> C2["Regional Collector"]
end
C1 -->|"OTel Arrow across regions"| CEN["Central gateway"]
C2 -->|"OTel Arrow across regions"| CEN
CEN -->|"OTLP"| BE["Backend"]
Pattern C: The last mile to a backend
If your backend or vendor offers an endpoint that speaks OTel Arrow natively, the final hop from your gateway can also use it, saving egress to the outside world. This depends on the backend’s support, which is still uncommon, so check with your vendor before planning around it.
Pattern D: Tiered fan-in
Large estates often have several layers of Collectors, each aggregating many senders. Where the layers are far apart or numerous, Arrow can be used on each long hop, while the short hops near applications remain plain OTLP.
Where not to use it
The hop between an application’s SDK and a Collector on the same machine is short and cheap, and the batches are usually small. Arrow adds encoding effort without saving anything meaningful there. Keep that hop on ordinary OTLP.
| Hop | Typical batch size | Network cost | Benefit of Arrow |
|---|---|---|---|
| SDK to local agent | Small | Negligible, same machine | Little, not recommended |
| Agent to gateway in the same data centre | Medium | Low | Modest, depends on volume |
| Edge site to central gateway | Large | High, limited bandwidth | Large |
| Region to region or cloud to cloud | Large | High, often charged | Large |
| Gateway to vendor over the internet | Large | High, often charged | Large if vendor supports it |
flowchart TD
Q1{"Is the hop long, costly, or bandwidth limited?"} -->|"No"| N["Keep plain OTLP"]
Q1 -->|"Yes"| Q2{"Are batches large and repetitive?"}
Q2 -->|"No"| N
Q2 -->|"Yes"| Q3{"Can both ends run Arrow components?"}
Q3 -->|"No"| N
Q3 -->|"Yes"| Y["Use OTel Arrow on that hop"]
Look at your network bill and your link usage first. Apply Arrow to the one hop that costs the most. A single well-chosen hop often delivers most of the benefit with little change elsewhere.
11Sizing, Performance, and the CPU Trade-off
OTel Arrow trades processor effort for network savings. A little arithmetic tells you whether the trade is good for you.
The trade in one sentence
Converting data to columns, building dictionaries, and encoding them takes more processor time than simply writing out OTLP, and the receiver must do matching work to rebuild the data. In exchange, fewer bytes cross the network. Whether that is a good deal depends on how expensive your bytes are compared with your processor time.
Vacuum-packing food takes time and a machine, but it lets you fit more into a small freezer and ship it more cheaply. If shipping is expensive and the freezer is tiny, vacuum-packing is a bargain. If you are carrying food next door, it is a waste of effort.
A worked example of the bandwidth saving
Suppose a regional Collector sends 40 megabytes per second of OTLP traffic, after general compression, across a link where data is charged by volume. Over a day, that is about 3.4 terabytes. Imagine that, for this particular data, OTel Arrow reduces the compressed size by about a third. The same telemetry would then cross the link at roughly 27 megabytes per second, or about 2.3 terabytes per day, saving more than one terabyte every day.
Multiply by thirty days and by several regions, and the saving becomes a significant line on the monthly network bill. Now compare it with the cost of the extra processor time: perhaps a few additional processor cores across the senders and receivers. If a terabyte of cross-region traffic costs more than those cores, the trade is favourable. If your link is free and fast, the trade may not be worth the added complexity.
The reduction used here is an assumption to show the arithmetic. Your real figure may be higher or lower. Measure it on a sample of your own traffic before you build a business case.
The knobs that affect the result
| Knob | Effect on network size | Effect on processor and memory |
|---|---|---|
| Larger batches | Smaller per record, more repetition to exploit | More memory while building a batch, slightly more delay |
| More streams | Little direct effect, each stream keeps its own dictionaries | More memory for stream state on both ends |
| Longer stream lifetime | Better, dictionaries stay useful for longer | Memory for state grows, uneven load across receivers |
| Extra general compression | Smaller still | More processor time |
| High-cardinality attributes | Larger, dictionaries grow | More memory for dictionaries |
Memory for stream state
Each open stream keeps dictionaries and schemas in memory on both the sender and the receiver. With a few streams per sender and thousands of senders, the receiver’s memory can become a real consideration. The receiver’s memory limit setting guards against exhaustion, but you should still estimate the total in advance: number of streams multiplied by the typical state per stream, plus the memory needed for batches in flight.
Latency
Encoding adds a small delay to each batch, and larger batches add the time needed to fill them. For telemetry this delay is usually unimportant, since people look at dashboards and traces after the fact, but if you rely on near-instant alerts from the data, measure the end-to-end delay before and after the change.
Before and after enabling Arrow on a hop, record network bytes per second, processor use on sender and receiver, memory use on the receiver, and end-to-end delay. Together they tell you the honest cost and benefit.
12Load Balancing, Stream Lifetime, and Reliability
Long-lived streams are the source of most of the savings, and also of most of the operational surprises.
The long connection problem
Traditional load balancers spread work by sending each new request to a different server. With plain OTLP over gRPC, each batch can be a separate request, so the work is spread evenly. With OTel Arrow, a stream is a single long connection. Once it is attached to a receiver, every batch on it goes to that same receiver for as long as the stream lives. If a few streams carry most of the traffic, one receiver can end up with a heavy load while others sit idle.
flowchart LR
subgraph BAD["Without rotation"]
S1["Sender A"] -->|"stream stays forever"| RA["Receiver 1: overloaded"]
S2["Sender B"] -->|"stream stays forever"| RA
S3["Sender C"] -->|"stream stays forever"| RB["Receiver 2: nearly idle"]
end
Stream lifetime to the rescue
The cure is for senders to close each stream after a chosen lifetime and open a new one. Each new stream is a fresh chance for the load balancer to choose a receiver, so over time the load spreads out. The lifetime is a balancing act: too long and load stays uneven, too short and the senders keep paying the cost of resending schemas and dictionaries, which weakens the compression.
Seconds to a minute
Excellent balance across receivers, but frequent restarts reduce the benefit of dictionaries.
Several minutes
A common compromise between balance and compression, worth testing as a starting point.
Hours
Best compression, but weak balance and slower recovery after receiver changes.
Use a load balancer that understands gRPC
A basic connection-level balancer sees only a single long connection per sender and cannot spread the batches inside it. A balancer that understands gRPC can sometimes balance at the level of streams or requests. Whichever you use, test the distribution of load across receivers under realistic traffic, and watch for a slow drift toward imbalance after rolling updates.
Reliability when a stream breaks
The stream drops
A network blip, a receiver restart, or a load balancer decision closes the stream. The remembered dictionaries on both sides are gone.
Unacknowledged batches are retried
Batches that were sent but not acknowledged are not assumed to be delivered. The sender retries them according to its retry rules.
A fresh stream starts
The sender opens a new stream and sends the full schema and dictionaries again, so the first batches are larger than later ones.
Steady state returns
Dictionaries rebuild, batches shrink again, and the saving returns to its normal level.
Backpressure and queues
The acknowledgement messages carry the receiver’s view of its own load. When the receiver is busy, it can respond with a temporary failure, and the sender slows down and retries. A sending queue in the exporter absorbs short bursts. For longer outages, a persistent queue on the sender holds data on disk until the receiver returns. The behaviour is similar to what you would plan for plain OTLP, with the extra detail that a restarted stream briefly costs more bytes.
When you restart receivers one by one, every stream attached to them is dropped and reopened. A fast, careless rollout can cause a wave of reconnections and a brief rise in network bytes. Roll updates gradually and watch the stream restart metrics.
What about tail sampling?
If your gateway applies tail sampling, spans of one trace must reach the same Collector instance. Arrow streams do not change that rule. Arrange trace-aware routing in the tier that needs it, and remember that long-lived streams can concentrate load on one instance, so keep an eye on balance at that tier in particular.
13Advantages, Disadvantages, and Trade-offs
OTel Arrow is powerful in the right place and wasteful in the wrong one. A balanced view tells you which is which.
Advantages
- Much smaller network traffic for large, repetitive batches
- Lower egress charges on cross-region and cross-cloud hops
- More headroom on limited links at edge sites
- Same data model, so nothing changes for users of the data
- Safe rollout, because it falls back to plain OTLP
- Built on an open standard with wide tool support
Disadvantages / Trade-offs
- More processor time to encode and decode
- Memory used for stream state on both ends
- Long streams make load balancing harder
- Few backends accept it natively, so conversion is needed
- Components and details are still evolving
- More moving parts to monitor and understand
OTLP with compression versus OTel Arrow
| Aspect | OTLP with general compression | OTel Arrow |
|---|---|---|
| Network size | Good | Often better for large repetitive batches |
| Processor cost | Low | Higher |
| Setup effort | Minimal | Moderate, both ends need components |
| Backend support | Universal | Limited, usually converted at a Collector |
| Connection style | Independent requests | Long-lived streams with state |
| Maturity | Very mature | Newer and evolving |
Other ways to reduce telemetry cost
OTel Arrow is one tool among several, and often the best results come from combining them. The table shows how they differ in what they change.
| Technique | What it changes | Information lost? |
|---|---|---|
| Sampling | Keeps only some traces | Yes, by design |
| Filtering and attribute trimming | Removes unwanted data and labels | Yes, what you choose to drop |
| Larger batches and compression | Packs the same data more tightly | No |
| OTel Arrow | Rearranges data into columns for better packing | No |
| Aggregating metrics earlier | Reduces the number of data points | Some detail |
When it is not worth it
If your telemetry volume is small, your network is fast and free, or your biggest costs are in storage and querying rather than transport, the extra complexity of OTel Arrow may not pay off. Likewise, if your data is mostly free-form text or unique identifiers, there is little repetition to exploit. In such cases, plain OTLP with compression and thoughtful sampling is simpler and good enough.
A cargo plane is wonderful for moving heavy loads across the ocean, but nobody hires one to carry a letter across town. Match the tool to the distance and the load.
14Security, Compliance, and Monitoring
A new encoding is a new thing to secure and a new thing to watch.
Security considerations
Unencrypted links
Arrow streams travel over gRPC, so the usual protections apply. Use encrypted connections, and prefer mutual authentication between Collectors.
Memory exhaustion
A buggy or hostile sender could open many streams or build huge dictionaries to use up the receiver’s memory. Configure memory and admission limits.
Malformed data
Decoders must handle unexpected or corrupted batches safely. Keep components up to date so that fixes for decoding problems reach you.
Sensitive content is unchanged
Arrow reshapes data but does not hide it. Personal or secret values are still present, so redact them before the data is encoded.
Compliance
Because the meaning and content of the telemetry are unchanged, your obligations are the same as with OTLP. If your rules require encryption in transit, enforce it on the Arrow hop. If your rules forbid certain data from crossing a border, remember that compression does not change what is being sent, only how many bytes it takes.
Monitoring OTel Arrow
Bytes on the wire
Compare bytes sent per second before and after. This is your primary proof that the saving is real.
Streams opened and restarted
Frequent restarts mean lost dictionaries and weaker compression. Look for patterns that match rolling updates or load balancer behaviour.
Fallbacks to plain OTLP
A steady count means one end does not support Arrow, or the connection setup is failing. You may be paying full price without knowing it.
Processor use
Watch sender and receiver processor use for the encoding and decoding work, and compare with your baseline.
Receiver memory and admissions
Track how close the receiver is to its memory limit and how often it refuses or delays incoming data.
Failures and retries
Track failed and retried batches, queue size, and dropped data, just as you would for any exporter.
A troubleshooting guide
| Symptom | Likely cause | First thing to check |
|---|---|---|
| No drop in network traffic after enabling | One end does not use Arrow, traffic fell back to OTLP | Fallback counts and receiver configuration |
| Small saving only | Small batches, unique attribute values, or short streams | Batch size, attribute cardinality, stream lifetime |
| One receiver much busier than others | Long streams attached to the same instance | Stream lifetime and load balancer behaviour |
| High memory on the receiver | Many streams, large dictionaries | Number of streams and receiver memory limits |
| Processor use rose sharply | Expected cost of encoding, or tiny batches | Batch size and whether the hop is worth it |
| Spikes of bytes after deployments | Streams reopened and dictionaries resent | Rollout pace and restart metrics |
Alert on a rise in fallbacks and on a drop in the compression ratio. Both are early signs that you are no longer getting the benefit you planned for, long before the bill arrives.
15Design Patterns and Anti-patterns
Teams keep rediscovering the same good habits and the same expensive mistakes. Here they are, named.
Patterns worth copying
Arrow only on the expensive hop
Find the link that costs the most, whether in money or in capacity, and apply Arrow there. Keep every other hop on plain OTLP to avoid needless encoding effort.
Measure with real traffic first
Replay a sample of production telemetry through a test pair of Collectors and record the saving, the processor cost, and the memory use before changing production.
Batch generously before the exporter
Use a batch processor sized so that each batch holds enough records for the encoder to find repetition, while keeping delay acceptable.
Keep fallback on during rollout
Allow the exporter to fall back to plain OTLP while you upgrade the fleet, and track fallbacks until they reach zero.
Rotate streams on purpose
Choose a stream lifetime that balances load and compression, and review it after traffic changes or when you add receivers.
Terminate Arrow at a Collector
Convert back to OTLP at the receiving Collector and send ordinary OTLP onward to backends, unless a backend explicitly supports Arrow.
Anti-patterns to avoid
Problem
Arrow is enabled on every hop, including the short link between applications and the Collector on the same machine.
Why It’s Harmful
Batches there are small and the network is free, so there is little to save. The extra encoding and decoding effort uses processor time and adds delay for no benefit.
Correct Approach
Use Arrow only on long, costly, or bandwidth-limited hops with large batches.
Problem
The exporter is upgraded but nobody confirms that the receiving end runs the Arrow receiver.
Why It’s Harmful
Traffic quietly falls back to plain OTLP. The team believes the saving is happening, while the bill and the bandwidth stay exactly the same.
Correct Approach
Track fallbacks and bytes on the wire, and confirm that Arrow streams are active on both ends.
Problem
Streams are set to live only a few seconds, or batches are tiny, in pursuit of perfect load balance.
Why It’s Harmful
Schemas and dictionaries are resent constantly, so most of the compression benefit disappears and the processor cost remains.
Correct Approach
Find a lifetime and batch size that balance load without destroying the savings, and test with real traffic.
Problem
The receiver runs with no memory or admission limits, exposed to many senders.
Why It’s Harmful
Stream state consumes memory. A burst of new streams or a misbehaving sender can exhaust memory and crash the receiver, taking telemetry for everyone with it.
Correct Approach
Set memory and admission limits, pair them with the memory limiter, and test the behaviour under overload.
Problem
A plain connection-level load balancer fronts the receivers, and nobody checks how load is spread.
Why It’s Harmful
Long streams stick to whichever receiver they first reached, leaving some overloaded and others idle, and making rolling updates unpredictable.
Correct Approach
Use stream rotation and a gRPC-aware balancer, and monitor the load on each receiver.
Problem
A business case is built on benchmark numbers from an article or a synthetic dataset, without testing on real telemetry.
Why It’s Harmful
Synthetic data is usually more repetitive than real data. Real savings may be much smaller, and the project may fail to deliver what was promised.
Correct Approach
Replay a sample of your own traffic and calculate the saving from measurements before committing.
16Best Practices and Common Mistakes
The habits that separate a smooth OTel Arrow rollout from a frustrating one, gathered in one place.
Start with the bill, not the technology
The strongest reason to adopt OTel Arrow is a measurable cost: a cross-region transfer charge, a metered egress link, or a constrained edge connection. Write down the number before you begin. Without it, you cannot tell whether the project succeeded, and you cannot defend the extra complexity when someone asks why the change was made.
Nobody buys a freight container to ship a parcel. You first look at what the shipping costs, and only then decide whether a bigger, cleverer way of packing is worth the effort. The cost tells you whether to bother.
Best practices at a glance
Target expensive hops
Apply Arrow where bytes cost real money or time: edge to gateway, region to region, and the final leg to a vendor that supports it. Leave cheap local hops on plain OTLP.
Keep the fallback
Let senders drop back to plain OTLP when a receiver cannot speak Arrow. It protects you during upgrades and mixed environments.
Measure on your own data
Replay a sample of real telemetry, compare bytes and processor time with and without Arrow, and decide using your own figures.
Limit memory and admission
Stream state uses memory. Put sensible limits on receivers and pair them with the memory limiter so a burst cannot take down the gateway.
Rotate streams
Close and reopen streams on a schedule so load spreads across receivers and rolling updates behave predictably.
Watch both ends
Dashboard bytes on the wire, processor use, memory, stream churn, retries, and fallback events on senders and receivers together.
Pin and test versions
Move senders and receivers together, test the pair in staging, and read release notes, because this area is still evolving.
Redact before you encode
Remove or hash sensitive attributes in processors ahead of the exporter. Columnar storage reshapes data but does not hide it.
Common mistakes and their cures
| Mistake | What happens | Better approach |
|---|---|---|
| Enabling Arrow everywhere on day one | Extra processor cost on hops that never needed savings, and many places to debug at once | Start with the single most expensive hop and widen only with evidence |
| Tiny batches | Little repetition to exploit, so savings shrink while overhead remains | Allow larger, well-formed batches within your delay budget |
| Ignoring receiver memory | Streams accumulate state until the process is under pressure | Set limits and watch memory as a first-class signal |
| Never rotating streams | Uneven load and awkward restarts | Choose a lifetime that balances compression and spread |
| Treating Arrow as a security feature | Sensitive values travel exactly as before | Keep redaction and encryption in place |
| Trusting published ratios | Business case built on someone else’s data | Replay your own traffic and calculate from measurements |
| Upgrading only one side | Silent fallback to plain OTLP and no savings | Track fallback counters and upgrade pairs together |
A short vocabulary cheat sheet
People new to the topic often get lost in words. Here is a compact list you can keep beside you while reading documentation or talking to colleagues.
| Word | Plain meaning |
|---|---|
| OTLP | The standard way OpenTelemetry components exchange telemetry, one record after another in nested groups |
| OTAP | The Arrow-based companion protocol, which carries the same telemetry in columns |
| Columnar | Storing all the values of one field together instead of storing whole records together |
| Dictionary encoding | Replacing a repeated value with a small number that points into a list |
| Run-length encoding | Writing a repeated value once together with a count |
| Delta encoding | Storing the difference from the previous value instead of the value itself |
| Stream | A long-lived two-way connection that remembers what has already been sent |
| Batch | A group of records sent together and acknowledged together |
| Fallback | Switching to plain OTLP when the other side cannot use Arrow |
The OTel Arrow components and the protocol around them have been changing. Stability levels, available settings, and supported signals can differ between releases. Before planning a rollout, read the current component documentation and release notes for the exact versions you intend to run.
17Real-World Situations
Four typical situations, described in general terms, showing where OTel Arrow helps, where it does not, and what to ask before you adopt it.
These are illustrative composites, not reports from named organisations. Figures are rounded and assumed so that the reasoning is easy to follow.
A retail company with stores across many regions
Context: Each region runs a Collector that gathers telemetry from local services and sends it to a central gateway in another region. Cross-region transfer is billed by volume, and the bill has become one of the larger observability costs.
Decision: Enable Arrow on the regional-Collector to central-gateway hop only. Keep service-to-regional-Collector traffic on plain OTLP.
Outcome: The team replays a day of real traffic, finds a meaningful drop in compressed bytes on that hop, and sees a modest rise in processor use on both ends. The saving exceeds the cost of the extra cores, so the change stays. Fallback counters remain near zero after both sides are upgraded.
A manufacturer with factory sites on constrained links
Context: Each factory has a small Collector sending to headquarters over a narrow, sometimes unreliable link. Telemetry arrives late whenever the link is busy.
Decision: Use Arrow on the factory link, together with a persistent queue on the factory Collector, so short outages do not lose data.
Outcome: Less data crosses the link, so the queue drains faster after outages. The team notes that a dropped link resets the stream state, and accepts a brief dip in compression after every reconnection.
A small startup with one cluster and a hosted backend
Context: All services and a single Collector run in one cluster. Traffic leaves the cluster to a vendor over a modest connection, and the monthly bill is small.
Decision: Stay on plain OTLP with general compression.
Outcome: The saving from Arrow would be small in money terms, while the added complexity would be real. The team sets a reminder to reconsider if volume grows tenfold. This is a perfectly good decision, and it shows that not adopting is sometimes the right answer.
A platform team running a shared gateway for many business units
Context: Dozens of teams send telemetry to a shared gateway fleet. Load is uneven, and rolling updates occasionally cause sudden surges.
Decision: Enable Arrow between the large regional gateways and the central tier, with stream rotation, memory limits, and a gRPC-aware load balancer.
Outcome: After tuning stream lifetime, load spreads evenly and rolling updates stop causing spikes. The team publishes a short internal guide so that other business units can enable Arrow safely on their own hops.
Questions to ask before you adopt
How much does this hop cost?
If you cannot name the cost in money or delay, you cannot judge the benefit.
Is the data repetitive enough?
Telemetry with many repeated names, labels, and resource details compresses far better than telemetry full of unique values.
Can both ends speak Arrow?
The saving exists only when the sender and receiver both support it and neither falls back silently.
Can we spare the processor time?
Check headroom on the sender and receiver. If processors are already near their limits, the trade may hurt.
Who owns the operation?
Name a team responsible for watching the dashboards, tuning stream settings, and handling upgrades.
18A Practical Adoption Roadmap
A calm, step-by-step path from “this sounds interesting” to “this is running quietly in production”.
Switching a delivery route to a new kind of truck is done one route at a time. You try it on the busiest route, watch the fuel use and delivery times, keep the old trucks ready, and only then move the other routes across.
Measure the baseline
Record bytes per second, processor use, memory, and the monetary cost on the hop you plan to change. This is the line you will compare against.
Replay a sample in a test setup
Run a copy of real traffic through a sender and receiver pair with Arrow enabled. Measure the same numbers and calculate the saving and the cost.
Prepare the receivers first
Upgrade and configure the receiving side with memory limits, admission control, and a gRPC-aware load balancer, while senders still use plain OTLP.
Enable one sender, then a few
Turn Arrow on for a single sender, watch the dashboards, then widen to a small group. Check fallback events, stream churn, and retries at each step.
Tune stream settings
Adjust stream count, lifetime, and batch size using what the dashboards show, aiming for even load and steady savings.
Document and hand over
Write down the settings, the reasons behind them, the dashboards, and the roll-back steps, and name the owners.
Maturity levels
| Level | Description | Typical signs |
|---|---|---|
| Exploring | Reading, discussing, and testing in a lab | No production traffic, a sample replay planned |
| Piloting | One expensive hop uses Arrow with fallback on | Dashboards exist, savings measured |
| Operating | Several hops use Arrow with limits and rotation | Alerts on fallback and memory, documented runbook |
| Optimising | Settings tuned from data, versions upgraded on a schedule | Regular reviews of savings against cost |
Because senders can fall back to plain OTLP, rolling back is usually a configuration change. Practise it once in a test environment so that the first time you need it is not during an incident.
19Frequently Asked Questions
Short, direct answers to the questions people ask most often.
It is a way of sending OpenTelemetry data in columns, using the Apache Arrow format over long-lived streams, so that repeated values are stored and sent only once and the data compresses much better than plain record-by-record OTLP.
No. It is a companion. Applications and SDKs continue to speak OTLP, and Collectors can translate to Arrow for a hop and back to OTLP at the other end.
Instead of storing each record as a bundle of fields, the data is stored one field at a time. All timestamps sit together, all names sit together, and so on. Similar values placed side by side are easy to shrink.
An open, language-neutral format for tabular data held in columns. It is designed so that different programs can share the same data cheaply, and OTel Arrow uses it as its container.
General compression looks for repetition in a stream of bytes. Columnar layout puts similar values next to each other and uses dictionaries and runs that remember repetition across batches, so there is far more repetition for any compressor to exploit.
It depends on your data. Highly repetitive telemetry with many shared labels can shrink a lot, while data full of unique values shrinks less. Measure with a replay of your own traffic rather than trusting any quoted figure.
More processor time to convert and encode, more memory to hold stream state, and more operational care around load balancing and upgrades. You pay in effort and compute to save on network bytes.
Usually not. The best fit is between Collectors on expensive hops. The link between an application and a local agent is cheap, so the savings would not justify the added work.
The Collector components have covered traces, metrics, and logs. Check the current documentation for the exact support and stability level in the version you use.
In the contrib collection of components. If you use a custom distribution, include the Arrow receiver and exporter in your manifest.
With fallback enabled, the sender notices and sends plain OTLP instead. Nothing is lost, but you also do not get the saving, so watch for fallback events.
Both sides lose their remembered schema and dictionaries. Batches that were not acknowledged are retried, a new stream is opened, and compression recovers as dictionaries are rebuilt.
Because a stream is long-lived, it stays with whichever receiver it first reached. Without rotation or a gRPC-aware balancer, some receivers end up busy while others sit idle.
No. It changes the shape of the data, not who can read it. Keep encryption, authentication, and redaction exactly as you would with OTLP.
Compare bytes sent before and after, check that fallback counters are low, and confirm that stream churn and retries are calm. If the bytes do not fall, one side is probably not using Arrow.
Not if you convert back to OTLP at the end of the Arrow section. Many teams use Arrow only between their own Collectors and send OTLP onward to the backend.
That depends on the component’s stability level in the release you run, and the answer has changed over time. Read the current documentation, test with your own traffic, and start with one hop.
It can add a small delay while a batch fills and is encoded. Keep batches large enough to compress well but small enough to meet your freshness needs, and measure end-to-end delay.
Yes, and it is a good pairing on unreliable links. The queue protects data during outages, and Arrow helps the queue drain faster when the link returns.
A better algorithm still works on the same record-by-record layout. OTel Arrow changes the layout itself, which exposes patterns that no byte-level compressor can see, and keeps dictionaries across batches.
Pick your most expensive hop, replay a sample of its traffic through a test pair with Arrow on, and compare bytes and processor use against plain OTLP.
When the hop is cheap, volumes are small, processors are already stretched, or nobody can own the operation. In those cases plain OTLP with general compression is simpler and good enough.
20Summary and Key Takeaways
Everything in this guide, gathered into a few ideas you can carry with you.
Telemetry is repetitive. The same service names, metric names, labels, and resource details appear again and again, and plain OTLP writes them out record after record. OTel Arrow takes the same data, arranges it into columns, replaces repeated values with small references, and sends it over long-lived streams that remember what has already been shared. The result is a much smaller flow of bytes on the hops where bytes are expensive, paid for with some extra processor time and memory.
It is a companion to OTLP and not a replacement. You use it where it pays, usually between Collectors across regions or from the edge to a gateway, and you leave the rest of your pipeline alone. With limits, rotation, fallback, and good dashboards, it can run quietly. Without them, it can surprise you. The wise path is to measure first, start small, and grow from evidence.
Key Takeaways
- OTel Arrow is a companion to OTLP — the same telemetry, carried in columns using Apache Arrow, with conversion at the edges of the Arrow section.
- Columns expose repetition — dictionaries, runs, and deltas turn repeated names and labels into tiny references, which is why it compresses so well.
- Streams remember — schemas and dictionaries are sent once and reused, with acknowledgements providing backpressure, but a broken stream resets that memory.
- Use it on expensive hops — cross-region links, metered egress, and constrained edges benefit most, while cheap local hops rarely justify it.
- You trade compute for bytes — expect more processor time and memory, so measure both sides with your own traffic before deciding.
- Operate it with care — rotate streams, use a gRPC-aware balancer, set memory and admission limits, watch fallback counters, and upgrade senders and receivers together.
- It is not a security feature — keep encryption, authentication, and redaction in place, and verify the current component status before you commit.