.Net 怎么着模拟会话级另外信号量澳门美高梅手机网站,对http接口调用频率举行限制(有demo)

现在,因为各个因素,你不可以不对一个呼吁或者措施举行频率上的走访限制。
譬如说,
你对外提供了一个API接口,注册用户每秒钟最多可以调用100次,非注册用户每分钟最多可以调用10次。
比如说,
有一个百般吃服务器资源的点子,在相同时刻无法超过10私家调用这些点子,否则服务器满载。
诸如, 有一部分奇特的页面,访客并不可能屡屡的造访或发言。
例如, 秒杀活动等举行。
譬如
,防范DDOS,当达到一定频率后调用脚本iis服务器ip黑名单,防火墙黑名单。
如上各个的比方,也就是说,怎样从一个断面的角度对调用的艺术开展频率上的界定。而对效用限制,服务器层面都有最直白的缓解形式,现在我说的则是代码层面上的频率管控。

本篇是一个Node新手做完实际项目后的体验总计。Node高手完全可以略过本文。

本文给出五个示范,一个是依照单机环境的实现,第二个则是据悉分布式的Redis实现

java码农.png


摘要

万一BOSS要求您在长时间内飞速实现一套聊天云服务平台, 你的第一影响是怎么样?

让自己细细一想实现本钱:

要珍贵社交关系, 一大波僵尸POJO正在向你袭来。
要存储数据库, 找个ORM工具这是必须的。
您怎么也得用长连接吧?好, 这就WebSocket标准吗,
Netty或Mina系的亲外甥框架选一个呗。什么?!你只用过Tomcat写WebSocoket?好啊,乖乖翻文档API去吧亲。
完事了?没呢! 连接断了你得实现下重连机制吗?服务器端写完了,
客户端呢?你得帮助指点下实现吗?
本猿的大脑一片黑暗。

以第一个API接口需求为例,先说下单机环境下的贯彻。
按照惯性思维,我们当然会想到缓存的晚点策略这种艺术,不过严酷来讲就HttpRuntime.Cache而言,通过缓存的过期策略来对请求举办频率的面世控制是不合适的。
  HttpRuntime.Cache
是应用程序级其它Asp.Net的缓存技术,通过这么些技能可以注解两个缓存对象,可以为每个对象设置过期时间,当过期时光到达后该缓存对象就会流失(也就是当您拜访该目的的时候为Null)

我们的征程是偷懒

比方有现成的轮子偷个懒岂不是很好?google后意识有个socket.io的车轮比较适合:

轻量级, 扩充便捷, API简单易用。
广阔完善,重连、路由、隔离、单播、广播等等都早就帮大家落实好了。
增长的客户端帮忙,涵盖了浏览器端, ANDROID, iOS。
在条分缕析研读了Flexi传授什么说服自己的业主采取Node.js,并打响说服BOSS后,本猿正式开班和气的Node之旅。

  为何如此说吧?比如对某个方法(方法名:GetUserList)我们要开展1分钟最多10次的限量,现在大家就新建一个int型的Cache对象,然后设置1分钟后过期消失。那么每当访问GetUserList方法前,我们就先判断这些Cache对象的值是否高于10,倘诺领先10就不举办GetUserList方法,假若低于10则允许实施。每当访问该对象的时候倘若不设有或者逾期就新建,这样循环,则该目标永远不容许超过10。

工欲善其事必先利其器

1   if ((int)HttpRuntime.Cache["GetUserListNum"] > 10) //大于10请求失败
2   {
3      Console.WriteLine("禁止请求");
4   }
5   else
6   {
7      HttpRuntime.Cache["GetUserListNum"] = (int)HttpRuntime.Cache["GetUserListNum"] + 1; //否则该缓存对象的值+1
8      Console.WriteLine("允许请求");
9   }

支付环境

对于开发条件, 青菜萝卜各有所爱, 无论你是使用神的编辑器/编辑器之神,
或是sublime/atom/npp之流, 亦或是WebStorm高富帅有钱任性,
都是很不错的抉择。
supervisor是个好东西,
它可以帮您watch代码变更, 自动重启服务。节省了手工重启程序的光阴。

如此的盘算及实现相对来说非常简单,可是按照这样的一个模型设定,那么就会面世这种景观:

关于调试

  • 高富帅款: WebStorm
  • 高逼格款: 原始打断点
  • 屌丝款:
    node-inspector,
    可以在Chrome中间接调试, 强烈推荐:

1.png

 澳门美高梅手机网站 1

离不开的中间件

先是, 勾勒出一个为主的拉扯系统大致的雏形:

 

基本功用

  • 登录,注销
  • 在线,离线等意况维护

如上图,每个点代表四遍访问请求,我在0秒的时候
新建了一个名字为GetUserListNum的缓存对象。
在0~0.5秒之内
我访问了3次,在0.5~1秒之内,大家走访了7次。此时,该目的消失,然后我们跟着访问,该对象重置为0.
              
 在第1~1.5秒之内,依旧访问了7次,在第1.5秒~2秒之内做客了3次。

好友

  • 加好友,删好友
  • 知音之间聊天,发文字发图片发音频发录像啥的

基于这种简单缓存过期策略的模子,在这2分钟内,我们尽管平均每分钟都访问了10次,知足这多少个确定,然则一旦大家从中取一个之间段,0.5秒~1.5秒之内,也是1秒钟,不过却的确的造访了14次!远远超过了大家设置的
1分钟最多访问10次的 限制。

群组

  • 创立,插足,退出群组
  • 群组内播放聊天

 

闲谈历史记录

那么哪些正确的来化解地点的问题啊?我们得以因此模拟对话级另外信号量这一招数,这也就是我们明天的核心了。
   什么是信号量?仅就以代码而言,  static
SemaphoreSlim semaphoreSlim = new SemaphoreSlim(5); 
它的意味就代表在多线程意况下,在此外一每天,只好同时5个线程去访问。

恢宏与普遍

  • 集群实现
  • 敏感词过滤

分析下大约需要的存储层和中间件以及是否有有关的Node实现:

  • MySQL: 存储一些至关重要的元数据, 主假使用户关系类的,
    需要工作扶助。(node-mysql)
  • ZooKeeper: 用户在线离线状态存储。 (node-zookeeper-client)
  • Redis: 使用缓存加速一些询问, PubSub特性用于落实集群通讯。 (ioredis)
  • HBase: 典型的列式存储, 用于实现部分非大旨数据的全速囤积查询。
    (hbase-rpc-client)
  • LevelDB: 本地快速读写一些键值对。(LevelUP)

 

技术栈

4容器4线程模型

现今,在贯彻代码的从前大家先规划一个模子。

澳门美高梅手机网站 2

  即便大家有一个用户A的管道,那些管道里装着用户A的乞求,比如用户A在一分钟发出了10次呼吁,那么每一个呼吁过来,管道里的要素都会多一个。但是我们设定这一个管道最六只可以容纳10个因素,而且每个元素的存活期为1秒,1秒后则该因素消失。那么如此设计的话,无论是速率如故多少的突进,都会有管道长度的界定。这样一来,无论从哪一个时刻节点依旧时间间隔出发,这多少个管道都能知足大家的频率限制需求。

而这边的管道,就务须和会话Id来对号入座了。每当有新会话进来的时候就生成一个新管道。这一个会话id按照自己场景所定,可以是sessionId,可以是ip,也足以是token。

这就是说既然这些管道是会话级其它,我们必将得需要一个容器,来装这个管道。现在,大家以IP来命名会话管道,并把持有的管道都装载在一个容器中,如图

澳门美高梅手机网站 3

而基于刚才的设定,我们还亟需对容器内的每条管道的因素举办处理,把过期的给删除掉,为此,还索要单独为该容器开辟出一个线程来为每条管道举办元素的清理。而当管道的因素为0时,大家就清掉该管道,以便节省容器空间。

 澳门美高梅手机网站 4

理所当然,由于用户量多,一个器皿内或许存在上万个管道,这几个时候只是用一个器皿来装载来清理,在成效上旗帜彰着是不够的。那一个时候,大家就得对容器举办横向扩展了。

  比如,我们得以按照Cpu主旨数自动生成对应的数码的器皿,然后按照一个算法,对IP来开展导流。我当下cpu是4个逻辑大旨,就生成了4个容器,每当用户访问的时候,都会起先经过一个算法,那个算法会对IP举行拍卖,如192.168.1.11~192.168.1.13这多少个Ip段进第一个容器,xxx~xxx进第二个容器,依次类推,相应的,也就有了4个线程去分别处理4个容器中的管道。

澳门美高梅手机网站 5

 

这就是说,最后就形成了俺们的4容器4线程模型了。

如今,着眼于编码实现:

  首先我们需要一个能承载这多少个器皿的载体,这一个载体类似于连接池的概念,可以依据一些需要自动生成适应数量的器皿,假若有特殊要求的话,还足以在容器上切出一个器皿管理的面,在线程上切出一个线程管理的面以便于实时监督和调度。假使真要做这么一个系统,那么
容器的调度 和 线程的调度功用是必备的,而本Demo则是成就了重点意义,像容器和线程在代码中我也没剥离开来,算法也是直接写死的,实际设计中,对算法的规划仍然很要紧的,还有多线程模型中,怎么样上锁才能让效能最大化也是最重要的。

而这里为了案例的直观就直接写死成4个容器。

public static List<Container> ContainerList = new List<Container>(); //容器载体
static Factory()
{
     for (int i = 0; i < 4; i++)
     {
        ContainerList.Add(new Container(i));  //遍历4次  生成4个容器
     }
     foreach (var item in ContainerList)
     {
        item.Run();    //开启线程
     }
}

前几日,咱们只要 有编号为 0 到 40 这样的 41个用户。那么这么些导流算法
我也就直接写死,编号0至9的用户
将他们的伸手给抛转到第一个容器,编号10~19的用户
放到第二个容器,编号20~29放到第两个容器,编号30~40的用户放到第三个容器。

这就是说这么些代码就是这样的:

 static Container GetContainer(int userId, out int i) //获取容器的算法
 {
     if (0 <= userId && userId < 10)    //编号0至9的用户  返回第一个容器  依次类推
     {
          i = 0;
          return ContainerList[0];
     }
     if (10 <= userId && userId < 20)
     {
          i = 1;
          return ContainerList[1];
     }
     if (20 <= userId && userId < 30)
     {
          i = 2;
          return ContainerList[2];
      }
      i = 3;
      return ContainerList[3];
  }

当我们的对话请求经过算法的导流之后,都必须调用一个方法,用于辨别管道数量。假若管道数量一度超越10,则请求失利,否则成功

  public static void Add(int userId)
  {
       if (GetContainer(userId, out int i).Add(userId))
            Console.WriteLine("容器" + i + " 用户" + userId + "  发起请求");
       else
            Console.WriteLine("容器" + i + " 用户" + userId + "  被拦截");
  }

接下去就是容器Container的代码了。

此处,对容器的选型用线程安全的ConcurrentDictionary类。
  线程安全:当三个线程同时读写同一个共享元素的时候,就会产出数量错乱,迭代报错等安全问提
  ConcurrentDictionary:除了GetOrAdd方法要慎用外,是.Net4.0专为解决Dictionary线程安全而出的新品类
  ReaderWriterLockSlim:较里德(Reade)rWriterLock优化的读写锁,五个线程同时做客读锁
或  一个线程访问写锁

private ReaderWriterLockSlim obj = new ReaderWriterLockSlim();  //在每个容器中申明一个读写锁
public ConcurrentDictionary<string, ConcurrentList<DateTime>> dic = new ConcurrentDictionary<string, ConcurrentList<DateTime>>(); //创建该容器 dic

然后当你向容器添加一条管道中的数据是经过那么些法子:

 public bool Add(int userId)
 {
     obj.EnterReadLock();//挂读锁,允许多个线程同时写入该方法
     try
     {
         ConcurrentList<DateTime> dtList = dic.GetOrAdd(userId.ToString(), new ConcurrentList<DateTime>()); //如果不存在就新建 ConcurrentList
         return dtList.CounterAdd(10, DateTime.Now); //管道容量10,当临界管道容量后 返回false
     }
     finally
     {
         obj.ExitReadLock();
     }
 }

 这里,为了在后头的线程遍历删除ConcurrentList的管道的时候保证ConcurrentList的安全性,所以这边要加读锁。

 而ConcurrentList,因为.Net没有推出List集合类的线程安全(count和add加锁),所以自己新建了一个延续于List<T>的平安项目,在这里
封装了3个需要运用的章程。

public class ConcurrentList<T> : List<T>
{
    private object obj = new object();

    public bool CounterAdd(int num, T value)
    {
        lock (obj)
        {
            if (base.Count >= num)
                return false;
            else
                base.Add(value);
            return true;
        }
    }
    public new bool Remove(T value)
    {
        lock (obj)
        {
            base.Remove(value);
            return true;
        }
    }
    public new T[] ToArray() 
    {
        lock (obj)
        {
            return base.ToArray();
        }
    }
}

末尾就是线程的周转形式:

 public void Run()
 {
     ThreadPool.QueueUserWorkItem(c =>
     {
         while (true)
         {
             if (dic.Count > 0)
             {
                 foreach (var item in dic.ToArray())
                 {
                     ConcurrentList<DateTime> list = item.Value;
                     foreach (DateTime dt in list.ToArray())   
                     {
                         if (DateTime.Now.AddSeconds(-3) > dt)
                         {
                             list.Remove(dt);
                             Console.WriteLine("容器" + seat + " 已删除用户" + item.Key + "管道中的一条数据");
                         }
                     }
                     if (list.Count == 0)
                     {
                         obj.EnterWriteLock();
                         try
                         {
                             if (list.Count == 0)
                             {
                                 if (dic.TryRemove(item.Key, out ConcurrentList<DateTime> i))
                                 { Console.WriteLine("容器" + seat + " 已清除用户" + item.Key + "的List管道"); }
                             }
                         }
                         finally
                         {
                             obj.ExitWriteLock();
                         }
                     }
                 }

             }
             else
             {
                 Thread.Sleep(100);
             }
         }
     }
   );
 }

最后,是意义图,一个是基于控制台的,还一个是按照Signalr的。

 澳门美高梅手机网站 6澳门美高梅手机网站 7

对比

常年滋润在JAVA这片润土之上, 先来做个相比较, 让我们对陌生的技艺栈有所精晓。

描述 JAVA Node 备注
依赖管理 maven npm
RESTFUL的Web框架 Vert.x expressjs
WebSocket实现 基于Netty实现 socket.io
ORM Hibernate/MyBatis/jOOQ sequelize 本篇未使用, 本猿觉得动态类型的语言没太大必要使用ORM
异步编程风格 rxjava promise

分布式下Redis

地点介绍了一种频率限制的模型,分布式与单机相比较,无非就是载体不同,我们只要把这多少个容器的载体从程序上移植出来,来弄成一个独门的劳动仍旧直接借用Redis也是实用的。

此地就介绍分布式意况下,Redis的贯彻。

不同于Asp.Net的多线程模型,大概因为Redis的各类类型的元素异常粒度的操作造成各个加锁的复杂,所以在网络请求处理这块Redis是单线程的,基于Redis的兑现则因为单线程的原故在编码角度不用太多考虑到与逻辑无关的题材。

  简单介绍下,Redis是一个内存数据库,这么些数据库属于非关系型数据库,它的概念不同于一般的我们体会的Mysql
Oracle
SqlServer关系型数据库,它从未Sql没有字段名尚未表名这多少个概念,它和HttpRun提姆(Tim)e.Cache的概念差不多一样,首先从操作上属于键值对格局,就如
Cache[“键名”]
这样就能得到到值类似,而且可以对各种Key设置过期策略,而Redis中的Key所对应的值并不是想存啥就存啥的,它帮忙五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及sorted
set(有序聚集)。

前几天要说的是Sorted
set有序聚集,有序聚集相相比另外的集结类型的特殊点在于,使用有序聚集的时候还可以给插入的元素指定一个
积分score,大家把这一个积分score了然为排系列,它其中会对积分举办排序,积分允许再度,而一成不变聚集中的元素则是唯一。

  仍然一如既往的思绪,每当有用户访问的时候,都对该用户的
管道(有序聚集)中添加一个因素,然后设置该因素的积分为近年来时光。接着在先后中开个线程,来对管道中积分小于约定时间的因素举办清理。因为规定有序聚集中的元素只可以是唯一值,所以在赋值方面倘诺是满意uuid即可。

 澳门美高梅手机网站 8

这就是说用Redis来兑现的代码这就是相仿这种:

澳门美高梅手机网站 9

透过using语法糖实现IDisposable而卷入的Redis分布式锁,然后里面正常的逻辑判断。

这么的代码即使也能形成功能,但不够自己。Redis是个基于内存的数据库,于性能而言,瓶颈在于网络
IO 上,与Get一次暴发四次呼吁相比较,能不可能因而一段脚本来实现多数逻辑吗?

有的,Redis支持 Lua脚本:
  Lua
是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放,
其设计目标是为着放置应用程序中,从而为应用程序提供灵活的扩张和定制效率。
  大致意思就是,直接向Redis发送一段脚本或者让它一直本地读取一段脚本从而平素实现所有的逻辑。

/// <summary>
/// 如果 大于10(AccountNum) 就返回1   否则就增加一条集合中的元素 并返回 空
/// </summary>
/// <param name="zcardKey"></param>
/// <param name="score"></param>
/// <param name="zcardValue"></param>
/// <param name="AccountNum"></param>
/// <returns></returns>
public string LuaAddAccoundSorted(string zcardKey, double score, string zcardValue, int AccountNum)
{
    string str = "local uu = redis.call('zcard',@zcardKey) if (uu >=tonumber(@AccountNum)) then return 1 else redis.call('zadd',@zcardKey,@score,@zcardValue)  end";
    var re = _instance.GetDatabase(_num).ScriptEvaluate(LuaScript.Prepare(str), new { zcardKey = zcardKey, score = score, zcardValue = zcardValue, AccountNum=AccountNum });
    return re.ToString();
}

local
uu就是发明一个为名uu的变量的意味,redis.call就是redis命令,这段脚本意思就是假诺大于10(AccountNum) 就回来1   否则就扩张一条集合中的元素 并赶回 空。

管道内元素处理的主意就是:

 /// <summary>
 /// 遍历当前所有前缀的有序集合,如果数量为0,那么就返回1 否则 就删除 满足最大分值条件区间的元素,如果该集合个数为0则消失
 /// </summary>
 /// <param name="zcardPrefix"></param>
 /// <param name="score"></param>
 /// <returns></returns>
public string LuaForeachRemove(string zcardPrefix, double score)
 {
     StringBuilder str = new StringBuilder();
     str.Append("local uu = redis.call('keys',@zcardPrefix) "); //声明一个变量 去获取 模糊查询的结果集合
     str.Append("if(#uu==0) then");    //如果集合长度=0
     str.Append("   return 1 ");
     str.Append("else ");
     str.Append("   for i=1,#uu do ");   //遍历
     str.Append("       redis.call('ZREMRANGEBYSCORE',uu[i],0,@score) ");  //删除从0 到 该score 积分区间的元素
     str.Append("       if(redis.call('zcard',uu[i])==0) then ");  //如果管道长度=0
     str.Append("           redis.call('del',uu[i]) ");   //删除
     str.Append("       end ");
     str.Append("   end ");
     str.Append("end ");
     var re = _instance.GetDatabase(_num).ScriptEvaluate(LuaScript.Prepare(str.ToString()), new { zcardPrefix = zcardPrefix + "*", score = score });
     return re.ToString();

这2段代码通过发送Lua脚本的款式来形成了方方面面过程,因为Redis的网络模型原因,所以把LuaForeachRemove方法给提议来做个服务来单独处理即可。至于这种多容器多线程的兑现,则一心可以开三个Redis的实例来落实。最终放上效果图。

澳门美高梅手机网站 10

最终,我把这么些都给做成了个Demo。不过并未找到适当的上传网盘,所以我们能够留邮箱(留了就发),或者直接加QQ群文件自取,探究沟通:166843154

 

自家爱不释手和自家同样的人交朋友,不被环境影响,自己是协调的老师,欢迎加群
.Net web交流群, QQ群:166843154 欲望与挣扎

 

作者:小曾
出处:http://www.cnblogs.com/1996V/p/8127576.html 欢迎转载,但任何转载必须保留完整文章及博客园出处,在显要地方显示署名以及原文链接。
.Net交流群, QQ群:166843154 欲望与挣扎 

ES6

ES6是个好东西, 我觉着比较好用的三点:

const: 终于得以便宜地对不可变的事物举办宣示了。
let: 作为一只 javascript 菜鸟再也不用担忧不知不觉把变量提高的题材了。
lambda表明式: 神器不表明。

主干实现

流程时序

细心揣摩, 勾勒出大约的时序图:

2.png

时序图

系统架构:

规划下大约的架构:

3.png

架构图

步步为赢, 各种击破

情形管理

特出的 IM 系统中自然存在用户在线离线的情形。每一个在线状态,
对于服务器来说,等价于与客户端存在一个Socket连接。所以对于单机环境下,在内存中体贴用户和Socket的关联即可,当Socket连接和断开时分别做立异操作。

当切换至集群环境时,意况变得稍微复杂,所以我们需要看重zookeeper来实现。除了本机每个用户与Socket关联关系,其余以临时节点的主意在zookeeper中举办仓储,目录结构为根节点/命名空间/用户标识/Socket标识(临时节点)。
当socket连接被确立的时候,创设对应的临时节点,socket断开时移除临时节点。
当服务器意外退出时,除了socket连接一切断开之外,在其zookeeper
session上的有着对应的暂时节点也会被销毁。SocketIO
的重连机制会尝试重连至此外伺服器比量齐观复确立起对应提到。

优点:

  • 认清一个用户是否在线只需判断用户标识节点的numChildren是否超越零即可。
  • 取得用户拥有已连接的Socket只需读取用户标识下的持有孩子节点即可。

缺点:

  • 多了附加读写zookeeper的开发。

用途:

  • 心想事成集群的底子
  • 有了动静判定才能实现离线消息推送

好友关系、群组关系

提到表原本存储于HBase, 但因为缺乏工作补助,实际效果不好,
平日造成关系不相同。传统关系型数据库在这一端依然强势。这块相比简单,即常见的关联模型表,在此略过。

点对点聊天实现

单机

A对B发送信息,除了基础的权位判定,只需询问内存表中对应B的享有socket,然后对其发出消息即可。见下图:

4.png

集群

由于B可能登录在不同的服务器上,需要依靠消息中间件(Redis
Pub/Sub),发布信息,每个服务器订阅音信列表,如若存在消息接收者,则找到其登记在本机的socket举办发射音信。流程如下图:

5.png

播音聊天实现

播音类似上述的点对点落实,只是多了一步查询成员表依次处理的步子。略过。

闲谈历史记录的实现

考虑到只需要依据时间限定做分页查询的简便需求,这里运用了 HBase 的宽表。
点对点花样的闲谈大家可以对三个用户标识举行排序,并结成命名空间变化唯一的哈希值,作为行健,而各个CELL的值则是光阴戳,
因为大家需要令其本来倒序排列,
所以针对时间戳做了LONG.MAX-时间戳的拍卖。综合起来, 大致的贮存结构如下:

敏感词过滤

维护脏词字典,对信息举办字符串替换?图样图森破!!!
为了落实科学识别“曹孟德在运动场操美丽的女子”中的动词“操”,需要贯彻闽南语分词和词性判断,
于是拍卖逻辑转变成:

  • 拉取最新的脏词列表,转换为简体闽南语并写入LevelDB中。
  • 利用nodejieba举行粤语分词: 武国君(n)/在(p)/操场(n)/操(v)/漂亮的女孩子(n)
  • 对分词后的名词和动词转换为简体闽南语并查询LevelDB,命中则替换。
  • 回到替换后的字符串拿到:曹孟德在运动场*美女

包装部署

PM2

Node本身是单线程的,尽管Node本身提供Cluster模块,但需要修改代码。通过PM2这个工具得以方便地让其多进程部署,充分利用多核CPU资源:

6.png

pm2

Docker
可以使用官方的node镜像。但体积相比较大,这里推荐基于alpine-node,
体积相比较娇小, 例如:

FROM mhart/alpine-node:4

RUN apk add --no-cache make gcc g++ python

RUN apk add --no-cache imagemagick

WORKDIR /src
ADD . .
RUN npm install --registry=http://registry.npm.taobao.org/

EXPOSE 3000
CMD ["npm","start"]

C1000K测试

老牌的单机100万总是, 由于品种是首个本子,
限于各方面原因我们临时髦未完成这些测试。

但在此地大概介绍所需的有些配备, 以备后续使用:

劳务器端

修改tcp连接的微小内存为4k, 编辑/etc/sysctl.conf

    net.ipv4.tcp_wmem = 4096 87380 4161536
    net.ipv4.tcp_rmem = 4096 87380 4161536
    net.ipv4.tcp_mem = 786432 2097152 3145728

修改系统最大文件描述符, 编辑/etc/sysctl.conf

    fs.file-max = 1000000

修改过程最大文件描述符, 编辑/etc/security/limits.conf

*         hard    nofile      1000000
*         soft    nofile      1000000
root      hard    nofile      1000000
root      soft    nofile      1000000
    ```
重载下配置(sysctl -p)或者重启,检查下当前的设置 cat /proc/sys/fs/file-nr


##客户端

 - 因为每个IP最多可以创建6万多个连接,不可能找很多服务器进行测试。所以客户端除了上述修改,还需要创建多个虚拟IP,这样每个IP可以提供大约6万的连接,如:
```javascript
     ifconfig eth0:0 192.168.77.10 netmask 255.255.255.0 up
     ifconfig eth0:1 192.168.77.11 netmask 255.255.255.0 up
     ifconfig eth0:2 192.168.77.12 netmask 255.255.255.0 up
     ifconfig eth0:3 192.168.77.13 netmask 255.255.255.0 up
     ifconfig eth0:4 192.168.77.14 netmask 255.255.255.0 up
     ifconfig eth0:5 192.168.77.15 netmask 255.255.255.0 up
     ifconfig eth0:6 192.168.77.16 netmask 255.255.255.0 up
     ifconfig eth0:7 192.168.77.17 netmask 255.255.255.0 up
     ifconfig eth0:8 192.168.77.18 netmask 255.255.255.0 up
     ifconfig eth0:9 192.168.77.19 netmask 255.255.255.0 up
     ifconfig eth0:10 192.168.77.20 netmask 255.255.255.0 up
     ifconfig eth0:11 192.168.77.21 netmask 255.255.255.0 up
     ifconfig eth0:12 192.168.77.22 netmask 255.255.255.0 up
     ifconfig eth0:13 192.168.77.23 netmask 255.255.255.0 up
     ifconfig eth0:14 192.168.77.24 netmask 255.255.255.0 up
     ifconfig eth0:15 192.168.77.25 netmask 255.255.255.0 up
     ifconfig eth0:16 192.168.77.26 netmask 255.255.255.0 up
     ifconfig eth0:17 192.168.77.27 netmask 255.255.255.0 up
     ifconfig eth0:18 192.168.77.28 netmask 255.255.255.0 up
  • 修改本地端口范围,编辑/etc/sysctl.conf

    net.ipv4.ip_local_port_range = 1024 65535
  • 重载配置或重启先河测试

总结

  • 留存即成立,不要卷入无谓的语言之争,本猿觉得干这行的最着重莫过于学习能力。
  • 写代码往日先理清楚思路和协会,不打没有备选的仗。
  • 卓绝的代码规范,服从KISS原则。

正文作者来自 马克斯(Max)Leap 团队_多少解析组 成员:蔡伟伟
原文链接

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注