Skip to content

Use math/rand top-level functions in grpcrand #6650

Closed
@huangchong94

Description

@huangchong94

Background

Although the rand object in math/rand is not safe for concurrent access , but the top-level functions defined in math/rand are concurrent-safe and since go1.20.0 these functions are auto-seeded.

Starting from 1.21.0 those functions are not only concurrent-safe, auto-seeded, but also lock-free (most of them are lock-free, except rand.Read), which run significantly faster than rand with mutex, especially for parallel calls.

The grpcrand package is widely used in grpc-go, some of its functionality is used in critical path like Picker.Pick (eg picker in leastrequest.go). The current approach of grpcrand uses a global rand object seeded by system time with mutex protection to generate random number in a concurrent-safe manner.

Proposed Solution

I propose replacing rand object+mutex with math/rand package's top-level functions to boost performance and to simplify the code in grpcrand.

Pros & Cons

Pros

go version >=1.21.0

  • Significantly faster execution when generating random number, especially for parallel calls (up to 30x speedup)
  • Simplified implementation

go version < 1.21.0

  • Simplified implementation

Cons

go version >=1.21.0

  • Currently, there are no apparent drawbacks I can think of

1.20.0 <= go version < 1.21.0

  • In my computer in non parallel case, occasionally top-level function ran much slower(rand.Intn) than rand object+mutex, but the results are not stable. (up to ~20% slower, usually below 10%)

go version <1.20.0

  • Top-level functions will produce a deterministic sequence of values each time a program is run
  • In my computer in non parallel case, occasionally top-level function ran much slower(rand.Intn) than rand object +mutex, but the results are not stable.(up to ~20% slower, usually below 10%)

Using top-level functions will simplify the implementation of grpcrand and significantly improve grpcrand's performance(go version>=1.21.0), the downside is the potential performance degradation when using go version below 1.21.0.
As for deterministic sequence of values when using go version below 1.20.0, I think it would not cause a security problem, because if grpcrand is used for secure PRNG, implementation should use crypto/rand instead of math/rand, but it might lead to other issues that I haven't considered.

Conclusion

Since grpc-go only supports the three latest major versions of go, even if we opt to continue using rand object + mutex for now, as go releases number bumping up, the cons will gradually disappear. At that point, using math/rand's top-level functions to generate random numbers will be a highly favorable choice.

Metadata

Metadata

Assignees

Labels

Type: PerformancePerformance improvements (CPU, network, memory, etc)

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions