用 Java 没法作出相似 Redis 这样的产品。Java 的内存回收机制使咱们在编写代码时不须要关注对象的回收,同时加大了内存回收的消耗,标记复制须要作内存拷贝,标记清除算法则须要 stop the world 。因此咱们在使用缓存的时候,量稍微大一些就须要借助相似 Redis 这样的中间件帮咱们处理了。做为 Javaer ,咱们享受了自动内存回收的安逸,同时也须要多了解下内存优化的方法。程序员
为了了解咱们的系统为何会不停 FGC ,咱们须要先了解一下系统什么状况下会 GC 。在 Jvm 层面,当咱们 new 一个对象的时候, Jvm 会先在堆区分配对象须要的内存,这个时候若是内存不够的话,就须要 GC 了, GC 的返回结果就是对象的空间地址。Jvm 会先进行 ygc ,也就是咱们一般说的标记复制,若是 ygc 以后依然申请不到空间,就会进行 FGC 了。同理,若是 FGC 以后依然没有足够的空间,就会循环的进行 FGC ,直到申请到足够的空间。算法
如上文所讲, FGC 有可能发生在你的每一行代码。若是 FGC 以后依然没有足够的空间,就会不停的 FGC ,直到申请到足够的空间。同时 JVM 会限制在抛出 OutOfMemory 错误以前在 GC 中花费的 VM 时间的比例。系统频繁 F 大体有五种状况:数据库
在一个高并发的系统中,多数 FGC 是请求处理变慢致使的。假设单机承受 tps 是1w,正常状况下处理一个请求的时间是 1ms ,那同一时刻并行的请求数量仅为 10 。若是性能发生抖动,每一个请求处理的时间增长到 100ms ,那同一时刻并行的请求数量就会增长到 100 个。每一个线程在处理请求的时候都会 new 一些对象出来,长时间存活的线程会形成相似内存泄漏的效果,将系统的内存耗尽。同时 FGC 也会加重系统性能的开销,使系统变得更慢,产生雪崩。编程
内存泄漏产生的缘由以及解决办法网上有不少资料,这里就不写了。内存泄漏形成系统瘫痪的频率很高,有些系统定时从数据库拉取配置信息缓存到集合中,可是 set 不当心写成了 list ,最终在新增元素的时候内存溢出了。养成良好的编程习惯,多关注些细节,就能避免不少未知的问题。缓存
每台服务器都有并行处理请求的上限,无论请求处理的多快,超过上限以后就会被撑死,对高并发的请求作好并发数限制是保持系统稳定的必要条件。须要注意的是,有一些系统在拒绝过多的请求时,也会作一些降级逻辑,降级逻辑也是有性能开销的,一样须要作并发限制,若是降级的请求超过并发限制,将不进行降级逻辑直接抛出异常。服务器
咱们须要自适应限流有两个缘由:并发
每台服务器所处的环境是不同的分布式
有些服务器和离线计算的 vm 混部在一块儿,有些部署在实体机,有些部署在新老型号的机器上,每台服务器能承受的 qps 并不彻底同样。统一配置分布式系统中每台服务器限流阀值,要么发挥不出每台服务器应有的做用,要么在高 qps 的状况下一些比较慢的服务器宕机,因此用服务器做为限流粒度是最合适的。高并发
设置了正确的限流阀值,也可能被摸死性能
当单机承受的 QPS 6~20 倍于限流的流量时,拒绝一次请求的开销就没法忽略不记了。譬如春晚活动有些系统设置了正确的限流也被 6~20 倍于限流的流量冲垮。这种死法称为被摸死。应对这种状况,咱们能够作的是在受到 6~20 倍的大流量时,动态减小限流的阀值。好比系统最开始接受 1000qps ,5000 的拒绝流量过来会把系统摸死,这个时候咱们调整系统的阀值,限流设置到 100 ,被摸死的阀值就能够高一些,这样就算有 6000 个请求进来,咱们系统也能够保证活下来。
阿里有结合算法动态调整单机限流阀的产品,已经对外公布了,感兴趣的同窗能够搜一下淘系技术公众号中的 诺亚自适应限流 的相关内容。
咱们盯系统监控的时候一般会关注 99 分位的数据,但若是设置了合理的限流,系统依然被流量打挂,就要从那百分之一的长尾数据入手了。有些长尾数据对系统的影响会很是大。想象若是一个 put 请求传过来几十兆的数据,对 Java 是极为不友好的,颇有可能产生 FGC ,让请求变慢,致使一系列问题。
总之,磨刀不误砍柴工,当咱们的系统由于 FGC 一次又一次重启的时候,不如花时间了解下系统产生性能问题的缘由,将产生问题的那根针拔掉,晚上睡个安稳觉,白天更加充满活力的挖新坑。但愿每一个程序员手里都是一个稳定的系统。
做者信息:通木, Github 帐号 zhdd99 ,阿里巴巴基础设施事业部高级开发工程师,目前主要负责阿里巴巴IDC监控系统。
本文做者:通木
本文为阿里云内容,未经容许不得转载。