首页 > 数据库 > 数据库开发技术 > 高并发流量的一些思考
所谓的大流量,我们可能会想到TPS(每秒事务数),QPS(每秒请求量),5000+,10000+,50000+....当然没有一个具体的数据,其实这么说吧,对你的系统造成了压力,影响了系统的性能,这个对于你的系统就叫做大流量。
那么应对大流量的手段有哪些呢?
万变不离其中:让数据尽早进入缓存,离程序近一点,不要频繁的访问DB。
下面就跟我们的RPC基本高级特征有关了。
降级:如果不是核心的作用,就把这个功能降级掉。比如说,我们做推荐系统,千人千面拿到数据后,做个性化排序,如果在大流量下,这个排序的功能就完全可以省去。
限流:这个我们就见得很多了,在现实生活中,在南京的地铁早高峰的时候,一段时间放一批人,这就是限流。说白了,就是在一定的时间段里面,保证系统不被击垮,同时还要尽量的保证系统的吞吐量。
有些比较特别的场景,很出名的就是双十一了,用户的购买,下单都是比较核心的功能,涉及到大量的读写,不能做降级,只能通过限流来保证系统的健壮性。
当然限流有很多种:计数器、滑动窗口、漏桶、令牌。
我今天就聊下令牌桶:
漏桶的出水速度是恒定的,意味着如果瞬时有大流量的话,将有大部分的请求被过滤掉,也就是说溢出。

生成令牌的速度是恒定的,去拿令牌的速度是没有限制的。如果有大量的请求过来的话,该算法可以让你快速拿到令牌,而且拿到令牌的过程不会内耗太大。这个中间虽然会过滤掉不少的正常请求,但是相比于系统的崩溃,还是值得去操作的。
限流神器:Guava RateLimiter(google出品 必属精品!鄙视facebook)
大家可以自行去google下。
这是典型的令牌桶算法,我们只需要告诉RateLimiter系统限制的QPS是多少,那么他就按这个速度往桶里放入令牌,然后请求的时候 调用tryAcquire()方法向RateLimiter获取许可。
那么分布式环境下的限流怎么做呢?
比如Nginx+Lua、Redis+Lua去实现。
以下是一个使用Nginx和Lua实现基于令牌桶算法的简单示例
lua_shared_dict limit_req_store 10m;# 定义限流逻辑的Lua脚本lua_package_path "/path/to/your/lua/scripts/?.lua;;";lua_code_cache on;# 定义限流处理逻辑limit_req_zone $binary_remote_addr zone=per_ip:10m rate=10r/s;server {# 其他 Nginx 配置项...location /limited-endpoint {# 使用Lua脚本实现限流逻辑access_by_lua_block {local limit = require "resty.limit.req"local lim, err = limit.new("per_ip", 10, 10)if not lim thenngx.log(ngx.ERR, "failed to instantiate a resty.limit.req object: ", err)return ngx.exit(500)endlocal key = ngx.var.binary_remote_addrlocal delay, err = lim:incoming(key, true)if not delay thenif err == "rejected" thenngx.status = 503ngx.say("Rate limit exceeded")ngx.exit(ngx.status)endngx.log(ngx.ERR, "failed to limit req: ", err)return ngx.exit(500)end}# 此处是你的应用逻辑proxy_pass http://your_upstream_server;}# 其他 location 配置...}
在这个例子中,lua_shared_dict用于在Nginx worker进程之间共享限流状态信息。limit_req_zone指令创建一个共享内存区域,用于存储限流相关的信息。access_by_lua_block指令使用Lua脚本实现了限流逻辑,其中使用了resty.limit.req库来处理基于令牌桶算法的限流。
这个例子中的限流是基于客户端IP地址的,每秒允许的请求数是10个。如果超过这个限制,请求将会收到503状态码作为响应,并显示"Rate limit exceeded"消息。
总结:
让系统的流量先去队列中排队、限流,不要讲流量直接打到系统上,这是关键。
原文作者:二进制跳动;如有侵权,请联系管理员删除。