随机字符串函数的性能优化经历

从⼀个简单功能说起

⽣成随机字符串

某平台提供系统函数,可以⽣成随机字符串,⽤于构造Http/gRPC请求,包括请求参数、请求头、请求体等多个地⽅。

示例:name=${sysRandom.randomAlphaNumeric(32)}

实现1.0

 

What’s Next?

实现有什么问题吗?

 

What’s Next?

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

实现2.0

 

What’s Next?

实现有什么问题吗?

What’s Next?

  1. 按1024字节计算,构造100万次请求需要~23秒,平均每秒可以构造4.3万个随机字符串
  2. 按单机每秒2万QPS计算,平均每秒有50%的时间耗费在构造随机字符串上

实现3.0

What’s Next?

实现有什么问题吗?

What’s Next?

  1. StringBuilder中使⽤char[],默认⻓度16,会重复扩容、拷⻉

实现4.0

What’s Next?

实现有什么问题吗?

What’s Next?

  1. 既然使⽤了char[],为什么还使⽤StringBuilder?

实现5.0

What’s Next?

实现有什么问题吗?

What’s Next?

  1. current()⽅法调⽤是不是耗时操作?

实现6.0

What’s Next?

实现有什么问题吗?

What’s Next?

  1. new String(char[]),需要进⾏数组拷⻉

实现7.0

 

 What’s Next?

实现有什么问题吗?

⼩结1

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

⼩结2

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

⼩结3

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

⼩结4

4.ThreadLocalRandom.current() 千万不要抽取变量!!!!!!!

使⽤初始化线程⽣成随机种⼦,抽取变量导致多个线程使⽤相同的seed

 

实现8.0

  1. 考虑对业务场景的要求,不需要每个字符那么随机
  2. 改为⽣成⼀次随机数,使⽤多次

⼩结5

  1. 伪随机
    1. 相同种⼦,⽣成的随机数字序列完全相同

 

 2、算法

  1.线性同余:简单、快,RandSeed = (A * RandSeed + B) % M

  2.梅森旋转:⽬前最好的算法之⼀

3、性能:

  多线程,使⽤CAS更新种⼦的值==>ThreadLocalRandom

4、安全性:

  不⽀持加密安全性==>SecureRandom

最后的⼩结

  1. 魔⻤在细节中
    1. 优秀的代码都是⼀个个⼩细节扣出来
    2. JDK、第三⽅类库中很多代码没有经过性能优化,有很多的性能问题
posted @ 2021-02-07 23:00  xxqing  阅读(137)  评论(0)    收藏  举报