当前位置: 首页 > news >正文

怎么电话销售网站建设wordpress相对路径

怎么电话销售网站建设,wordpress相对路径,上海手机网站建设哪家专业,做花馍网站现在#xff0c;因为种种因素#xff0c;你必须对一个请求或者方法进行频率上的访问限制。 比如#xff0c; 你对外提供了一个API接口#xff0c;注册用户每秒钟最多可以调用100次#xff0c;非注册用户每秒钟最多可以调用10次。比如#xff0c; 有一个非常吃服务器资源的… 现在因为种种因素你必须对一个请求或者方法进行频率上的访问限制。 比如 你对外提供了一个API接口注册用户每秒钟最多可以调用100次非注册用户每秒钟最多可以调用10次。比如 有一个非常吃服务器资源的方法在同一时刻不能超过10个人调用这个方法否则服务器满载。比如 有一些特殊的页面访客并不能频繁的访问或发言。比如 秒杀活动等进行。比如 防范DDOS当达到一定频率后调用脚本iis服务器ip黑名单防火墙黑名单。如上种种的举例也就是说如何从一个切面的角度对调用的方法进行频率上的限制。而对频率限制服务器层面都有最直接的解决方法现在我说的则是代码层面上的频率管控。本文给出两个示例一个是基于单机环境的实现第二个则是基于分布式的Redis实现。--------------------以第一个API接口需求为例先说下单机环境下的实现。按照惯性思维我们自然会想到缓存的过期策略这种方法但是严格来讲就HttpRuntime.Cache而言通过缓存的过期策略来对请求进行频率的并发控制是不合适的。  HttpRuntime.Cache 是应用程序级别的Asp.Net的缓存技术通过这个技术可以申明多个缓存对象可以为每个对象设置过期时间当过期时间到达后该缓存对象就会消失(也就是当你访问该对象的时候为Null)  为什么这样说呢比如对某个方法方法名GetUserList我们要进行1秒钟最多10次的限制现在我们就新建一个int型的Cache对象然后设置1秒钟后过期消失。那么每当访问GetUserList方法前我们就先判断这个Cache对象的值是否大于10如果大于10就不执行GetUserList方法如果小于10则允许执行。每当访问该对象的时候如果不存在或者过期就新建这样周而复始则该对象永远不可能超过10。if ((int)HttpRuntime.Cache[GetUserListNum] 10) //大于10请求失败  {     Console.WriteLine(禁止请求);  }  else  {     HttpRuntime.Cache[GetUserListNum] (int)HttpRuntime.Cache[GetUserListNum] 1; //否则该缓存对象的值1     Console.WriteLine(允许请求);  }这样的思想及实现相对来说非常简单但是基于这样的一个模型设定那么就会出现这种情况  如上图每个点代表一次访问请求我在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个线程去访问。 4容器4线程模型现在在实现代码的之前我们先设计一个模型。  假设我们有一个用户A的管道这个管道里装着用户A的请求比如用户A在一秒钟发出了10次请求那么每一个请求过来管道里的元素都会多一个。但是我们设定这个管道最多只能容纳10个元素而且每个元素的存活期为1秒1秒后则该元素消失。那么这样设计的话无论是速率还是数量的突进都会有管道长度的限制。这样一来无论从哪一个时间节点或者时间间隔出发这个管道都能满足我们的频率限制需求。而这里的管道就必须和会话Id来对应了。每当有新会话进来的时候就生成一个新管道。这个会话id根据自己场景所定可以是sessionId可以是ip也可以是token。那么既然这个管道是会话级别的我们肯定得需要一个容器来装这些管道。现在我们以IP来命名会话管道并把所有的管道都装载在一个容器中如图而基于刚才的设定我们还需要对容器内的每条管道的元素进行处理把过期的给剔除掉为此还需要单独为该容器开辟出一个线程来为每条管道进行元素的清理。而当管道的元素为0时我们就清掉该管道以便节省容器空间。 当然由于用户量多一个容器内可能存在上万个管道这个时候仅仅用一个容器来装载来清理在效率上显然是不够的。这个时候我们就得对容器进行横向扩展了。  比如我们可以根据Cpu核心数自动生成对应的数量的容器然后根据一个算法对IP来进行导流。我当前cpu是4个逻辑核心就生成了4个容器每当用户访问的时候都会最先经过一个算法这个算法会对IP进行处理如192.168.1.11~192.168.1.13这个Ip段进第一个容器xxx~xxx进第二个容器依次类推相应的也就有了4个线程去分别处理4个容器中的管道。 那么最终就形成了我们的4容器4线程模型了。现在着眼于编码实现  首先我们需要一个能承载这些容器的载体这个载体类似于连接池的概念可以根据一些需要自动生成适应数量的容器如果有特殊要求的话还可以在容器上切出一个容器管理的面在线程上切出一个线程管理的面以便于实时监控和调度。如果真要做这样一个系统那么 容器的调度 和 线程的调度功能 是必不可少的而本Demo则是完成了主要功能像容器和线程在代码中我也没剥离开来算法也是直接写死的实际设计中对算法的设计还是很重要的还有多线程模型中怎样上锁才能让效率最大化也是重中之重的。而这里为了案例的直观就直接写死成4个容器。public static ListContainer ContainerList new ListContainer(); //容器载体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 ConcurrentDictionarystring, ConcurrentListDateTime dic new ConcurrentDictionarystring, ConcurrentListDateTime(); //创建该容器 dic然后当你向容器添加一条管道中的数据是通过这个方法public bool Add(int userId) {     obj.EnterReadLock();//挂读锁允许多个线程同时写入该方法     try     {         ConcurrentListDateTime dtList dic.GetOrAdd(userId.ToString(), new ConcurrentListDateTime()); //如果不存在就新建 ConcurrentList         return dtList.CounterAdd(10, DateTime.Now); //管道容量10当临界管道容量后 返回false     }     finally     {         obj.ExitReadLock();     } } 这里为了在后面的线程遍历删除ConcurrentList的管道的时候保证ConcurrentList的安全性所以此处要加读锁。 而ConcurrentList因为.Net没有推出List集合类的线程安全(count和add加锁)所以自己新建了一个继承于ListT的安全类型在这里 封装了3个需要使用的方法。public class ConcurrentListT : ListT{    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())                 {                     ConcurrentListDateTime 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 ConcurrentListDateTime i))                                 { Console.WriteLine(容器 seat 已清除用户 item.Key 的List管道); }                             }                         }                         finally                         {                             obj.ExitWriteLock();                         }                     }                 }             }             else             {                 Thread.Sleep(100);             }         }     }   ); }最后是效果图一个是基于控制台的还一个是基于Signalr的。 分布式下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即可。 那么用Redis来实现的代码那就是类似这种通过using语法糖实现IDisposable而包装的Redis分布式锁然后里面正常的逻辑判断。这样的代码虽然也能完成功能但不够友好。Redis是个基于内存的数据库于性能而言瓶颈在于网络 IO 上与Get一次发出一次请求相比能不能通过一段脚本来实现大部分逻辑呢有的Redis支持 Lua脚本  Lua 是一种轻量小巧的脚本语言用标准C语言编写并以源代码形式开放 其设计目的是为了嵌入应用程序中从而为应用程序提供灵活的扩展和定制功能。  大致意思就是直接向Redis发送一段脚本或者让它直接本地读取一段脚本从而直接实现所有的逻辑。/// summary/// 如果 大于10(AccountNum) 就返回1   否则就增加一条集合中的元素 并返回 空/// /summary/// param namezcardKey/param/// param namescore/param/// param namezcardValue/param/// param nameAccountNum/param/// returns/returnspublic 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, AccountNumAccountNum });    return re.ToString();}ocal uu就是申明一个为名uu的变量的意思redis.call就是redis命令这段脚本意思就是如果 大于10(AccountNum) 就返回1   否则就增加一条集合中的元素 并返回 空。管道内元素处理的方法就是/// summary /// 遍历当前所有前缀的有序集合如果数量为0那么就返回1 否则 就删除 满足最大分值条件区间的元素如果该集合个数为0则消失 /// /summary /// param namezcardPrefix/param /// param namescore/param /// returns/returnspublic string LuaForeachRemove(string zcardPrefix, double score) {     StringBuilder str new StringBuilder();     str.Append(local uu redis.call(keys,zcardPrefix) ); //声明一个变量 去获取 模糊查询的结果集合     str.Append(if(#uu0) then);    //如果集合长度0     str.Append(   return 1 );     str.Append(else );     str.Append(   for i1,#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的实例来实现。最后放上效果图。最后我把这些都给做成了个Demo。我喜欢和我一样的人交朋友不被环境影响自己是自己的老师欢迎加群 .Net web交流群 166843154原文地址:http://www.cnblogs.com/1996V/p/8127576.html.NET社区新闻深度好文欢迎访问公众号文章汇总 http://www.csharpkit.com
http://www.pierceye.com/news/576976/

相关文章:

  • 如何推广自己的网站和产品如何用dw做网站地图
  • 株洲有名的网站重庆市公路建设信息网官网
  • 网站安全证书出错怎么做dw网页制作素材网站
  • 收录查询 站长工具给网站做解答是干嘛的
  • 成都哪些公司可以做网站建网站现软件
  • 深圳wap网站建设传奇霸主页游
  • 做网站首先要干什么营销软文200字
  • 帝国cms做的网站私人定制女装店
  • 网站建设南沙wordpress video
  • 网站建设开票应该开哪个行业什么网站可以免费做视频的软件
  • 百度seo查询收录查询网站推广策划案seo教程
  • 如何免费建立网站中贤建设集团网站
  • 如何做转运网站黄聪 wordpress
  • 临海市住房与城乡建设规划局网站宁波网络推广培训
  • go 网站开发自己在线制作logo
  • 重庆市网站建设公司企业服务账号
  • 网站建设的市场情况网站系统里不能打印
  • 网站如何适应屏幕做网站时无法上传图片
  • 网站的橱窗怎么做嘉兴住房和城乡建设厅网站
  • 吉林省城乡建设官方网站163企业邮箱登录入口官网
  • 做网站参考文献某企业网站建设方案2000字
  • 网站托管哪家好织梦购物网站整站源码
  • 怎么做网站的优化排名wordpress的目录结构(一)
  • 个人可以做公益网站吗美食杰网站的建设目的
  • 宿迁公司企业网站建设《网站基础建设-首保》
  • 做全屏式网站尺寸是多大国外虚拟主机 两个网站
  • 黑龙江建设网站招聘广西住房和城乡建设厅培训中心官方网站
  • 做网站客户最关心的是什么制作网页原型的目的
  • 电子商务网站建设工具河南安阳吧
  • 南通网站建设公司哪个好肯德基的网站建设