Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ddtrace/tracer: use math/rand/v2 for SpanID and TraceID #2689

Merged
merged 4 commits into from
May 22, 2024

Conversation

knusbaum
Copy link
Contributor

@knusbaum knusbaum commented May 9, 2024

With the new version 2 of the math/rand standard library package, there is no longer a need to perform our own complicated initialization of an RNG, and in fact, we should avoid doing so.

See more details about the new rand package here: https://go.dev/blog/randv2

Instead, we can rely on the global RNG provided by the Go runtime. We previously chose not to do that because we could not rely on the global RNG to be initialized, meaning there would likely be many trace and span ID clashes. Likewise, it was a bad idea to initialize the RNG ourselves, since as a library it's bad practice to mutate global state in a way that will have visible effects on the application.

We previously chose to initialize our own RNG instance for the tracer and synchronize access to it. Due to the low entropy of the RNG seed (it only used 32 bits of the 64 provided) we also chose to xor the produced random numbers with the current unix time in order to decrease collisions.

math/rand/v2 removes the need to do either of those things. The new global RNG is automatically seeded at startup with enough entropy to remove the need to xor with a timestamp. It also has the added benefit of being per-goroutine, meaning there is no synchronization involved.

This PR adds a new implementation of the span/trace ID generator which will be used for all Go applications compiled with go1.22.0 and later. The old implementation remains for older versions of Go, but should be removed once those versions fall out of the support window.

I've also added some benchmarks and used them to compare the old and new implementations.

The benefits of this change are a smaller implementation and less historical baggage, as well as improved performance if there are lots of threads trying to generate spans.

goos: linux
goarch: amd64
pkg: gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer
cpu: 13th Gen Intel(R) Core(TM) i5-1340P
                       │  old.bench   │              new.bench              │
                       │    sec/op    │   sec/op     vs base                │
StartSpan-16              1.681µ ± 3%   1.662µ ± 3%        ~ (p=0.447 n=10)
StartSpanConcurrent-16    4.673µ ± 1%   3.955µ ± 3%  -15.37% (p=0.000 n=10)
GenSpanID-16             13.840n ± 0%   4.502n ± 1%  -67.47% (p=0.000 n=10)
geomean                   477.3n        309.3n       -35.20%

                       │   old.bench    │               new.bench               │
                       │      B/op      │     B/op      vs base                 │
StartSpan-16             1.603Ki ± 0%     1.603Ki ± 0%       ~ (p=1.000 n=10) ¹
StartSpanConcurrent-16   16.05Ki ± 0%     16.04Ki ± 0%  -0.03% (p=0.000 n=10)
GenSpanID-16               0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
geomean                               ²                 -0.01%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                       │  old.bench   │              new.bench              │
                       │  allocs/op   │ allocs/op   vs base                 │
StartSpan-16             16.00 ± 0%     16.00 ± 0%       ~ (p=1.000 n=10) ¹
StartSpanConcurrent-16   160.0 ± 0%     160.0 ± 0%       ~ (p=1.000 n=10) ¹
GenSpanID-16             0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
geomean                             ²               +0.00%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean

Motivation

  • Changed code has unit tests for its functionality at or near 100% coverage.
  • System-Tests covering this feature have been added and enabled with the va.b.c-dev version tag.
  • There is a benchmark for any new code, or changes to existing code.
  • If this interacts with the agent in a new way, a system test has been added.
  • Add an appropriate team label so this PR gets put in the right place for the release notes.
  • Non-trivial go.mod changes, e.g. adding new modules, are reviewed by @DataDog/dd-trace-go-guild.

Unsure? Have a question? Request a review!

@knusbaum knusbaum requested review from a team as code owners May 9, 2024 16:38
@knusbaum knusbaum force-pushed the knusbaum/new-rand branch from 4ee1a83 to aee9c87 Compare May 9, 2024 16:48
With the new version 2 of the math/rand standard library package, there is
no longer a need to perform our own complicated initialization of an RNG,
and in fact, we should avoid doing so.

See more details about the new rand package here: https://go.dev/blog/randv2

Instead, we can rely on the global RNG provided by the Go runtime. We
previously chose not to do that because we could not rely on the global RNG
to be initialized, meaning there would likely be many trace and span ID
clashes. Likewise, it was a bad idea to initialize the RNG ourselves, since
as a library it's bad practice to mutate global state in a way that will
have visible effects on the application.

We previously chose to initialize our own RNG instance for the tracer and
synchronize access to it. Due to the low entropy of the RNG seed (it only
used 32 bits of the 64 provided) we also chose to xor the produced random
numbers with the current unix time in order to decrease collisions.

math/rand/v2 removes the need to do either of those things. The new global
RNG is automatically seeded at startup with enough entropy to remove the
need to xor with a timestamp. It also has the added benefit of being
per-goroutine, meaning there is no synchronization involved.

This PR adds a new implementation of the span/trace ID generator which will
be used for all Go applications compiled with go1.22.0 and later. The old
implementation remains for older versions of Go, but should be removed once
those versions fall out of the support window.

I've also added some benchmarks and used them to compare the old and new
implementations.

The benefits of this change are a smaller implementation and less
historical baggage, as well as improved performance if there are lots of
threads trying to generate spans.

```
goos: linux
goarch: amd64
pkg: gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer
cpu: 13th Gen Intel(R) Core(TM) i5-1340P
                       │  old.bench   │              new.bench              │
                       │    sec/op    │   sec/op     vs base                │
StartSpan-16              1.681µ ± 3%   1.662µ ± 3%        ~ (p=0.447 n=10)
StartSpanConcurrent-16    4.673µ ± 1%   3.955µ ± 3%  -15.37% (p=0.000 n=10)
GenSpanID-16             13.840n ± 0%   4.502n ± 1%  -67.47% (p=0.000 n=10)
geomean                   477.3n        309.3n       -35.20%

                       │   old.bench    │               new.bench               │
                       │      B/op      │     B/op      vs base                 │
StartSpan-16             1.603Ki ± 0%     1.603Ki ± 0%       ~ (p=1.000 n=10) ¹
StartSpanConcurrent-16   16.05Ki ± 0%     16.04Ki ± 0%  -0.03% (p=0.000 n=10)
GenSpanID-16               0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=10) ¹
geomean                               ²                 -0.01%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                       │  old.bench   │              new.bench              │
                       │  allocs/op   │ allocs/op   vs base                 │
StartSpan-16             16.00 ± 0%     16.00 ± 0%       ~ (p=1.000 n=10) ¹
StartSpanConcurrent-16   160.0 ± 0%     160.0 ± 0%       ~ (p=1.000 n=10) ¹
GenSpanID-16             0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=10) ¹
geomean                             ²               +0.00%                ²
¹ all samples are equal
² summaries must be >0 to compute geomean
```
Copy link
Member

@darccio darccio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@darccio darccio merged commit 14d15d5 into DataDog:main May 22, 2024
101 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants