首页 文章 精选 留言 我的

精选列表

搜索[高DPI],共10000篇文章
优秀的个人博客,低调大师

高并发系统三大利器之限流

点击蓝色字关注我们! 什么是限流? ❝ 限流可以认为服务降级的一种,限流就是限制系统的输入和输出流量已达到保护系统的目的。一般来说系统的吞吐量是可以被测算的,为了保证系统的稳定运行,一旦达到的需要限制的阈值,就需要限制流量并采取一些措施以完成限制流量的目的。比如:延迟处理,拒绝处理,或者部分拒绝处理等等。 ❞ 坐地铁上班的同学对于这张图片是不是都不会陌生。基本上在上下班的早晚高峰我们就会发现进站的闸机会有一部分是关闭的。为什么地铁站会关闭一部分闸机呢?这就是为了限流。毕竟地铁站就那么大,可容纳的人数也就那么多。如果大家一股脑全部挤进地铁站是不是又会发生踩踏事件什么的。这是生活中的限流。还有我们去景区玩,景区的门票是不是也是固定的,每天就卖那么多张,卖完即止。限流是不是和我们的生活也息息相关。 为什么要限流? 开篇也有说到限流是为了「保证系统的稳定运行」。假设我们一个系统一小时之最多只能处理10000个请求,但是一小时流量突增10倍,这突增的流量我们如果不进行限制的话,任由它直接进入系统的话,是不是直接会把我们的系统弄瘫痪,就无法对外提供服务了。本人就曾经被这个所坑过,有一次把爬虫开关拦截的开关给关掉了,突然有一大波的爬虫流量进入系统中,我们也没有把这些爬虫请求进行拦截,然后一股脑的全部给转发到下游系统里面去了。下游系统直接就找上门来了,造成他们的服务发生大量的超时。比如地铁早高峰的时候我们如果不对地铁站进行限流的话,大家是不是都会往地铁站挤,然后再往地铁里面挤,挤不上都还要挤。会导致地铁门都关不上,然后地铁就开不走,会导致越来越多的人堵在地铁站。然后最后就会导致整条地铁线都阻塞了。上班就妥妥的迟到了(对于程序员说大多数应该是弹性制的所以也不存在迟到这一说法)。 限流操作有哪些? 拒绝服务 这个是最最简单粗暴的做法了,直接把请求直接拒绝掉。比如早高峰坐地铁的时候,直接让进入1000个人,剩下多出来的人不让坐地铁了。直接把入站口给关闭了。 服务降级 将系统的所有功能服务进行一个分级,当系统出现问题,需要紧急限流时,可将不是那么重要的功能进行降级处理,停止服务,这样可以释放出更多的资源供给核心功能的去用。假设有一个功能新用户注册完,要给用户发送多少优惠券。这时候服务降级的话就可以直接把送券服务关掉,让服务快速响应,提高系统处理能力。应用到早高峰坐地铁的时候比如在人民广场这个大站点,处理不过来了那么多人换乘,我们是不是可以直接地铁一号线在人民广场不停,直接到下一站在停,这时候经过人民广场换乘的人就少多了。 延迟处理 把请求全部放入到队列中,真正处理的话,就从队列里面依次去取,这样的话流量比较大的情况可能会导致处理不及时,会有一定的延时。双十一零点我们付款的时候,去查询订单的状态是不是也会有一定的延时,不像在平时付完款订单状态就变成了付款状态。 特权处理 这个模式需要将用户进行分类,通过预设的分类,让系统优先处理需要高保障的用户群体,其它用户群的请求就会延迟处理或者直接不处理。我们去银行办理业务的时候是不是也会经常需要排队,但是是不是经常会VIP用户、什么白金卡用户,直接不需要排队,直接一上来就可以办理业务,还优先处理这些人的业务。是不是特羡慕这些人,哎 羡慕也没办法谁叫人家有钱咧。 限流的实现方式? 计数器方法 这是最简单的限流算法了,系统里面维护一个计数器,来一个请求就加1,请求处理完成就减1,当计数器大于指定的阈值,就拒绝新的请求。是通过全局的总求数于设置的阈值来达到限流的目的。通常应用在池化技术上面比如:「数据库连接池、线程池」等中应用。这种方式的话限流不是「平均速率」的。扛不住突增的流量。 漏桶算法 我们可以看到水是可以持续流入漏桶里面的,底部也是匀速的流出,如果流入的速率大于底部流出的速率,以及漏桶的水超过桶的大小就会发生益出。请求一经过漏桶的过滤,不管你请求有多少,速率有多快,我反正就这么个速度处理。我们平时坐地铁的时候是不是也是这样,不管你乘客有多少,反正就是隔5min发一趟车。那早高峰的时候你5min钟一趟车根本就不够用啊,上班的人太多啊,你需要加快速度处理啊,所以可能早高峰改为3min一趟,动态调整速率。 令牌桶 在这里插入图片描述 看图的话是不是令牌桶和漏桶都差不多,只不过令牌桶新增了一个匀速生产令牌的中间人以恒定的速度往桶里面放令牌,如果令牌的数量超过里桶的限制的话,令牌就会溢出,这时候就直接舍弃多余的令牌。每个请求过来必须拿到桶里面拿到了令牌才允许请求(拿令牌的速度是不限制的,这就意味着如果瞬间有大量的流量请求进来,可以短时间内拿到大量的令牌),拿不到令牌的话直接拒绝。这个令牌桶的思想是不是跟我们java里面的「Semaphore」 有点类似。Semaphore 是拿信号量,用完了就还回去。但是令牌桶的话,不需要还回去,因为令牌会定时的补充。令牌桶算法我们可以通过Google开源的guava包创建一个令牌桶算法的限流器。 总结 以上粗略的介绍了几种单机的限流思想,大家可以根据这个思想然后去实现各种各样的限流组件。 我们的限流算法每个里面是不是都一个阈值,这个阈值设置为多少是不是比较难。阈值设置过大的话,服务可能扛不住,阈值设置小了会把用户请求给误杀,资源没有得到最大的一个利用。 分布式限流的话,以后有机会再讲。 结束 由于自己才疏学浅,难免会有纰漏,假如你发现了错误的地方,还望留言给我指出来,我会对其加以修正。 如果你觉得文章还不错,你的转发、分享、赞赏、点赞、留言就是对我最大的鼓励。 感谢您的阅读,十分欢迎并感谢您的关注。 往期推荐最近面试BAT,整理一份面试资料《Java面试BATJ通关手册》,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构、等等。获取方式:点“在看”,关注公众号并回复 666领取,更多内容陆续奉上。文章有帮助的话,在看,转发吧。谢谢支持哟 (*^__^*) 本文分享自微信公众号 - java金融(java4299)。如有侵权,请联系 support@oschina.cn 删除。本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

优秀的个人博客,低调大师

Java高并发之从零到放弃

前言 本篇主要讲解如何去优化锁机制或者克服多线程因为锁可导致性能下降的问题 ThreadLocal线程变量 有这样一个场景,前面是一大桶水,10个人去喝水,为了保证线程安全,我们要在杯子上加锁导致大家轮着排队喝水,因为加了锁的杯子是同步的,只能有一个人拿着这个唯一的杯子喝水这样子大家都喝完一杯水需要很长的时间如果我们给每个人分发一个杯子呢?是不是每人喝到水的时间缩小到了十分之一 多线程并发也是一个道理在每个Thread中都有自己的数据存放空间(ThreadLocalMap)而ThreadLocal就是在当前线程的存放空间中存放数据下面这个例子,在每个线程中存放一个arraylist,而不是大家去公用一个arraylist publicclassThreadLocalTest{ publicstaticThreadLocalthreadLocal=newThreadLocal(); publicstaticArrayListlist=newArrayList(); publicstaticclassDemoimplementsRunnable{ privateinti; publicDemo(inti){ this.i=i; } @Override publicvoidrun(){ list.add(i); threadLocal.set(list); System.out.println(threadLocal.get()); } } publicstaticvoidmain(String[]args)throwsInterruptedException{ ExecutorServicees=Executors.newFixedThreadPool(5); for(intj=0;j<200;j++){ es.execute(newDemo(j)); } Thread.sleep(3000); System.out.println(list.size()); es.shutdown(); } } 在每个线程内部有一块存储区域叫做ThreadLocalMap可以看到,ThreadLocal采用set,get存取值方式只有线程完全关闭时,在ThreadLocalMap中的数据才会被GC回收 这时有一个值得考虑的问题我们使用线程池来开发的时候,线程池中的线程并不会关闭,它只是处于空闲状态也就是说,我们如果把过大的数据存储在当前线程的ThreadLocalMap中,线程不断的调用,被空闲...最后会导致内存溢出解决方法是当不需要这些数据时使用ThreadLocal.remove()方法将变量给移除 CAS操作 还有一种脱离锁的机制,那就是CASCAS带着三个变量,分别是:V更新变量:需要返回的变量E预期值:原来的值N新值,传进来的新变量 只有当预期值和新值相等时,才会把V=N,如果不相等,说明该操作会让数据无法同步根据上面的解释,大概就能知道CAS其实也是在保护数据的同步性 当多个线程进行CAS操作时,可想只有一个线程能成功更新,之后其它线程的E和V会不地进行断比较所以CAS的同步锁的实现是一样的 CAS操作的并发包在Atomic包中,atomic实现了很多类型不管是AtomicInteger还是AtomicReference,都有相同点,请观察它们的源码: privatevolatileVvalue; privatestaticfinallongvalueOffset; 以上是AtomicReferenc privatevolatileintvalue; privatestaticfinallongvalueOffset; 以上是AtomicIntege 都有value,这是它们的当前实际值 valueOffset保存的是value的偏移量 下面给出一个简单的AtomicIntege例子: publicclassAtomicTest{ publicstaticAtomicIntegeratomicInteger=newAtomicInteger(); //publicstaticAtomicReferenceatomicReference=newAtomicReference(); publicstaticclassDemoimplementsRunnable{ @Override publicvoidrun(){ for(intj=0;j<1000;j++){ atomicInteger.incrementAndGet();//当前值加1并且返回当前值 } } } publicstaticvoidmain(String[]args)throwsInterruptedException{ ExecutorServicees=Executors.newFixedThreadPool(10); for(inti=0;i<10;i++){ es.submit(newDemo()); } Thread.sleep(5000); System.out.println(atomicInteger); } } 你试着执行一下,如果打印出10000说明线程安全 使用CAS操作比同步锁拥有更好的性能 我们来看下incrementAndGet()的源码: publicfinalintincrementAndGet(){ returnunsafe.getAndAddInt(this,valueOffset,1)+1; } 来看下getAndAddInt()源码: publicfinalintgetAndAddInt(Objectvar1,longvar2,intvar4){ intvar5; do{ var5=this.getIntVolatile(var1,var2); }while(!this.compareAndSwapInt(var1,var2,var5,var5+var4)); returnvar5; } 这里有一个循环,再细看源码发现是native的,虽然看不到原生代码,但是可以看出它这里做了一个CAS操作,不断地进行多个变量的比较,只有预设值和新值相等时,才跳出循环var5就是需要更新的变量,var1和var2是预设值和新值 死锁 讲了那么多无锁的操作,我们来看一下一个死锁的现象两个线程互相占着对方想得到的锁,就会出现死锁状况 publicclassDeadLockextendsThread{ protectedStringsuo; publicstaticStringzuo=newString(); publicstaticStringyou=newString(); publicDeadLock(Stringsuo){ this.suo=suo; } @Override publicvoidrun(){ if(suo==zuo){ synchronized(zuo){ System.out.println("拿到了左,正在拿右......"); synchronized(you){ System.out.println("拿到了右,成功了"); } } } if(suo==you){ synchronized(you){ System.out.println("拿到了右,正在拿左......"); synchronized(zuo){ System.out.println("拿到了zuo,成功了"); } } } } publicstaticvoidmain(String[]args)throwsInterruptedException{ for(inti=0;i<10000;i++){ DeadLockt1=newDeadLock(zuo); DeadLockt2=newDeadLock(you); t1.start();t2.start(); } Thread.sleep(50000); } } 如图: 出现了两个线程的死锁现象,所以说去锁不仅能提升性能,也能防止死锁的产生。 本文地址https://segmentfault.com/a/1190000012218687

资源下载

更多资源
Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册