聊聊高并发系统之限流特技(二)(转)

上一篇《聊聊高并发系统限流特技-1》讲了限流算法、应用级限流、分布式限流;本篇将介绍接入层限流实现。

接入层限流

接入层通常指请求流量的入口,该层的主要目的有:负载均衡、非法请求过滤、请求聚合、缓存、降级、限流、 A/B 测试、服务质量监控等等,可以参考笔者写的《 使用 Nginx+Lua(OpenResty) 开发高性能 Web 应用 》。

对于 Nginx 接入层限流可以使用 Nginx 自带了两个模块:连接数限流模块 ngx_http_limit_conn_module 和漏桶算法实现的请求限流模块 ngx_http_limit_req_module 。还可以使用 OpenResty 提供的 Lua 限流模块 lua-resty-limit-traffic 进行更复杂的限流场景。

limit_conn 用来对某个 KEY 对应的总的网络连接数进行限流,可以按照如 IP 、域名维度进行限流。 limit_req 用来对某个 KEY 对应的请求的平均速率进行限流,并有两种用法:平滑模式( delay )和允许突发模式 (nodelay) 。

ngx_http_limit_conn_module

limit_conn 是对某个 KEY 对应的总的网络连接数进行限流。可以按照 IP 来限制 IP 维度的总连接数,或者按照服务域名来限制某个域名的总连接数。但是记住不是每一个请求连接都会被计数器统计,只有那些被 Nginx 处理的且已经读取了整个请求头的请求连接才会被计数器统计。

配置示例:

================================

http {

limit_conn_zone$binary_remote_addr zone=addr:10m;
limit_conn_log_level error;
limit_conn_status 503;

...

server {

...

location /limit {

limit_conn addr 1;

}

================================

limit_conn :要配置存放 KEY 和计数器的共享内存区域和指定 KEY 的最大连接数;此处指定的最大连接数是 1 ,表示 Nginx 最多同时并发处理 1 个连接;

limit_conn_zone :用来配置限流 KEY 、及存放 KEY 对应信息的共享内存区域大小;此处的 KEY 是“ $binary_remote_addr ”其表示 IP 地址,也可以使用如 $server_name 作为 KEY 来限制域名级别的最大连接数;

limit_conn_status :配置被限流后返回的状态码,默认返回 503 ;

limit_conn_log_level :配置记录被限流后的日志级别,默认 error 级别。

limit_conn 的主要执行过程如下所示:

1 、请求进入后首先判断当前 limit_conn_zone 中相应 KEY 的连接数是否超出了配置的最大连接数;

2.1 、如果超过了配置的最大大小,则被限流,返回 limit_conn_status 定义的错误状态码;

2.2 、否则相应 KEY 的连接数加 1 ,并注册请求处理完成的回调函数;

3 、进行请求处理;

4 、在结束请求阶段会调用注册的回调函数对相应 KEY 的连接数减 1 。

limt_conn 可以限流某个 KEY 的总并发 / 请求数, KEY 可以根据需要变化。

按照 IP 限制并发连接数配置示例:

首先定义 IP 维度的限流区域:

================================

limit_conn_zone $binary_remote_addrzone=perip:10m;

================================

接着在要限流的 location 中添加限流逻辑:

================================

location /limit {

limit_conn perip 2;

echo "123";

}

================================

即允许每个 IP 最大并发连接数为 2 。

使用 AB 测试工具进行测试,并发数为 5 个,总的请求数为 5 个:

================================

ab -n 5 -c 5 http://localhost/limit

================================

将得到如下 access.log 输出:

================================

[08/Jun/2016:20:10:51+0800] [1465373451.802] 200

[08/Jun/2016:20:10:51+0800] [1465373451.803] 200

[08/Jun/2016:20:10:51 +0800][1465373451.803] 503

[08/Jun/2016:20:10:51 +0800][1465373451.803] 503

[08/Jun/2016:20:10:51 +0800][1465373451.803] 503

================================

此处我们把 access log 格式设置为 log_format main  '[$time_local] [$msec] $status' ;分别是“日期 日期秒 / 毫秒值 响应状态码”。

如果被限流了,则在 error.log 中会看到类似如下的内容:

================================

2016/06/08 20:10:51 [error] 5662#0: *5limiting connections by zone "perip", client: 127.0.0.1, server: _,request: "GET /limit HTTP/1.0", host: "localhost"

================================

按照域名限制并发连接数配置示例:

首先定义域名维度的限流区域 :

================================

limit_conn_zone $ server_name zone=perserver:10m;

===========

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这是一个关于 Java 编程的问题。我可以为您解答。 请看以下 Java 代码实现动物演员的相关内容: ```java class AnimalPlayer { private int number; // 编号 private String name; // 名字 private int age; // 年龄 public AnimalPlayer(int number, String name, int age) { this.number = number; this.name = name; this.age = age; } public void drive() { System.out.println("Oh, " + name + " is driving."); } public void rollBall() { System.out.println("Oh, " + name + " is rolling the ball."); } public void bugle() { System.out.println("Oh, " + name + " is blowing the bugle."); } public void stunt() { System.out.println("Oh, " + name + " is performing a special stunt."); } } class Monkey extends AnimalPlayer { public Monkey(int number, String name, int age) { super(number, name, age); } @Override public void stunt() { System.out.println("Oh, " + getName() + " is swinging from the trapeze."); } } class Dog extends AnimalPlayer { public Dog(int number, String name, int age) { super(number, name, age); } @Override public void stunt() { System.out.println("Oh, " + getName() + " is jumping through a hoop."); } } class Bear extends AnimalPlayer { public Bear(int number, String name, int age) { super(number, name, age); } @Override public void stunt() { System.out.println("Oh, " + getName() + " is balancing on a ball."); } } class Panda extends AnimalPlayer { public Panda(int number, String name, int age) { super(number, name, age); } @Override public void stunt() { System.out.println("Oh, " + getName() + " is eating bamboo while balancing on a seesaw."); } } public class AnimalPlayerDemo { public static void main(String[] args) { AnimalPlayer monkey = new Monkey(1, "Jerry", 3); AnimalPlayer dog = new Dog(2, "Sparky", 5); AnimalPlayer bear = new Bear(3, "Teddy", 4); AnimalPlayer panda = new Panda(4, "Bao Bao", 2); perform(monkey); perform(dog); perform(bear); perform(panda); } public static void perform(AnimalPlayer ap) { ap.drive(); ap.rollBall(); ap.bugle(); ap.stunt(); System.out.println(""); } } ``` 以上代码定义了一个 AnimalPlayer 类和四个继承自该类的类:Monkey、Dog、Bear、Panda。每个类都有自己的 stunt 特技表演。 在 `AnimalPlayerDemo` 类中,创建了四个动物实例,每个动物实例都进行表演。`perform` 方法接收一个 AnimalPlayer 类型的参数,并依次执行骑车、滚球、吹号和特技表演,并输出相关信息。 比如执行 `monkey.drive()` 的结果会输出:"Oh, Jerry is driving."。 希望能帮到您!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值