随机字符串函数的性能优化经历
从⼀个简单功能说起
⽣成随机字符串
某平台提供系统函数,可以⽣成随机字符串,⽤于构造Http/gRPC请求,包括请求参数、请求头、请求体等多个地⽅。
示例:name=${sysRandom.randomAlphaNumeric(32)}
实现1.0

What’s Next?
实现有什么问题吗?


What’s Next?
1. 有同学使⽤该函数,构造⻓度为100K的字符串,导致多个线程被阻塞,压⼒上不去
实现2.0

What’s Next?
实现有什么问题吗?

What’s Next?
- 按1024字节计算,构造100万次请求需要~23秒,平均每秒可以构造4.3万个随机字符串
- 按单机每秒2万QPS计算,平均每秒有50%的时间耗费在构造随机字符串上
实现3.0

What’s Next?
实现有什么问题吗?
What’s Next?
- StringBuilder中使⽤char[],默认⻓度16,会重复扩容、拷⻉
实现4.0

What’s Next?
实现有什么问题吗?

What’s Next?
- 既然使⽤了char[],为什么还使⽤StringBuilder?
实现5.0

What’s Next?
实现有什么问题吗?

What’s Next?
- current()⽅法调⽤是不是耗时操作?
实现6.0

What’s Next?
实现有什么问题吗?

What’s Next?
- new String(char[]),需要进⾏数组拷⻉
实现7.0

What’s Next?
实现有什么问题吗?
⼩结1

- ⽅案5、6、7的百万次调⽤都在3.x秒,⽐RandomStringUtils/StringBuilder好很多
⼩结2

2.根据⽕焰图,随机函数的nextInt()占⽤了64.86%的耗时,说明随机函数是瓶颈
⼩结3

3.反射并不⽐数组拷⻉更耗时

⼩结4
4.ThreadLocalRandom.current() 千万不要抽取变量!!!!!!!
使⽤初始化线程⽣成随机种⼦,抽取变量导致多个线程使⽤相同的seed

实现8.0

- 考虑对业务场景的要求,不需要每个字符那么随机
- 改为⽣成⼀次随机数,使⽤多次
⼩结5
- 伪随机
- 相同种⼦,⽣成的随机数字序列完全相同

2、算法
1.线性同余:简单、快,RandSeed = (A * RandSeed + B) % M
2.梅森旋转:⽬前最好的算法之⼀
3、性能:
多线程,使⽤CAS更新种⼦的值==>ThreadLocalRandom
4、安全性:
不⽀持加密安全性==>SecureRandom

最后的⼩结
- 魔⻤在细节中
- 优秀的代码都是⼀个个⼩细节扣出来
- JDK、第三⽅类库中很多代码没有经过性能优化,有很多的性能问题

浙公网安备 33010602011771号