buckettoken令牌桶算法是网络流量整形(TrafficShaping)和速率限制(RateLimiting)中最常使用的一种算法。 图片来源于网络 首先我们有一个bucket,里面存放了n个token,每次当有一个网络请求时,我们发一个token,当这个请求结束时,我们再将其token收回放入bucket中。这样我们的请求数量就不会同时超过桶内的token的数量。 可能有人想,我们创建一个数组来维护这个token也可以实现吧。但是在go语言中,我们对于每一个请求都是在一个单独的协程中处理的,所以当有并发时,这个数组就不好维护了。当然,我们可以加锁,但是可想而知,这个系统的性能必然下降。而且在go语言中,我们提倡的是使用channel来处理并发,所以我们将这个算法使用channel来处理是很理想的。也就是通过共享通道而不是用共享内存来解决。 今天我们先实现一个总的连接数量的限制的简单实现: packagemainimport"fmt"typeLimiterstruct{contintbucketchanint}funcNewConnLimiter(ccint)*Limiter{returnLimiter{cont:cc,bucket:make(chanint,cc),//bufferchannel}}func(cl*Limiter)GetToken(idint)bool{iflen(cl.bucket)=cl.cont{fmt.Println("超过限制")returnfalse}cl.bucket-idreturntrue}func(cl*Limiter)ReleaseToken(){c:=-cl.bucketfmt.Println(c)}funcmain(){c:=NewConnLimiter(5)r:=c.GetToken(1)fmt.Println("获取token结果:",r)fori:=0;i5;i++{r:=c.GetToken(i)fmt.Println("获取token结果:",r)}c.ReleaseToken()} 这个代码是非常简单的,目的就是,在有一个连接时,我们就给他一个token,当他结束时,在释放这个token。我们看一下上面代码的运行结果: 运行结果 我们可以看到,开始时我们设置桶的数量为5,也就是最多有5个请求可以连接,当有一个token被释放之后,又可以有新的连接了。但是现在这个代码有一个缺点,就是总的连接数是固定的,有时我们需要的是在一段时间内,请求数量不能超过最大的值,这是我们就需要设置一个timer,在这段时间内,我们来判断token的数量,而且超过时间我们自动释放token就可以了。这个代码不再这里演示了,希望感兴趣的同学回去手动试一下,学习语言最好的方法就是动手。我之前也说过,我这里写的都是简单的实现,如果大家项目中有用到,就需要随机应变,但是基本思路都是类似的。活学活用很主要。 后续会有更多的模式和算法以及区块链相关的,如果你是想学习go语言或者是对设计模式或者算法感兴趣亦或是区块链开发工作者,都可以北京市中科医院北京中科白殿疯
|