Nacos 限流最佳实践

    技术2022-07-10  147

    Nacos 限流最佳实践

    Nacos自开源以来,版本迭代速度很快,已经发布了0.9版本,准备发1.0的正式版本,支持企业使用Nacos生产高可用。在生产环境,Nacos首先需要保证自身服务的稳定性,在正常的运行环境下不会出现服务挂掉的情况。当然在一些依赖的系统出问题的时候(比如磁盘和DB),Nacos服务会受到影响,需要监控系统发现这些问题并能及时的介入处理。

    作为高性能的服务发现和配置管理服务,Nacos也是存在自己的性能基线的,当瞬时的高峰流量超过自身的性能基线的时候,需要对高峰流量进行限流,以保证整体服务的健康运行而不影响到其他核心应用。

    Tomcat 限流

    Nacos基于spring boot使用内嵌的tomcat,tomcat线程分为acceptor线程和worker线程,acceptor线程负责从内核accept队列中取出连接并交给worker线程,而worker线程则负责处理连接(读取参数、执行处理、返回响应等)

    acceptCount

    当tomcat不能及时处理新的连接时,内核中新建的连接将会进入连接队列排队,acceptCount参数能够设置tomcat accept连接队列大小,当新的连接数超过acceptCount则拒绝连接,立即返回给client,不会让client一直等待造成响应很慢或超时

    maxConnections

    接受了的连接需要由worker线程调度处理,当worker线程处理的连接数越来越多时,处理的速度会越来越慢造成client响应时间变长,需要根据系统和机器情况设置合理的maxConnections,当连接数到达maxConnections时,不再接受新的连接,让新连接排队等待,超出队列长度则直接拒绝。

    maxThreads

    maxThreads参数设置tomcat的最大线程数,过高的线程数会让系统运行的负载过高、响应变慢,过低的线程数让系统的资源利用率太低,需要根据实际的运行情况(CPU、IO等)设置合理的最大线程数。

    Nginx 限流

    tomcat限流只能做到自身负载的调节,在实际生产环境中还远远不够,需要依赖Nacos自身的限流来提高系统的限流能力。

    Nacos的open API都是基于http协议,可以很方便地使用nginx来做限流,不需要自身再开发限流模块来支持各种限流策略。nginx的基本使用以及nginx+lua模块安装网上资源很丰富,这里就不再介绍。

    Nacos每个接口执行的代价不尽相同,一般来说写操作代价比读操作大,与此同时还有高频操作和低频操作之分,SDK调用的接口一般来说是高频接口,容易出现问题,所以在生产环境需要将这些接口区别对待,根据服务自身的实际情况采取合理的限流策略,以防错用方打垮Nacos服务。下面介绍一下Nacos在生产环境的几种限流场景

    限制访问速率

    1、限制单个接口的请求QPS

    limit_get_config对读操作进行限流,正常使用Nacos获取动态配置一般就启动和运行时修改配置推送到client,获取配置相对来说是低频操作,如果频繁获取配置肯定是client有错用或者应用不正常(比如数据平台任务failover重试任务)

    limit_req_zone $limit_key zone=limit_get_config:10m rate=10r/s; server { listen 8080; server_name localhost; location /nacos/v1/cs/configs { if ($request_method = POST ) { rewrite ^ /limit_publish_config_url last; } rewrite ^ /limit_get_config_url last; } location /limit_get_config_url { set $limit_key "$remote_addr+$arg_dataid+$arg_group+$arg_tenant"; limit_req zone=limit_get_config burst=10 nodelay; proxy_pass http://127.0.0.1:8848/nacos/v1/cs/configs; } } limit_req_zone设置限流key和内存大小,以及请求速率limit_key由[ip,dataId,group,tenant]四元组组成,可以防止client错用频繁访问单个配置burst设置漏桶算法的桶的大小nodelay设置非延迟模式,如果桶满了则会马上返回给客户端错误码proxy_pass指定后端Nacos的接口url

    limit_publish_config对写操作进行限流,可以有效防止热点写问题。对同一个数据的高频写会触发mysql的行锁,从而导致mysql的多线程任务因等待行锁排队,最终导致mysql所有操作都超时服务不可用。这里通过nginx lua模块获取post请求的参数,设置limit_key

    limit_req_zone $limit_key zone=limit_publish_config:10m rate=5r/s; location /limit_publish_config_url { set $dataId $arg_dataid; set $group $arg_group; set $tenant $arg_tenant; set $limit_key "$remote_addr+$dataId+$group+$tenant"; lua_need_request_body on; rewrite_by_lua ' ngx.req.read_body() local post_args = ngx.req.get_post_args() if post_args["dataId"] then ngx.var.dataId = post_args["dataId"]; ngx.var.group = post_args["group"]; ngx.var.tenant = post_args["tenant"]; ngx.var.limit_key = ngx.var.remote_addr.."+"..ngx.var.dataId.."+"..ngx.var.group; if ngx.var.tenant then ngx.var.limit_key = ngx.var.limit_key.."+"..ngx.var.tenant; end end '; limit_req zone=limit_publish_config burst=10 nodelay; proxy_pass http://127.0.0.1:8848/nacos/v1/cs/configs; } lua_need_request_body on;用于读取post请求的request bodyrewrite_by_lua指令在http rewrite阶段执行lua代码

    2、限制单机访问QPS

    perclient对单个client的所有请求限制低于500QPS,可以有效防止单台client的重试攻击

    limit_req_zone $remote_addr zone=perclient:10m rate=500r/s; server { listen 8080; server_name localhost; limit_req zone=perclient burst=250 nodelay; location / { proxy_pass http://127.0.0.1:8848/nacos/v1/cs/configs; } }

    3、限制 Nacos 服务 QPS

    perserver限制整个Nacos服务的QPS,Nacos的服务部署在nginx之后,nginx可以保证到达Nacos的流量不会打垮Nacos

    limit_req zone=perserver burst=1000 nodelay;

    限制并发连接数

    /nacos/v1/cs/configs/listener接口是Nacos的长连接通道,一般来说,一个client一个长连接就可以满足生产需求。limit_conn_client限制client的连接数不超过10个,limit_conn_server限制Nacos单机(8核16G内存)支撑最多9000个长连接,最多可以同时服务9000个应用节点

    limit_conn_zone $remote_addr zone=limit_conn_client:10m; limit_conn_zone $server_name zone=limit_conn_server:10m; server { listen 8080; server_name localhost; location = /nacos/v1/cs/configs/listener { limit_conn limit_conn_client 10; limit_conn limit_conn_server 9000; proxy_pass http://127.0.0.1:7001/diamond-server/config.co; tcp_nodelay on; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }

    黑名单

    1、IP黑名单

    当生产环境发现有错用的client影响到Nacos服务,可以使用nginx黑名单限制client的访问

    deny 30.5.125.70;

    从被限制的IP访问Nacos 

    curl -X GET "http://{IP}:8080/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test" -i

    Nginx返回403状态码给client,禁止client访问 

    HTTP/1.1 403 Forbidden Server: nginx/1.13.5 Date: Fri, 15 Mar 2019 08:34:33 GMT Content-Type: text/html Content-Length: 169 Connection: keep-alive <html> <head><title>403 Forbidden</title></head> <body bgcolor="white"> <center><h1>403 Forbidden</h1></center> <hr><center>nginx/1.13.5</center> </body> </html>

    2、读写黑名单分离

    有时候通过IP维度直接限制client访问所有Nacos接口粒度过大,会导致应用服务不可用,可以将读操作和写操作分开,禁止client写Nacos,依然允许其进行读

    # 1 limit read, 0 no limit map "$remote_addr" $limit_read { #10.2.24.252 1; default 0; } # 1 limit write, 0 no limit map "$remote_addr" $limit_write { #10.2.24.252 1; default 0; } location /some_url_to_write { if ($limit_write = 1) { return 403; } } map指令匹配remote_addr变量,如果$remote_addr变量在ip黑名单里面,则设置limit_read和limit_write参数为1,否则为0在写接口中对limit_write做判断,如果禁写则返回403状态码

    3、应用黑名单

    IP黑名单功能是nginx提供的基础能力,能够限制某些IP的访问,但是一般一个应用会有很多台机器,当一个应用出问题的时候,会有很多IP访问都有问题,通过IP的维度来限制访问达不到预期,需要有应用的维度来限制

    namespace(命名空间)是一个可以区分不同应用的维度,不同的应用一般会使用不同的namespace,这样可以在namespace维度对服务的访问进行限制

    map "$arg_tenant" $limit_namespace { af884cf8-1719-4e07-a1e1-3c4c105ab237 1; #a6c745b7-fd92-4c1d-be99-6dc98abfe3dc 1; default 0; } location /some_url { if ($limit_namespace = 1) { return 403; } }

    通过匹配namespace是否在黑名单中来设置limit_namespace变量,然后在访问的url中判断limit_namespace的值,如果为1返回403状态码

    ak维度:使用一个ak代表一个应用,不同的应用在启动的时候设置不同的ak。client在发起请求的时候会带上ak参数到server端,在nginx层对请求的参数进行解析,对特定的应用的ak进行访问限制

    map "$http_Spas_AccessKey" $limit_ak { 6839c164bb344cdc93107f08eda8a136 1; default 0; } location /some_url { if ($limit_ak = 1) { return 403; } }

    总结

    本文简单介绍了Nacos在实际生产环境中如何通过限流来提高自身服务的稳定性,除了自身设置tomcat参数,还可以通过高性能的nginx作为前端对流量进行过滤提高限流能力。文中难免会有个别错误或者遗漏,如果大家有更多的限流或者提高稳定性的办法可以在Nacos官网提出来。

    Processed: 0.016, SQL: 9