老胡也摆摆了摇头,“这中档的距离还是甚充分之,田宇的案件里,田宇是死于快卡胺中毒,而快卡胺片剂的深浅大高,只要几切片溶于水中,就能够落得致死的含量。可是星舒2不同,为了有利于服用,它的片剂里还带有了零星的面、糖份,以及其它维生素和矿物质等。你考虑看,如果拿一百大多片星舒2溶解在和里,水会变成什么样的含意?恐怕正常人是喝不下的。”

那哪些是的来化解者的问题也?我们好由此模拟对话级别的信号量当下同样手法,这也就是咱们今天的主题了。
   什么是信号量?仅就因为代码而言,  static
SemaphoreSlim semaphoreSlim = new SemaphoreSlim(5); 
它的意思就是表示以差不多线程情况下,在其它一样整日,只能同时5独线程去看。

第九章    1

 

落得官宁眼睛一样亮,抢先说道:“他应是当田宇的爱妻,和田宇的爱侣于齐。”

现今,因为种种因素,你要对一个呼吁或措施进行频率达到的造访限制。
按,
你对外提供了一个API接口,注册用户每秒钟最多足调用100潮,非注册用户每秒钟最多好调用10不良。
随,
有一个怪吃服务器资源的方,在同等时刻不克跳10私家调用这个法,否则服务器满载。
遵照, 有有特殊的页面,访客并无可知屡屡之拜访还是发言。
仍, 秒杀活动相当展开。

,防范DDOS,当上自然频率后调用脚本iis服务器ip黑名单,防火墙黑名单。
若达到种的比方,也就是说,如何由一个断面的角度对调用的章程进行频率上之限。而对效率限制,服务器层面还发出无比直白的解决方式,现在自说的则是代码层面上之效率管控。

“不可能!”老胡斩钉截铁地商议,“通常用于医疗治疗的星舒2制剂,它的行含量其实是格外没有之,每片只含几微克而已,远不足以对身体造成伤害。除非他一次性吞食上百片,除非是痛下决心自杀,否则,不可能出现服用过量的气象。另外,我查看了外的医记录,并没有抑郁症的治记录。而从不医生的处方的话,他是买入不顶这种药物的。”

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   }

夏乐听到这里,忽然插话道:“除非,凶手会拿药片中的星舒2提纯出来?”

分布式下Redis

上面介绍了相同种植频率限制的模型,分布式与单机相比,无非就是是载体不同,我们要拿此容器的载体从程序及移植出来,来干成一个单身的劳务或直接借用Redis也是有效的。

这边就介绍分布式情况下,Redis的实现。

差为Asp.Net的多线程模型,大概为Redis的各种类型的因素非常粒度的操作造成各种加锁之繁杂,所以于网要处理这块Redis是单线程的,基于Redis的落实则以单线程的案由在编码角度不用太多着想到同逻辑无关之问题。

  简单介绍下,Redis是一个内存数据库,这个数据库属于非关系型数据库,它的定义不同于一般的我们体会的Mysql
Oracle
SqlServer关系型数据库,它没有Sql没有字段名无表名这些概念,它同HttpRunTime.Cache的定义差不多一样,首先从操作及属于键值对模式,就使
Cache[“键名”]
这样虽可知取得到价值类似,而且可以本着每个Key设置过策略,而Redis中之Key所对应的价并无是眷恋存啥就存啥的,它支持五种植多少类:string(字符串),hash(哈希),list(列表),set(集合)及sorted
set(有序聚集)。

今要说之凡Sorted
set有序聚集,有序聚集相比其它的成团类型的非常点在于,使用有序聚集的时节还能够叫插入的元素指定一个
积分score,我们管此积分score理解为扫除序列,它其中会针对积分进行排序,积分允许再次,而一成不变聚集中的元素虽然是绝无仅有。

  还是同的思绪,每当有用户访问的时刻,都针对该用户之
管道(有序聚集)中上加一个元素,然后设置该因素的积分也目前时光。接着在程序中开始单线程,来对管道被积分小于约定时间的元素进行清理。因为规定有序聚集中之素只能是唯一值,所以于赋值方面只要是满足uuid即可。

 科学 1

那么因此Redis来落实之代码那就是接近这种:

科学 2

通过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的实例来兑现。最后放上功能图。

科学 3

说到底,我拿这些都于做成了单Demo。但是没有找到适当的上传网盘,所以大家好留给邮箱(留了即发),或者直接加QQ群文件自取,讨论交流:166843154

 

本人好同我同一的食指交朋友,不深受环境影响,自己是温馨之先生,欢迎加群
.Net web交流群, QQ群:166843154 欲望跟挣扎

 

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

高达官宁瞪圆了双眼,“这么说,他是生病有抑郁症,死为超用药?“

为率先独API接口需求也例,先说下单机环境下的实现。
准惯性思维,我们当然会想到缓存的过期策略这种办法,但是严格来讲就是HttpRuntime.Cache而言,通过缓存的晚点策略来针对要进行频率之面世控制是不合适的。
  HttpRuntime.Cache
是应用程序级别的Asp.Net的苏存技术,通过是技能可以说明多单缓存对象,可以吗每个对象设置过时,当过岁月到达晚该缓存对象就会见没有(也不怕是当你拜访该目标的时段也Null)

“从他尸体表面的动静来拘禁,死去相应都一个大抵小时候,”说着,老胡看了一晃工夫,“现在凡上午11沾,应该就是坏为10点之前。”

 科学 4

“如果他是异常给10点事先的话,那他中毒的时光应当是9点之前。那个时刻……”

  为什么这样说呢?比如对准某方法(方法名:GetUserList)我们只要拓展1秒钟最多10软的限,现在咱们虽新建一个int型的Cache对象,然后设置1秒钟后过消失。那么在访问GetUserList方法前,我们就是先行判断这Cache对象的值是否高于10,如果超过10即使不实行GetUserList方法,如果低于10虽允许实施。每当访问该对象的下要未设有或者过就新建,这样循环,则该对象永远不可能跨越10。

从来不当老胡说,夏乐就拿话茬儿接了过去,“星舒2是一律种很有效的对抗抑郁药物,但是,如果用过量的话,会针对心肌产生一定之不成作用,严重的言语,直接促成猝死。”

 

“这个因人而异,要拘留他自家对这种药之耐受度。但常见状态下,一个小时左右咔嚓。”

比方达到图,每个点代表一律不行走访请求,我在0秒的下
新建了一个名也GetUserListNum的缓存对象。
在0~0.5秒中
我访问了3涂鸦,在0.5~1秒里,我们看了7次等。此时,该对象消失,然后我们跟着访问,该目标重置为0.
              
 在第1~1.5秒里,还是看了7次,在第1.5秒~2秒中访了3软。

老胡点点头,“对。不过,这得肯定之化学知识,普通人是举行不至的。”

正文为来片只示范,一个是基于单机环境之落实,第二单则是冲分布式的Redis实现

啊之,她查看了很多材料,科学家等就此赤诚的口吻,还有形形色色的的数额证明:浮之城的动力系统内置了多法保障方案,并且具有紧密的预警系统,就算出啊问题,也会被及时发现并得到妥善处理,所以,根本管需担心。但是,颜苏还忍不住想:万一呢,万一意外产生在科学家等从不想到的地方吧?她虽然想象不至会出什么意外,但是,正以想象不交,所以才是意外啊!

基于这种概括缓存过期策略的范,在及时2秒钟内,我们虽然平均每秒钟都看了10次于,满足这个规定,但是如果我们于中取一个之间段,0.5秒~1.5秒里,也是1秒钟,但是也实实在在的造访了14破!远远超越了我们安的
1秒钟最多看10赖的 限制。

上一节

 

成星离开后,颜苏一个人口因为在沙发上,眼睛向在无声的房间,又发起了呆。在其眼里,人生了就是平摆无穷无尽的厄,反正未来的归属一定是物化,那在在还有呀含义为??然而,可忧伤的是,人既然没有不吃百般下来的即兴,也不曾随心所欲地死去的人身自由,然后在每日的生存之中对形形色色的怕,各种无处不在的畏惧,比如:有一致上,悬浮之城去了动力,掉下来怎么处置?

4容器4线程模型

今天,在实现代码的之前我们先行筹一个模子。

科学 5

  假设我们出一个用户A的管道,这个管道里装在用户A的伸手,比如用户A在平等秒钟发出了10坏呼吁,那么每一个告过来,管道里之素都见面多一个。但是我们设定是管道最多只能容10只元素,而且每个元素的存活期为1秒,1秒后则该因素消失。那么这么设计吧,无论是速率还是多少之突进,都见面时有发生管道长度的界定。这样一来,无论由哪一个岁月节点还是时间距离出发,这个管道都能满足我们的频率限制需求。

要是这边的管道,就亟须与会话Id来对号入座了。每当有新会话进来的时段即便死成一个新管道。这个会话id根据自己场景所定,可以是sessionId,可以是ip,也得以是token。

那么既这管道是会说话级别之,我们终将得用一个器皿,来装这些管道。现在,我们盖IP来定名会话管道,并拿所有的管道还装在一个容器中,如图

科学 6

如若根据刚才之设定,我们还需要针对容器内之每条管道的元素进行拍卖,把过的为抹掉,为这个,还得独自为该容器开辟出一个线程来吧每条管道展开元素的清理。而当管道的因素呢0时,我们就算到底掉该管道,以便节省容器空间。

 科学 7

自然,由于用户量基本上,一个容器内或有上万独管道,这个时段只是用一个容器来装来清理,在效率上醒目是不够的。这个时刻,我们就是得对容器进行横向扩张了。

  比如,我们可依据Cpu核心数自动生成对应的数量的器皿,然后因一个算法,对IP来开展导流。我时cpu是4独逻辑核心,就杀成了4单容器,每当用户访问的时光,都见面首先经过一个算法,这个算法会对IP进行拍卖,如192.168.1.11~192.168.1.13是Ip段进第一单容器,xxx~xxx进第二独容器,依次类推,相应的,也即来了4单线程去分别处理4只容器中的管道。

科学 8

 

那,最终便形成了俺们的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:较ReaderWriterLock优化的朗诵写锁,多个线程同时做客读锁
或  一个线程访问写锁

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的。

 科学 9科学 10

经检查,成星死让心脏骤停,也就算是“猝死”。老胡同开始怀疑他随身患有某种严重的心血管病,但吃他的下手胖子调来田宇历年之体检和诊治记录同一看,却发现他的人一直还非常正常,毫无重大疾病之征象。


若果被颜苏整日里烦恼不堪的,还不仅仅是这些。她似乎有超乎寻常的感受力。天空下雨的时节,她会客毫无来由地想到自己吃了伤走在街道上,伤口为雨水浇得疼痛;外面炎热的时光,她会客想到自己的腿被疯狗咬伤,伤口暴露于高温中,烧心一般的疼痛;站在镜子前,她会客设想发生团结年迈的典范,满脸的斑点以及褶皱让好拘留起如一个童话里的女巫;想起自己之老人,她见面莫名其妙地想到出一样上自己以飞杀去,然后,便起为借想蒙老人之可悲而心酸不止……

这么的考虑及落实相对来说非常简单,但是因这样的一个型设定,那么尽管会见出现这种情况:

下一节

这叫他不禁有些迷惑。于是,他开拓随身的检测箱,从成星的异物及抽取了某些血液样本,注射到快速化验皿中,没喽会儿,化验结果就是出了。在成星的血中,星舒2的含量严重超标,

对它底猜疑,田宇就建议她搬到地面世界去生活。到了本土上,踏踏实实的,总不至于再不见下来了吧。然而,田宇话音刚落,她便以皱起了眉头,“万一地面上地震怎么处置?万一地面上爆发洪水怎么处置?如果悬浮的都而奔掉的言辞,科学家们恐怕还能帮忙上啊忙。可地震为,她圈罢有关的视频资料,只需要几秒的年华,一整个山村就从来不了,人们连反应的年月还不会见生出;洪水也是,一夜之间,就会管同所都化为海底世界,在本来的能力面前,科学简直就是婴幼儿般的留存。”她的语句说罢,田宇没有词了,只好任由它们闷闷不乐地胡思乱想。

回目录

兹,她盖在沙发里,又突然担心打成星来,他未会见吧遇到什么意外吧。想到这里,颜苏忽然觉得一阵恶心,心口突突直跳,自己之嗓子也像是给卡住了相似,呼吸也艰苦起来。她时而脑瘫倒在沙发上,浑身冒着冷汗,哆嗦着,从沙发上滚动到了地上,一动不动地睡了马拉松,腹部一环抱,一抹寒潮从胃部涌上喉间,“呃”的如出一辙声于了单嗝儿,这才渐渐睁开了眼睛,看了圈四周,一边眼里滴着眼泪,一边从地上起来,走至橱边打开一个斗,取出一个标志着“星舒2”的药瓶,从里倒有点儿颗在掌心上,然后以倒了一致杯子水,一仰脖,就正在回,将两片药吞了下去。然后,她一面擦在泪,一边活动上前卧室,往床上一致倒,便放声大哭起来。

“一个时,”夏乐口里就念叨了相同句,紧接着问道,“那他的逝世时,大概是呀时候?”


“什么意思?”上官宁听了老胡的话,连忙问道。

“所以,这同时是同台下毒案件?”上官宁睁大的肉眼长期且不曾合上,她扭头看了拘留夏乐,见夏乐为是瞪着简单只眼,咬在嘴唇,便同时说道:“看起,成星的可怜,和田宇的可怜,凶手的作案手法很相似啊,只不过用的药物不同。”

等等等等,数不穷的堵与忧困扰着它们,让它的活处处洋溢了灰色。而田宇的死,则是给其底各种顾虑变成了平等栽具体。她难以忍受对协调之样胡思乱想更笃信起来,并经过激发了其底重新多想象。比如,她吗会见如丈夫那样,被人下毒;或者,自己一个人口当舍时,因为操作不慎,导致有电器引发火警……于是,有成百上千潮,她想到了轻生。然而,这也并无是桩容易的事,万一自杀不化,自己的处境更加痛苦怎么收拾?

哭着哭着,声音暂停,颜苏睡着了。

“那照成星体内的星舒2的含量,从服下到已故,大约得多长时间?”夏乐以问道。