diff --git a/.gitignore b/.gitignore index 88ba84eef..8d32144a6 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,8 @@ # Text formatting and spelling tools. .tools + + +# Added by cargo + +/target diff --git a/text/0156-columnar-encoding.md b/text/0156-columnar-encoding.md new file mode 100644 index 000000000..e9950be7f --- /dev/null +++ b/text/0156-columnar-encoding.md @@ -0,0 +1,1018 @@ +# OTel Arrow Protocol Specification + +**Author**: Laurent Querel, F5 Inc. + +**Keywords**: OTLP, Arrow Columnar Format, Bandwidth Reduction, Multivariate Time-series, Logs, Traces. + +**Abstract**: This OTEP describes a new protocol, the OTelArrow protocol, which is based on a **generic columnar representation +for metrics, logs and traces**. This protocol significantly improves efficiency in scenarios involving the transmission +of large batches of metrics, logs, traces. Moreover, it provides a better representation for [multivariate time-series](#multivariate-time-series). +The OTelArrow protocol also supports a fallback mechanism to the [OpenTelemetry protocol (OTEP 0035)](https://github.com/open-telemetry/oteps/blob/main/text/0035-opentelemetry-protocol.md) +in instances when one of the endpoints does not support the OTelArrow protocol. + +**Reference implementation**: The [OTel Arrow Adapter](https://github.com/f5/otel-arrow-adapter) Go library specifies +the protobuf spec, and implements the OTel Arrow Encoder/Decoder (main contributor [Laurent Querel](https://github.com/lquerel)). +An [experimental OTel Collector](https://github.com/open-telemetry/experimental-arrow-collector) has been implemented to +expose the new gRPC endpoint and to provide OTel Arrow support via the previous library (main contributor [Joshua MacDonald](https://github.com/jmacd)). + +## Table of contents + +* [Introduction](#introduction) + * [Motivation](#motivation) + * [Validation](#validation) + * [Why Apache Arrow and How to Use It?](#why-apache-arrow-and-how-to-use-it) + * [Integration Strategy and Phasing](#integration-strategy-and-phasing) +* [Protocol Details](#protocol-details) + * [ArrowStreamService](#arrowstreamservice) + * [Mapping OTel Entities to Arrow Records](#mapping-otel-entities-to-arrow-records) + * [Logs Arrow Mapping](#logs-arrow-mapping) + * [Spans Arrow Mapping](#spans-arrow-mapping) + * [Metrics Arrow Mapping](#metrics-arrow-mapping) +* [Implementation Recommendations](#implementation-recommendations) + * [Protocol Extension and Fallback Mechanism](#protocol-extension-and-fallback-mechanism) + * [Batch ID Generation](#batch-id-generation) + * [Schema ID Generation](#schema-id-generation) + * [Traffic Balancing Optimization](#traffic-balancing-optimization) + * [Throttling](#throttling) + * [Delivery Guarantee](#delivery-guarantee) +* [Risks and Mitigation](#risks-and-mitigations) +* [Trade-offs and Mitigations](#trade-offs-and-mitigations) + * [Duplicate Data](#duplicate-data) + * [Incompatible Backends](#incompatible-backends) + * [Small Devices/Small Telemetry Data Stream](#small-devicessmall-telemetry-data-stream) +* [Future Versions and Interoperability](#future-versions-and-interoperability) +* [Prior Art and Alternatives](#prior-art-and-alternatives) +* [Open Questions](#open-questions) +* [Future Possibilities](#future-possibilities) +* [Appendix A - Protocol Buffer Definitions](#appendix-a---protocol-buffer-definitions) +* [Glossary](#glossary) +* [Acknowledgements](#acknowledgements) + +## Introduction + +### Motivation + +As telemetry data becomes more widely available and volumes increase, new uses and needs are emerging for the OTLP +ecosystem: cost-effectiveness, advanced data processing, data minimization. This OTEP aims to improve the OTLP +protocol to better address them while maintaining compatibility with the existing ecosystem. + +Currently, the OTLP protocol uses a "row-oriented" format to represent all the OTel entities. This representation works +well for small batches (<50 entries) but, as the analytical database industry has shown, a "column-oriented" +representation is more optimal for the transfer and processing of *large batches* of entities. The term "row-oriented" +is used when data is organized into a series of records, keeping all data associated with a record next to each other in +memory. A "column-oriented" system organizes data by fields, grouping all the data associated with a field next to each +other in memory. The main benefits of a columnar approach are: + +* **better data compression rate** (arrays of similar data generally compress better), +* **faster data processing** (see diagram below), +* **faster serialization and deserialization** (few arrays vs many in-memory objects to serialize/deserialize), +* **better IO efficiency** (less data to transmit). + +![row vs column-oriented](img/0156_OTEL%20-%20Row%20vs%20Column.png) + +This OTEP proposes to improve the [OpenTelemetry protocol (OTEP 0035)](https://github.com/open-telemetry/oteps/blob/main/text/0035-opentelemetry-protocol.md) +with a **generic columnar representation for metrics, logs and traces based on Apache Arrow**. Compared to the existing +OpenTelemetry protocol this compatible extension has the following improvements: + +* **Reduce the bandwidth requirements** of the protocol. The two main levers are: 1) a better representation of the + telemetry data based on a columnar representation, 2) a stream-oriented gRPC endpoint that is more efficient to + transmit batches of OTLP entities. +* **Provide a more optimal representation for multivariate time-series data**. + Multivariate time-series are currently not well compressed in the existing protocol (multivariate = related metrics + sharing the same attributes and timestamp). The OTel Arrow protocol provides a much better compression rate for this + type of data by leveraging the columnar representation. +* **Provide more advanced and efficient telemetry data processing capabilities**. Increasing data volume, cost + efficiency, and data minimization require additional data processing capabilities such as data projection, + aggregation, and filtering. + +These improvements not only address the aforementioned needs but also answer the [open questions](https://github.com/open-telemetry/oteps/blob/main/text/0035-opentelemetry-protocol.md#open-questions) +cited in OTEP 035 (i.e. cpu usage, memory pressure, compression optimization). + +**It is important to understand that this proposal is complementary to the existing protocol. The row-oriented version +is still suitable for some scenarios. Telemetry sources that generate a small amount of telemetry data should continue +to use it. On the other side of the spectrum, sources and collectors generating or aggregating a large amount of +telemetry data will benefit from adopting this extension to optimize the resources involved in the transfer and +processing of this data. This adoption can be done incrementally.** + +Before detailing the specifications of the OTel Arrow protocol, the following two sections present: 1) a validation of +the value of a columnar approach based on a set of benchmarks, 2) a discussion of the value of using Apache Arrow as a +basis for columnar support in OTLP. + +### Validation + +A series of tests were conducted to compare compression ratios between OTLP and a columnar version of OTLP called OTel +Arrow. The key results are: + +* For univariate time series, OTel Arrow is **2 to 2.5 better in terms of bandwidth reduction while having an + end-to-end speed (including conversion to/from OTLP) 1.5 to 2 times slower in phase 1**. In **phase 2** the conversion + OTLP to/from Arrow is gone and the end-to-end speed is **3.1 to 11.2 times faster by our estimates**. +* For multivariate time series, OTel Arrow is **3 to 7 times better in terms of bandwidth reduction while having an + end-to-end speed (including conversion to/from OTLP) similar to the univariate time series scenario phase 1**. Phase 2 + has been yet estimated but similar results are expected. +* For logs, OTel Arrow is **1.6 to 2 times better in terms of bandwidth reduction while having an end-to-end speed + (including conversion to/from OTLP) 2.0 to 3.5 times slower in phase 1**. In **phase 2** the conversion + OTLP to/from Arrow is gone and the end-to-end speed is **2.3 to 4.86 times faster** by our estimates. +* For traces, OTel Arrow is **1.7 to 2.8 times better in terms of bandwidth reduction while having an end-to-end speed + (including conversion to/from OTLP) 1.5 to 2.1 times slower in phase 1**. In **phase 2** the conversion + OTLP to/from Arrow is gone and the end-to-end speed is **3.37 to 6.16 times faster** by our estimates. + +The following 3 columns charts show the results of the benchmarks for the univariate metrics, logs and traces. For both +protocols, the baseline is the size of the uncompressed OTLP messages. The reduction factor is the ratio between this +baseline and the compressed message size for each protocol. The compression algorithm used is ZSTD for OTLP and OTel +Arrow. + +![Summary (standard metrics)](img/0156_compression_ratio_summary_std_metrics.png) + +In the following 3-columns charts, the only difference with the previous ones is that the metrics are multivariate. The +benchmarks show that the compression ratio is much better for OTel Arrow than for OTLP. This is due to the fact that +OTel Arrow is able to leverage the columnar representation to compress the data more efficiently in a multivariate +scenario. + +![Summary (multivariate metrics)](img/0156_compression_ratio_summary_multivariate_metrics.png) + +The following stacked bar graphs compare side-by-side the distribution of time spent for each step and for each +version of the protocol. + +![Summary of the time spent](img/0156_summary_time_spent.png) +[Zoom on the chart](https://raw.githubusercontent.com/lquerel/oteps/main/text/img/0156_summary_time_spent.png) + +> In conclusion, these benchmarks demonstrate the interest of integrating a column-oriented telemetry data protocol to +> optimize bandwidth and processing speed in a batch processing context. + +### Why Apache Arrow and How to Use It? + +[Apache Arrow](https://arrow.apache.org/) is a versatile columnar format for flat and hierarchical data, well +established in the industry. Arrow is optimized for: + +* column-oriented data exchange based on an in-memory format common among implementations, regardless of the language. +The use of a serialization and deserialization mechanism is thus eliminated, allowing zero-copy. +* in-memory analytic operations using modern hardware optimizations (e.g. SIMD) +* integration with a large ecosystem (e.g. data pipelines, databases, stream processing, etc.) +* language-independent + +All these properties make Arrow a great choice for a general-purpose telemetry protocol. Efficient implementations of +Apache Arrow exist for most of the languages (Java, Go, C++, Rust, ...). Connectors with Apache Arrow buffer exist for +well-known file format (e.g. Parquet) and for well-known backend (e.g. BigQuery). +By reusing this existing infrastructure (see [Arrow ecosystem](https://arrow.apache.org/powered_by/)), we are accelerating the development and +integration of the OpenTelemetry protocol while expanding its scope of application. + +Adapting the OTLP data format to the Arrow world (see below) is only part of the problem this proposal aims to describe. +Many other design choices and trade-offs have been made, such as: + +- the organization of the data (i.e. schema and sorting) and the selection of the compression algorithm to optimize the compression ratio. +- the way to serialize the Arrow data, the metadata, the dictionaries, and the selection of the transfer mode (reply/reply vs. bi-dir stream). +- optimization of many parameters introduced in the system. + +![In-memory Apache Arrow RecordBatch](img/0156_OTEL%20-%20HowToUseArrow.png) + +### Integration Strategy and Phasing + +This OTEP enhances the existing OTel eco-system with an additional representation of telemetry data in columnar form to +better support certain scenarios (e.g. cost-effectiveness to transmit large batch, multivariate time-series, advanced +data processing, data minimization). All existing components will continue to be compatible and operational. + +A two-phase integration is proposed to allow incremental benefits. + +#### Phase 1 + +This proposal is designed as a new protocol compatible with the OTLP protocol. As illustrated in the +following diagram, a new OTel Arrow receiver will be responsible for translating this new protocol to the +OTLP protocol. Similarly, a new exporter will be responsible for translating the OTLP messages into this new Arrow-based +format. + +![OTel Collector](img/0156_collector_internal_overview.png) + +This first step is intended to address the specific use cases of **traffic reduction** and native support of +**multivariate time-series**. Based on community feedback, many companies want to reduce the cost of transferring +telemetry data over the Internet. By adding a collector that acts as a point of integration and traffic conversion at +the edge of a client environment, we can take advantage of the columnar format to eliminate redundant data and optimize +the compression ratio. This is illustrated in the following diagram. + +![Traffic reduction](img/0156_traffic_reduction_use_case.png) + +> Note 1: A fallback mechanism can be used to handle the case where the new protocol is not supported by the target. +> More on this mechanism in this [section](#protocol-extension-and-fallback-mechanism). + +#### Phase 2 + +Phase 2 aims to extend the support of Apache Arrow end-to-end and more specifically inside the collector to better +support the following scenarios: cost efficiency, advanced data processing, data minimization. New receivers, processors, +and exporters supporting Apache Arrow natively will be developed. A bidirectional adaptation layer OTLP / OTel Arrow +will be developed within the collector to continue supporting the existing ecosystem. The following diagram is an +overview of a collector supporting both OTLP and an end-to-end OTel Arrow pipeline. + +![OTel Arrow Collector](img/0156_collector_phase_2.png) + +Implementing an end-to-end column-oriented pipeline will provide many benefits such as: + +- **Accelerate stream processing**, +- **Reduce CPU and Memory usage**, +- **Improve compression ratio end-to-end**, +- **Access to the Apache Arrow ecosystem** (query engine, parquet support, ...). + +## Protocol Details + +The protocol specifications are composed of two parts. The first section describes the new gRPC services supporting +column-oriented telemetry data. The second section presents the mapping between the OTLP entities and their Apache +Arrow counterpart. + +### ArrowStreamService + +OTel Arrow defines the columnar encoding of telemetry data and the gRPC-based protocol used to exchange data between +the client and the server. OTel Arrow is a bi-directional stream oriented protocol leveraging Apache Arrow for the +encoding of telemetry data. + +OTLP and OTel Arrow protocols can be used together and can use the same TCP port. To do so, in addition to the 3 +existing +services (`MetricsService`, `LogsService` and `TraceService`), we introduce the service `ArrowStreamService` +(see [this protobuf specification](#appendix-a---protocol-buffer-definitions) for more details) exposing a single API +endpoint named `ArrowStream`. This endpoint is based on a bidirectional streaming protocol. The client message is a +`BatchArrowRecords` stream encoding a batch of Apache Arrow buffers (more specifically [Arrow IPC format](#arrow-ipc-format)). +The server message side is a `BatchStatus` stream reporting asynchronously the status of each `BatchArrowRecords` +previously sent. In addition to this endpoint, the OTel Arrow protocol offers three additional services to facilitate +intricate load-balancing routing rules, tailored to the specific nature of the OTLP entities - namely Metrics, Logs, +and Traces. + +After establishing the underlying transport, the client starts sending telemetry data using the `ArrowStream` service. +The client continuously sends `BatchArrowRecords`'s messages over the opened stream to the server and expects to receive +continuously `BatchStatus`'s messages from the server as illustrated by the following sequence diagram: + +![Sequence diagram](img/0156_OTEL%20-%20ProtocolSeqDiagram.png) + +> Multiple streams can be simultaneously opened between a client and a server to increase the maximum achievable +throughput. + +If the client is shutting down (e.g. when the containing process wants to exit) the client will wait until +all pending acknowledgements are received or until an implementation specific timeout expires. This ensures reliable +delivery of telemetry data. + +The protobuf definition of this service is: + +```protobuf +// Service that can be used to send `BatchArrowRecords` between one Application instrumented with OpenTelemetry and a +// collector, or between collectors. +service ArrowStreamService { + // The ArrowStream endpoint is a bi-directional stream used to send batch of `BatchArrowRecords` from the exporter + // to the collector. The collector returns `BatchStatus` messages to acknowledge the `BatchArrowRecords` + // messages received. + rpc ArrowStream(stream BatchArrowRecords) returns (stream BatchStatus) {} +} + +// ArrowTracesService is a traces-only Arrow stream. +service ArrowTracesService { + rpc ArrowTraces(stream BatchArrowRecords) returns (stream BatchStatus) {} +} + +// ArrowTracesService is a logs-only Arrow stream. +service ArrowLogsService { + rpc ArrowLogs(stream BatchArrowRecords) returns (stream BatchStatus) {} +} + +// ArrowTracesService is a metrics-only Arrow stream. +service ArrowMetricsService { + rpc ArrowMetrics(stream BatchArrowRecords) returns (stream BatchStatus) {} +} +``` + +> **Unary RPC vs Stream RPC**: We use a stream-oriented protocol **to get rid of the overhead of specifying the schema +> and dictionaries for each batch.** A state will be maintained receiver side to keep track of the schemas and +> dictionaries. The [Arrow IPC format](#arrow-ipc-format) has been designed to follow this pattern and also allows the +> dictionaries to be sent incrementally. Similarly, ZSTD dictionaries can also be transferred to the RPC stream to +> optimize the transfer of small batches. To mitigate the usual pitfalls of a stream-oriented protocol (e.g. unbalanced +> connections with load balancer deployment) please see this [paragraph](#traffic-balancing-optimization) in the +> implementation recommendations section. + +A `BatchArrowRecords` message is composed of 3 attributes. The protobuf definition is: + +```protobuf +// Enumeration of all the OTelArrow payload types currently supported by the OTel Arrow protocol. +// A message sent by an exporter to a collector containing a batch of Arrow +// records. +message BatchArrowRecords { + // [mandatory] Batch ID. Must be unique in the context of the stream. + int_64 batch_id = 1; + + // [mandatory] A collection of payloads containing the data of the batch. + repeated ArrowPayload arrow_payloads = 2; + + // [optional] Headers associated with this batch, encoded using hpack. + bytes headers = 3; +} +``` + +The `batch_id` attribute is a unique identifier for the batch inside the scope of the current stream. It is used to +uniquely identify the batch in the server message `BatchStatus` stream. See the [Batch Id generation](#batch-id-generation) +section for more information on the implementation of this identifier. + +The `arrow_payloads` attribute is a list of `ArrowPayload` messages. Each `ArrowPayload` message represents +a table of data encoded in a columnar format (e.g. metrics, logs, traces, attributes, events, links, exemplars, ...). +Several correlated IPC Arrow messages of different nature and with different schemas can be sent in the same OTelArrow batch +identified by `batch_id` and thus be processed as one unit without complex logic in the collector or any other processing systems. +More details on the `ArrowPayload` columns in the section [Mapping OTel entities to Arrow records](#mapping-otel-entities-to-arrow-records). + +The `headers` attribute is optional and used to send additional HTTP headers associated with the batch and encoded with +hpack. + +More specifically, an `ArrowPayload` protobuf message is defined as: + +```protobuf +// Enumeration of all the OTel Arrow payload types currently supported by the +// OTel Arrow protocol. +enum ArrowPayloadType { + UNKNOWN = 0; + + // A payload representing a collection of resource attributes. + RESOURCE_ATTRS = 1; + // A payload representing a collection of scope attributes. + SCOPE_ATTRS = 2; + + // A set of payloads representing a collection of metrics. + METRICS = 10; // Main metric payload + NUMBER_DATA_POINTS = 11; + SUMMARY_DATA_POINTS = 12; + HISTOGRAM_DATA_POINTS = 13; + EXP_HISTOGRAM_DATA_POINTS = 14; + NUMBER_DP_ATTRS = 15; + SUMMARY_DP_ATTRS = 16; + HISTOGRAM_DP_ATTRS = 17; + EXP_HISTOGRAM_DP_ATTRS = 18; + NUMBER_DP_EXEMPLARS = 19; + HISTOGRAM_DP_EXEMPLARS = 20; + EXP_HISTOGRAM_DP_EXEMPLARS = 21; + NUMBER_DP_EXEMPLAR_ATTRS = 22; + HISTOGRAM_DP_EXEMPLAR_ATTRS = 23; + EXP_HISTOGRAM_DP_EXEMPLAR_ATTRS = 24; + + // A set of payloads representing a collection of logs. + LOGS = 30; + LOG_ATTRS = 31; + + // A set of payloads representing a collection of traces. + SPANS = 40; + SPAN_ATTRS = 41; + SPAN_EVENTS = 42; + SPAN_LINKS = 43; + SPAN_EVENT_ATTRS = 44; + SPAN_LINK_ATTRS = 45; +} + +// Represents a batch of OTel Arrow entities. +message ArrowPayload { + // [mandatory] A canonical ID representing the schema of the Arrow Record. + // This ID is used on the consumer side to determine the IPC reader to use + // for interpreting the corresponding record. For any NEW `schema_id`, the + // consumer must: + // 1) close the current IPC reader, + // 2) create a new IPC reader in order to interpret the new schema, + // dictionaries, and corresponding data. + string schema_id = 1; + + // [mandatory] Type of the OTel Arrow payload. + ArrowPayloadType type = 2; + + // [mandatory] Serialized Arrow Record Batch + // For a description of the Arrow IPC format see: + // https://arrow.apache.org/docs/format/Columnar.html#serialization-and-interprocess-communication-ipc + bytes record = 3; +} + +``` + +The `schema_id` attribute is a unique identifier representing the schema of the Arrow Record present in the +`ArrowPayload`. This id will be used receiver side to keep track of the schema and dictionaries for a +specific type of Arrow Records. See the [Schema Id generation](#schema-id-generation) section for more information +on the implementation of this identifier. + +The `ArrowPayloadType` enum specifies the `type` of the payload. + +The `record` attribute is a binary representation of the Arrow RecordBatch. + +By storing Arrow buffers in a protobuf field of type 'bytes' we can leverage the zero-copy capability of some +protobuf implementations (e.g. C++, Java, Rust) in order to get the most out of Arrow (relying on zero-copy ser/deser +framework). + +> Note: By default, ZSTD compression is enabled at the Arrow IPC level in order to benefit from the best compression +> ratio regardless of the collector configuration. However, this compression can be disabled to enable it at the global +> gRPC level if it makes more sense for a particular configuration. + +On the server message stream, a `BatchStatus` message is a collection of `StatusMessage`. A `StatusMessage` is composed of 5 +attributes. The protobuf definition is: + +```protobuf +// A message sent by a Collector to the exporter that opened the data stream. +message BatchStatus { + repeated StatusMessage statuses = 1; +} + +message StatusMessage { + int64 batch_id = 1; + StatusCode status_code = 2; + ErrorCode error_code = 3; + string error_message = 4; + RetryInfo retry_info = 5; +} + +enum StatusCode { + OK = 0; + ERROR = 1; +} + +enum ErrorCode { + UNAVAILABLE = 0; + INVALID_ARGUMENT = 1; +} + +message RetryInfo { + int64 retry_delay = 1; +} +``` + +The `BatchStatus` message definition is relatively simple and essentially self-explanatory. + +The server may respond with either a success ('OK') or an error ('ERROR') status. Receiving an `OK` means that the +message received by the collector has been processed by the collector. If the server receives an empty `BatchEvent` +the server should respond with success. + +When an error is returned by the server it falls into 2 broad categories: retryable and not-retryable: + +* Retryable errors indicate that processing of telemetry data failed and the client should record the error and may + retry exporting the same data. This can happen when the server is temporarily unable to process the data. +* Not-retryable errors indicate that processing of telemetry data failed and the client must not retry sending the same + telemetry data. The telemetry data must be dropped. This can happen, for example, when the request contains bad data + and + cannot be deserialized or otherwise processed by the server. The client should maintain a counter of such dropped + data. + +The server should indicate retryable errors using code UNAVAILABLE and may supply additional details via `error_message` +and `retry_info`. + +To indicate not-retryable errors the server is recommended to use code INVALID_ARGUMENT and may supply additional +details +via `error_message`. + +> Note: [Appendix A](#appendix-a---protocol-buffer-definitions) contains the full protobuf definition. + +### Mapping OTel Entities to Arrow Records + +OTel entities are batched into multiple Apache Arrow `RecordBatch`. An Apache Arrow RecordBatch is a combination of two things: +a schema and a collection of Arrow Arrays. Individual Arrow Arrays or their nested children may be dictionary encoded, +in which case the Array that is dictionary encoded contains a reference to its dictionary. The Arrow IPC +implementations, in general, will recognize when one dictionary is referenced by multiple Arrays and only send it +across the wire once, allowing the receiving end to maintain the memory usage benefits of reusing a dictionary. In this +proposal dictionary encoded arrays are used to encode string (or binary) columns that have low cardinality. The +stream-oriented API is leveraged to amortize the schema and dictionary overheads across multiple batches. + +An Apache Arrow schema can define columns of different [types](https://arrow.apache.org/docs/python/api/datatypes.html) +and with or without nullability property. For more details on the Arrow Memory Layout see this +[document](https://arrow.apache.org/docs/format/Columnar.html). + +A set of specific and well-defined Arrow Schemas is used for each OTel entity type (metrics, logs, traces). + +The current OTel metric model can be summarized by this UML diagram: + +![OTel Metrics Model](img/0156_OTEL-Metric-Model.png) + +The leaf nodes (in green in this diagram) are where the data are actually defined as list of attributes and metrics. +Basically the relationship between the metric and resource nodes is a many-to-one relationship. Similarly, the +relationship between the metric and instrumentation scope nodes is also a many-to-one relationship. + +The approach chosen for this proposal involves dividing the OTel entities into multiple Arrow RecordBatches. Each of +these RecordBatches will possess a specific schema and will be linked to other RecordBatches through a combination of +primary and foreign keys. This methodology offers an optimal balance between compression ratio, queryability, and ease +of integration with existing Arrow-based tools. + +To maximize the benefits of this columnar representation, OTel Arrow sorts a subset of columns to enhance the locality +of identical data, thereby amplifying the compression ratio. + +Finally, to mitigate the overhead of defining schemas and dictionaries, we use the Arrow IPC format. RecordBatches sharing the +same schema are grouped in a homogeneous stream. The first message sent contains in addition to the columns data, +the schema definition and the dictionaries. The following messages will not need to define the schema anymore. +The dictionaries will only be sent again when their content change. The following diagram illustrates this process. + +> Note: The approach of using a single Arrow record per OTel entity, which employs list, struct, and union Arrow data +> types, was not adopted mainly due to the inability to sort each level of the OTel hierarchy independently. The mapping +> delineated in this document, on average, provides a superior compression ratio. + +![Arrow IPC](img/0156_OTEL%20-%20Arrow%20IPC.png) + +The next sections describe the schema of each type of `ArrowPayload`. The mapping of OTLP entities +to `ArrowPayload` has been designed to be reversible in order to be able to implement an OTel Arrow -> OTLP +receiver. + +#### Logs Arrow Mapping + +We begin with the logs payload as it is the most straightforward to map onto Arrow. The following Entity Relationship +Diagram succinctly describes the schemas of the four Arrow record utilized to represent a batch of OTLP logs. + +The `LOGS` entity contains a flattened representation of the `LogRecord`, merged with `ResourceLogs` and `ScopeLogs`. +The `id` column functions as a primary key, linking the `LogRecord` with their corresponding attributes, which are +stored in the `LOG_ATTRS` entity. The `resource_id` column serves as a key, associating each `ResourceLogs` instance +with their respective attributes stored in the `RESOURCE_ATTRS` entity. Likewise, the `scope_id` column acts as a key +to link each `ScopeLogs` instance with their corresponding attributes found in the `SCOPE_ATTRS` entity. + +![Logs Arrow Schema](img/0156_logs_schema.png) + +Each of these Arrow records is sorted by specific columns to optimize the compression ratio. The `id`, `resource_id`, +and `scope_id` are stored with delta encoding to minimize their size post-compression. `parent_id` is also stored with a +variant of delta encoding, known as "delta group encoding" (more details will follow). + +Attributes are represented as a triad of columns: `key`, `type`, and one of the following columns: `str`, `int`, +`double`, `bool`, `bytes`, `ser`. The `key` column is a string dictionary, the `type` column is an enum with six +variants, and the value column depends on the type of the attribute. The `ser` column is a binary column containing the +CBOR encoding of the attribute value when the attribute type is complex (e.g., map, or array). Unused value columns are +filled with null values. + +The `body` is represented with the tuple `body_type` and one of the following columns: `body_str`, `body_int`, +`body_double`, `body_bool`, `body_bytes`, `body_ser`. + +This representation offers several advantages: + +- Each record can be sorted independently to better arrange the data for compression. +- Primary keys and foreign keys can be used to connect the different Arrow records, and they easily integrate with SQL +engines. +- The avoidance of complex Arrow data types (like union, list of struct) optimizes compatibility with the Arrow +ecosystem. + +> Note: Complex attribute values could also be encoded in protobuf once the `pdata` library provides support for it. + +#### Spans Arrow Mapping + +The approach for OTLP traces is similar to that used for logs. The primary `SPANS` entity (i.e., Arrow record) +encompasses a flattened representation of `ResourceSpans`, `ScopeSpans`, and `Spans`. Beyond the standard set of +attributes (i.e., resource, scope, and span attributes), this mapping represents span events and span links as distinct +entities (`SPAN_EVENTS` and `SPAN_LINKS` respectively). These have a 1-to-many relationship with the `SPANS` entity. +Each of these entities is also associated with dedicated attribute entities (i.e. `SPAN_EVENT_ATTRS` and +`SPAN_LINK_ATTRS`). + +![Traces Arrow Schema](img/0156_traces_schema.png) + +Similarly, each of the Arrow records is sorted by specific columns to optimize the compression ratio. + +The `end_time_unix_nano` is represented as a duration (`end_time_unix_nano` - `start_time_unix_nano`) to reduce the +number of bits required to represent the timestamp. + +#### Metrics Arrow Mapping + +The mapping for metrics, while being the most complex, fundamentally follows the same logic as applied to logs and +spans. The primary 'METRICS' entity encapsulates a flattened representation of `ResourceMetrics`, `ScopeMetrics`, and +`Metrics`. All common columns among the different metric types are consolidated in this main entity (i.e., `metric_type`, +`name`, `description`, `unit`, `aggregation_temporality`, and `is_monotonic`). Furthermore, a dedicated entity is +crafted to represent data points for each type of metrics, with their columns being specific to the respective metric +type. For instance, the `SUMMARY_DATA_POINTS` entity includes columns `id`, `parent_id`, `start_time_unix_nano`, +`time_unix_nano`, `count`, `sum`, and `flags`. Each of these "data points" entities is linked to: + +- A set of data point attributes (following a one-to-many relationship). +- A set of data points exemplars (also adhering to a one-to-many relationship). + +Exemplar entities, in turn, are connected to their dedicated set of attributes. + +Technically speaking, the `quantile` entity isn't encoded as an independent entity but rather as a list of struct within +the `SUMMARY_DATA_POINTS entity`. + +![Metrics Arrow Schema](img/0156_metrics_schema.png) + +Gauge and Sum are identified by the `metric_type` column in the `METRICS` entity and they share the same Arrow record +for the data points, i.e. `NUMBER_DATA_POINTS`. + +`span_id` and `trace_id` are represented as fixed size binary dictionaries by default but can evolve to non-dictionary +form when their cardinality exceeds a certain threshold (usually 2^16). + +As usual, each of these Arrow records is sorted by specific columns to optimize the compression ratio. With this mapping +batch of metrics containing a large number of data points sharing the same attributes and timestamp will be highly +compressible (multivariate time-series scenario). + +> Note: every OTLP timestamps are represented as Arrow timestamps as Epoch timestamps with nanosecond precision. This representation will +> simplify the integration with the rest of the Arrow ecosystem (numerous time/date functions are supported in +> DataFusion for example). +> Note: aggregation_temporality is represented as an Arrow dictionary with a dictionary index of type int8. This OTLP +> enum has currently 3 variants, and we don't expect to have in the future more than 2^8 variants. + +## Implementation Recommendations + +### Protocol Extension and Fallback Mechanism + +The support of this new protocol can only be progressive, so implementers are advised to follow the following +implementation recommendations in phase 1: + +* `OTelArrow Receiver`: Listen on a single TCP port for both OTLP and OTel Arrow protocols. The goal is to make the + support of this protocol extension transparent and automatic. This can be achieved by adding the `ArrowStreamService` + to the same gRPC listener. A configuration parameter will be added to the OTelArrow receiver to disable this default + behavior to support specific uses. +* `OTelArrow Exporter`: By default the OTelArrow exporter should initiate a connection to the `ArrowStreamService` + endpoint of the target receiver. If this connection fails because the `ArrowStreamService` is not implemented by the + target, the exporter must automatically fall back on the behavior of the OTLP protocol. A configuration parameter + could be added to disable this default behavior. + +The implementation of these two rules should allow a seamless and +adaptive integration of OTel Arrow into the current ecosystem +generally. + +For the prototype specifically, which is a fork of the OpenTelemetry +collector codebase, we have derived the OTelArrow exporter and +receiver as set of changes directly to the `receiver/otelarrowreceiver` and +`exporter/otelarrowexporter` components, with new `internal/arrow` packages +in both. With every collector release we merge the OTel Arrow changes +with the mainline components to maintain this promise of +compatibility. + +OTel Arrow supports conveying the gRPC metadata (i.e., http2 headers) using a dedicated `bytes` field. Metadata is +encoded using [hpack](https://datatracker.ietf.org/doc/rfc7541/) like a typical unary gRPC request. + +Specifically: + +#### OTelArrow/gRPC Receiver + +When Arrow is enabled, the OTelArrow receiver listens for both the standard unary gRPC service OTLP and OTel Arrow stream +services. Each stream uses an instance of the OTel-Arrow-Adapter's +[Consumer](https://pkg.go.dev/github.com/f5/otel-arrow-adapter@v0.0.0-20230112224802-dafb6df21c97/pkg/otel/arrow_record#Consumer). Sets +`client.Metadata` in the Context. + +#### OTelArrow/gRPC Exporter + +When Arrow is enabled, the OTelArrow exporter starts a fixed number of streams and repeatedly sends one `plog.Logs`, +`ptrace.Traces`, or `pmetric.Metrics` item per stream request. The `exporterhelper` callback first tries to get an +available stream, blocking when none are available (or until the connection is downgraded), and then falls back to the +standard unary gRPC path. The stream-sending mechanism internally handles retries when failures are caused by streams +restarting, while honoring the caller's context deadline, to avoid delays introduced by allowing these retries to go +through the `exporterhelper` mechanism. + +Each stream uses an instance of the OTel-Arrow-Adapter's +[Producer](https://pkg.go.dev/github.com/f5/otel-arrow-adapter@v0.0.0-20230112224802-dafb6df21c97/pkg/otel/arrow_record#Producer). + +When a stream fails specifically because the server does not recognize the Arrow service, it will not restart. When all +streams have failed in this manner, the connection downgrades by closing a channel, at which point the exporter behaves +exactly as the OTLP exporter. + +The mechanism as described is vulnerable to partial failure scenarios. When some of the streams are succeeding but some +have failed with Arrow unsupported, the collector performance will be degraded because callers are blocked waiting for +available streams. The exact signal used to signal that Arrow and downgrade mechanism is seen as an area for future +development. [See the prototype's test for whether to downgrade.](https://github.com/open-telemetry/experimental-arrow-collector/blob/30e0ffb230d3d2f1ad9645ec54a90bbb7b9878c2/exporter/otlpexporter/internal/arrow/stream.go#L152) + +### Batch ID Generation + +The `batch_id` attribute is used by the message delivery mechanism. Each `BatchArrowRecords` issued must be associated with a +unique `batch_id`. Uniqueness must be ensured in the scope of the stream opened by the call to the `ArrowStreamService`. +This `batch_id` will be used in the `BatchStatus` object to acknowledge receipt and processing of the corresponding +batch. +A numeric counter is used to implement this batch_id, the goal being to use the most concise id possible. + +### Schema ID Generation + +Within the collector, batching, filtering, exporting, ... operations require to group the Arrow Records having a +compatible schema. A synthetic identifier (or `schema_id`) must be computed for each `ArrowPayload` to perform this +grouping. + +We recommend calculating the schema id in the following way: + +* for each Arrow Schema create a list of triples (name, type, metadata) for each column. +* sort these triples according to a lexicographic order. +* concatenate the sorted triples with a separator and use these identifiers as `schema_id` (or a shorter version via + an equivalence table). + +### Traffic Balancing Optimization + +To mitigate the usual pitfalls of a stream-oriented protocol, protocol implementers are advised to: + +* client side: create several streams in parallel (e.g. create a new stream every 10 event types), +* server side: close streams that have been open for a long time (e.g. close stream every 1 hour). + +These parameters must be exposed in a configuration file and be tuned according to the application. + +### Throttling + +OTel Arrow allows backpressure signaling. If the server is unable to keep up with the pace of data it receives from the +client then it should signal that fact to the client. The client must then throttle itself to avoid overwhelming the +server. + +To signal backpressure when using OTel Arrow, the server should return an error with code UNAVAILABLE and may supply +additional details via the `retry_info` attribute. + +When the client receives this signal it should follow the recommendations outlined in documentation for RetryInfo: + +``` +// Describes when the clients can retry a failed request. Clients could ignore +// the recommendation here or retry when this information is missing from error +// responses. +// +// It's always recommended that clients should use exponential backoff when +// retrying. +// +// Clients should wait until `retry_delay` amount of time has passed since +// receiving the error response before retrying. If retrying requests also +// fail, clients should use an exponential backoff scheme to gradually increase +// the delay between retries based on `retry_delay`, until either a maximum +// number of retires have been reached or a maximum retry delay cap has been +// reached. +``` + +The value of retry_delay is determined by the server and is implementation dependent. The server should choose a +retry_delay value that is big enough to give the server time to recover, yet is not too big to cause the client to drop +data while it is throttled. + +Throttling is important for implementing reliable multi-hop telemetry data delivery all the way from the source to the +destination via intermediate nodes, each having different processing capacity and thus requiring different data transfer +rates. + +### Delivery Guarantee + +The OTel Arrow protocol adheres to the OpenTelemetry Protocol (OTLP) specification, particularly in terms of delivery guarantee. +The collector ensures that messages received will only receive a positive acknowledgement if they have been properly +processed by the various stages of the collector. + +## Risks and Mitigations + +An authentication mechanism is highly recommended to protect against malicious traffic. Without authentication, an OTel +Arrow receiver can be attacked in multiple ways ranging from DoS, traffic amplification to sending sensitive data. This +specification reuses the authentication mechanisms already in place in the collector. + +## Trade-offs and Mitigations + +### Duplicate Data + +In edge cases (e.g. on reconnections, network interruptions, etc) the client has no way of knowing if recently sent data +was delivered if no acknowledgement was received yet. The client will typically choose to re-send such data to guarantee +delivery, which may result in duplicate data on the server side. This is a deliberate choice and is considered to be the +right tradeoff for telemetry data. This can be mitigated by using an idempotent insertion mechanism at the data backend +level. + +### Incompatible Backends + +Backends that don't support natively multivariate time-series can still automatically transform these events in multiple +univariate time-series and operate as usual. + +### Small Devices/Small Telemetry Data Stream + +A columnar-oriented protocol is not necessarily desirable for all scenarios (e.g. devices that do not have the resources +to accumulate data in batches). This protocol extension allows to better respond to these different scenarios by letting +the client select between OTLP or OTel Arrow protocol depending on the nature of its telemetry traffic. + +## Future Versions and Interoperability + +As far as protocol evolution and interoperability mechanisms are concerned, this extension follows the +[recommendations](https://github.com/open-telemetry/oteps/blob/main/text/0035-opentelemetry-protocol.md#future-versions-and-interoperability) +outlined in the OTLP spec. + +## Prior Art and Alternatives + +We considered using a purely protobuf-based columnar encoding for this protocol extension. The realization of a +prototype and its comparison with [Apache Arrow](https://arrow.apache.org/) dissuaded us to continue in this direction. + +We also considered using [VNG](https://zed.brimdata.io/docs/formats/vng) from the Zed project as a columnar coding +technology. Although this format has interesting properties, this project has not yet reached a sufficient level of +maturity comparable to Apache Arrow. + +Finally, we also considered the use of Parquet records encapsulated in protobuf messages (similar to the approach described +in this document). Although a Parquet representation offers some additional encoding modes that can improve the compression +ratio, Parquet is not designed as an in-memory format optimized for online data processing. Apache Arrow is optimized for +this type of scenario and offers the best trade-off of compression ratio, processing speed, and serialization/deserialization speed. + +## Monitoring OTel-Arrow performance + +[OpenTelemetry Collector users would benefit from standard ways to monitor the number of network bytes sent and received.](https://github.com/open-telemetry/opentelemetry-collector/issues/6638). [We have proposed the use of dedicated `obsreport` metrics in the Collector.](https://github.com/open-telemetry/opentelemetry-collector/pull/6712). + +In connection with these proposals, [we also propose corresponding improvements in the OpenTelemetry +Collector-Contrib's `testbed` framework](https://github.com/open-telemetry/opentelemetry-collector-contrib/pull/16835), +in order to include OTel-Arrow in standard regression testing of the Collector. + +## Open Questions + +### Extending into other parts of the Arrow ecosystem + +A SQL support for telemetry data processing remains an open question in the current Go collector. The main OTelArrow query +engine [Datafusion](https://github.com/apache/arrow-datafusion) is implemented in Rust. Several solutions can be +considered: 1) create a Go wrapper on top of Datafusion, 2) implement a Rust collector dedicated to the end-to-end +support of OTel Arrow, 3) implement a SQL/Arrow engine in Go (big project). A proof of concept using Datafusion has been +implemented in Rust and has shown very good results. + +We believe that because the Arrow IPC mechanism and data format is intended for zero-copy use, we believe it is possible +to use Arrow libraries written in other languages, for example within the Golang-based OpenTelemetry Collector. + +### Choosing row-oriented transport when it is more efficient + +The columnar representation is more efficient for transporting large homogeneous batches. The support of a mixed approach +combining automatically column-oriented and row-oriented batches would allow to cover all scenarios. The development of +a strategy to automatically select the best data representation mode is an open question. + +### Unary gRPC OTel Arrow and HTTP OTel Arrow + +The design currently calls for the use of gRPC streams to benefit from OTel Arrow transport. We believe that some of +this benefit can be had even for unary gRPC and HTTP requests with large request batches to amortize sending of +dictionary and schema information. This remains an area for study. + +## Future possibilities + +### Further-integrated compression techniques + +ZSTD offers a training mode, which can be used to tune the algorithm for a selected type of data. The result of this +training is a dictionary that can be used to compress the data. Using this [dictionary](http://facebook.github.io/zstd/#small-data) +can dramatically improve the compression rate for small batches. This future development will build on both the gRPC +stream approach used in this proposal and the ability to send a ZSTD dictionary over the OTel Arrow stateful protocol, +allowing us to train the ZSTD algorithm on the first batches and then update the configuration of the ZSTD +encoder/decoder with an optimized dictionary. + +More advanced lightweight compression algorithms on a per column basis could be integrated to the OTel Arrow +protocol (e.g. [delta delta encoding](https://www.vldb.org/pvldb/vol8/p1816-teller.pdf) for numerical columns) + +## Appendix A - Protocol Buffer Definitions + +Protobuf specification for an Arrow-based OpenTelemetry event. + +```protobuf +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// This protocol specifies the services and messages utilized by the OTel Arrow +// Protocol. OTelArrow represents OTLP entities in a columnar manner using +// Apache Arrow. The primary objective of this new protocol is to optimize +// transport efficiency in terms of compression (phase 1), memory, and CPU usage +// (phase 2). +// +// Note: This protocol is still experimental and subject to change. + +syntax = "proto3"; + +package opentelemetry.proto.experimental.arrow.v1; + +option java_multiple_files = true; +option java_package = "io.opentelemetry.proto.experimental.arrow.v1"; +option java_outer_classname = "ArrowServiceProto"; + +// Note the following is temporary +option go_package = "github.com/f5/otel-arrow-adapter/api/experimental/arrow/v1"; + +// This service can be utilized to transmit `BatchArrowRecords` either from an +// application instrumented with OpenTelemetry to a collector, or between +// multiple collectors. +// +// Note: If your deployment requires to load-balance the telemetry data based on +// the nature of the telemetry data (e.g. traces, metrics, logs), then you should +// use the `ArrowTracesService`, `ArrowMetricsService`, and `ArrowLogsService`. +service ArrowStreamService { + // The ArrowStream endpoint is a bi-directional stream used to send batch of + // `BatchArrowRecords` from the exporter to the collector. The collector + // returns `BatchStatus` messages to acknowledge the `BatchArrowRecords` + // messages received. + rpc ArrowStream(stream BatchArrowRecords) returns (stream BatchStatus) {} +} + +// ArrowTracesService is a traces-only Arrow stream. +service ArrowTracesService { + rpc ArrowTraces(stream BatchArrowRecords) returns (stream BatchStatus) {} +} + +// ArrowTracesService is a logs-only Arrow stream. +service ArrowLogsService { + rpc ArrowLogs(stream BatchArrowRecords) returns (stream BatchStatus) {} +} + +// ArrowTracesService is a metrics-only Arrow stream. +service ArrowMetricsService { + rpc ArrowMetrics(stream BatchArrowRecords) returns (stream BatchStatus) {} +} + +// A message sent by an exporter to a collector containing a batch of Arrow +// records. +message BatchArrowRecords { + // [mandatory] Batch ID. Must be unique in the context of the stream. + int64 batch_id = 1; + + // [mandatory] A collection of payloads containing the data of the batch. + repeated ArrowPayload arrow_payloads = 2; + + // [optional] Headers associated with this batch, encoded using hpack. + bytes headers = 3; +} + +// Enumeration of all the OTel Arrow payload types currently supported by the +// OTel Arrow protocol. +enum ArrowPayloadType { + UNKNOWN = 0; + + // A payload representing a collection of resource attributes. + RESOURCE_ATTRS = 1; + // A payload representing a collection of scope attributes. + SCOPE_ATTRS = 2; + + // A set of payloads representing a collection of metrics. + METRICS = 10; // Main metric payload + NUMBER_DATA_POINTS = 11; + SUMMARY_DATA_POINTS = 12; + HISTOGRAM_DATA_POINTS = 13; + EXP_HISTOGRAM_DATA_POINTS = 14; + NUMBER_DP_ATTRS = 15; + SUMMARY_DP_ATTRS = 16; + HISTOGRAM_DP_ATTRS = 17; + EXP_HISTOGRAM_DP_ATTRS = 18; + NUMBER_DP_EXEMPLARS = 19; + HISTOGRAM_DP_EXEMPLARS = 20; + EXP_HISTOGRAM_DP_EXEMPLARS = 21; + NUMBER_DP_EXEMPLAR_ATTRS = 22; + HISTOGRAM_DP_EXEMPLAR_ATTRS = 23; + EXP_HISTOGRAM_DP_EXEMPLAR_ATTRS = 24; + + // A set of payloads representing a collection of logs. + LOGS = 30; + LOG_ATTRS = 31; + + // A set of payloads representing a collection of traces. + SPANS = 40; + SPAN_ATTRS = 41; + SPAN_EVENTS = 42; + SPAN_LINKS = 43; + SPAN_EVENT_ATTRS = 44; + SPAN_LINK_ATTRS = 45; +} + +// Represents a batch of OTel Arrow entities. +message ArrowPayload { + // [mandatory] A canonical ID representing the schema of the Arrow Record. + // This ID is used on the consumer side to determine the IPC reader to use + // for interpreting the corresponding record. For any NEW `schema_id`, the + // consumer must: + // 1) close the current IPC reader, + // 2) create a new IPC reader in order to interpret the new schema, + // dictionaries, and corresponding data. + string schema_id = 1; + + // [mandatory] Type of the OTel Arrow payload. + ArrowPayloadType type = 2; + + // [mandatory] Serialized Arrow Record Batch + // For a description of the Arrow IPC format see: + // https://arrow.apache.org/docs/format/Columnar.html#serialization-and-interprocess-communication-ipc + bytes record = 3; +} + +// A message sent by a Collector to the exporter that opened the data stream. +message BatchStatus { + repeated StatusMessage statuses = 1; +} + +message StatusMessage { + int_64 batch_id = 1; + StatusCode status_code = 2; + ErrorCode error_code = 3; + string error_message = 4; + RetryInfo retry_info = 5; +} + +enum StatusCode { + OK = 0; + ERROR = 1; +} + +enum ErrorCode { + UNAVAILABLE = 0; + INVALID_ARGUMENT = 1; +} + +message RetryInfo { + int64 retry_delay = 1; +} +``` + +## Glossary + +### Arrow Dictionary + +Apache Arrow allows to encode a text or binary column as a dictionary (numeric index -> text/binary buffer). When this +encoding is used, the column contains only the index values and the dictionary is attached to the schema for reference. +This type of encoding significantly reduce the space occupied by text or binary columns with low cardinalities +(usually less than 2^16 distinct values). See Apache Arrow [documentation](https://arrow.apache.org/docs/python/data.html#dictionary-arrays) +for more details. + +### Arrow IPC Format + +The [Arrow IPC format](https://arrow.apache.org/docs/python/ipc.html) is used to efficiently send homogenous record +batches in stream mode. The schema is only sent at the beginning of the stream. Dictionaries are only sent when they are +updated. + +### Multivariate Time-series + +A multivariate time series has more than one time-dependent variable. Each variable depends not only on +its past values but also has some dependency on other variables. A 3 axis accelerometer reporting 3 metrics +simultaneously; a mouse move that simultaneously reports the values of x and y, a meteorological weather station +reporting temperature, cloud cover, dew point, humidity and wind speed; an http transaction characterized by many +interrelated metrics sharing the same attributes are all common examples of multivariate time-series. + +## Acknowledgements + +Special thanks to [Joshua MacDonald](https://github.com/jmacd) for his contribution in integrating the reference +implementation into the OTel collector, to [Tigran Najaryan](https://github.com/tigrannajaryan) for helping to define +the integration strategy with the OTLP protocol, and to [Sébastien Soudan](https://github.com/ssoudan) for the +numerous exchanges and advice on the representation of the data charts. + +Thanks to all reviewers who participated in the review and validation of this [PR](https://github.com/open-telemetry/oteps/pull/171). + +Finally, many thanks to [F5](https://www.f5.com/) for supporting this effort. diff --git a/text/img/0156-arrow-ecosystem.svg b/text/img/0156-arrow-ecosystem.svg new file mode 100644 index 000000000..61b319d24 --- /dev/null +++ b/text/img/0156-arrow-ecosystem.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/text/img/0156-resource-events.svg b/text/img/0156-resource-events.svg new file mode 100644 index 000000000..8e32f99dd --- /dev/null +++ b/text/img/0156-resource-events.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/text/img/0156_All trials.png b/text/img/0156_All trials.png new file mode 100644 index 000000000..0a9bdce47 Binary files /dev/null and b/text/img/0156_All trials.png differ diff --git a/text/img/0156_Best trials.png b/text/img/0156_Best trials.png new file mode 100644 index 000000000..c89aaafb6 Binary files /dev/null and b/text/img/0156_Best trials.png differ diff --git a/text/img/0156_OTEL - Arrow IPC.png b/text/img/0156_OTEL - Arrow IPC.png new file mode 100644 index 000000000..b65a24691 Binary files /dev/null and b/text/img/0156_OTEL - Arrow IPC.png differ diff --git a/text/img/0156_OTEL - HowToUseArrow.png b/text/img/0156_OTEL - HowToUseArrow.png new file mode 100644 index 000000000..154e1d863 Binary files /dev/null and b/text/img/0156_OTEL - HowToUseArrow.png differ diff --git a/text/img/0156_OTEL - ProtocolSeqDiagram.png b/text/img/0156_OTEL - ProtocolSeqDiagram.png new file mode 100644 index 000000000..c623f2349 Binary files /dev/null and b/text/img/0156_OTEL - ProtocolSeqDiagram.png differ diff --git a/text/img/0156_OTEL - Row vs Column.png b/text/img/0156_OTEL - Row vs Column.png new file mode 100644 index 000000000..ea11561f6 Binary files /dev/null and b/text/img/0156_OTEL - Row vs Column.png differ diff --git a/text/img/0156_OTEL-Metric-Model.png b/text/img/0156_OTEL-Metric-Model.png new file mode 100644 index 000000000..1bd38128c Binary files /dev/null and b/text/img/0156_OTEL-Metric-Model.png differ diff --git a/text/img/0156_RecordBatch.png b/text/img/0156_RecordBatch.png new file mode 100644 index 000000000..f32969ca9 Binary files /dev/null and b/text/img/0156_RecordBatch.png differ diff --git a/text/img/0156_collector_internal_overview.png b/text/img/0156_collector_internal_overview.png new file mode 100644 index 000000000..0d86e6b5d Binary files /dev/null and b/text/img/0156_collector_internal_overview.png differ diff --git a/text/img/0156_collector_phase_2.png b/text/img/0156_collector_phase_2.png new file mode 100644 index 000000000..829c39d2c Binary files /dev/null and b/text/img/0156_collector_phase_2.png differ diff --git a/text/img/0156_compression_ratio_summary_multivariate_metrics.png b/text/img/0156_compression_ratio_summary_multivariate_metrics.png new file mode 100644 index 000000000..a09e4fb07 Binary files /dev/null and b/text/img/0156_compression_ratio_summary_multivariate_metrics.png differ diff --git a/text/img/0156_compression_ratio_summary_std_metrics.png b/text/img/0156_compression_ratio_summary_std_metrics.png new file mode 100644 index 000000000..ca39029c3 Binary files /dev/null and b/text/img/0156_compression_ratio_summary_std_metrics.png differ diff --git a/text/img/0156_logs_bytes.png b/text/img/0156_logs_bytes.png new file mode 100644 index 000000000..52d8374e6 Binary files /dev/null and b/text/img/0156_logs_bytes.png differ diff --git a/text/img/0156_logs_schema.png b/text/img/0156_logs_schema.png new file mode 100644 index 000000000..9e3eb4be5 Binary files /dev/null and b/text/img/0156_logs_schema.png differ diff --git a/text/img/0156_logs_step_times.png b/text/img/0156_logs_step_times.png new file mode 100644 index 000000000..a3e98c2ef Binary files /dev/null and b/text/img/0156_logs_step_times.png differ diff --git a/text/img/0156_logs_step_times_phase1.png b/text/img/0156_logs_step_times_phase1.png new file mode 100644 index 000000000..d1f50d02f Binary files /dev/null and b/text/img/0156_logs_step_times_phase1.png differ diff --git a/text/img/0156_metrics_schema.png b/text/img/0156_metrics_schema.png new file mode 100644 index 000000000..2d94e64bb Binary files /dev/null and b/text/img/0156_metrics_schema.png differ diff --git a/text/img/0156_metrics_small_batches.png b/text/img/0156_metrics_small_batches.png new file mode 100644 index 000000000..74db3c7c7 Binary files /dev/null and b/text/img/0156_metrics_small_batches.png differ diff --git a/text/img/0156_metrics_step_times.png b/text/img/0156_metrics_step_times.png new file mode 100644 index 000000000..3e792a991 Binary files /dev/null and b/text/img/0156_metrics_step_times.png differ diff --git a/text/img/0156_metrics_step_times_phase1.png b/text/img/0156_metrics_step_times_phase1.png new file mode 100644 index 000000000..1f9c40c77 Binary files /dev/null and b/text/img/0156_metrics_step_times_phase1.png differ diff --git a/text/img/0156_multivariate_metrics_bytes.png b/text/img/0156_multivariate_metrics_bytes.png new file mode 100644 index 000000000..f7caf50f2 Binary files /dev/null and b/text/img/0156_multivariate_metrics_bytes.png differ diff --git a/text/img/0156_summary.png b/text/img/0156_summary.png new file mode 100644 index 000000000..8b83027c3 Binary files /dev/null and b/text/img/0156_summary.png differ diff --git a/text/img/0156_summary_time_spent.png b/text/img/0156_summary_time_spent.png new file mode 100644 index 000000000..9ccdc4118 Binary files /dev/null and b/text/img/0156_summary_time_spent.png differ diff --git a/text/img/0156_traces_schema.png b/text/img/0156_traces_schema.png new file mode 100644 index 000000000..98a20ee4e Binary files /dev/null and b/text/img/0156_traces_schema.png differ diff --git a/text/img/0156_traces_step_times_phase1.png b/text/img/0156_traces_step_times_phase1.png new file mode 100644 index 000000000..dba3d5b35 Binary files /dev/null and b/text/img/0156_traces_step_times_phase1.png differ diff --git a/text/img/0156_traffic_reduction_use_case.png b/text/img/0156_traffic_reduction_use_case.png new file mode 100644 index 000000000..12b9ae34f Binary files /dev/null and b/text/img/0156_traffic_reduction_use_case.png differ diff --git a/text/img/0156_univariate_metrics_bytes.png b/text/img/0156_univariate_metrics_bytes.png new file mode 100644 index 000000000..6c23d7725 Binary files /dev/null and b/text/img/0156_univariate_metrics_bytes.png differ