调用方式
调用方式 | |
---|---|
同步阻塞方式 | 阻塞影响性能 |
同步非阻塞方式 | 实际不应用 |
异步阻塞方式 | 实际不应用 |
异步非阻塞方式 | 效率最高 |
保障服务稳定的手段
缓存、限流、熔断降级
缓存
缓存击穿、缓存雪崩、缓存穿透
限流
-
为什么限流
对外API服务无法应对突增的请求
-
限流算法
-
计数器
1、实现 限制1s内允许通过请求数 2、缺陷 若前10ms有100个请求通过,剩余990ms拒绝其他请求 产生“突刺现象”,不平滑
-
漏桶
1、实现 准备一个队列保存请求,另外通过一个线程池定期从队列中获取请求并执行,可以一次性获取多个请求并发执行 2、缺陷 无法应对突增流量
-
令牌桶
1、实现 可以准备一个队列,用来保存令牌,另外通过一个线程池定期生成令牌放到队列中,每来一个请求,就从队列中获取一个令牌,并继续执行。
-
熔断降级
-
熔断
概念 1、应对雪崩效应的一种微服务链路保护机制 解决问题 2、当所依赖的对象不稳定时,能够起到快速失败的目的; 3、快速失败后,能够根据一定的算法动态试探所依赖对象是否恢复
-
降级
概念 1、服务降级是从整个系统的负荷情况出发和考虑的,对某些负荷会比较高的情况,为了预防某些功能(业务场景)出现负荷过载或者响应慢的情况 2、在其内部暂时舍弃对一些非核心的接口和数据的请求,而直接返回一个提前准备好的fallback(退路)错误处理信息。这样,虽然提供的是一个有损的服务,但却保证了整个系统的稳定性和可用性。
-
主流框架
1、Sentinel 2、Hystrix 3、Resilience4j
-
熔断、降级相同点
1、目的很一致,都是从可用性可靠性着想,为防止系统的整体缓慢甚至崩溃,采用的技术手段; 2、最终表现类似,对于两者来说,最终让用户体验到的是某些功能暂时不可达或不可用; 3、粒度一般都是服务级别,当然,业界也有不少更细粒度的做法,比如做到数据持久层(允许查询,不允许增删改); 4、自治性要求很高,熔断模式一般都是服务基于策略的自动触发,降级虽说可人工干预,但在微服务架构下,完全靠人显然不可能,开关预置、配置中心都是必要手段;
-
熔断、降级区别
1、触发原因不太一样,服务熔断一般是某个服务(下游服务)故障引起,而服务降级一般是从整体负荷考虑; 2、管理目标的层次不太一样,熔断其实是一个框架级的处理,每个微服务都需要(无层级之分),而降级一般需要对业务有层级之分(比如降级一般是从最外围服务开始) 3、实现方式不太一样;服务降级具有代码侵入性(由控制器完成/或自动降级),熔断一般称为自我熔断。
内存模型
线程共享数据区、线程私有数据区
-
线程共享数据区
随着虚拟机启动而创建,随着虚拟机退出而销毁-
堆内存
新生代 eden区(生成区) survivor区(幸存区) Survivor0即FromSpace Survivor1即ToSpace Eden:FromSpace:ToSpace 为 8:1:1 老年代 old区:存储长期活动的对象
-
方法区
存储类信息、常量、静态变量、即时编译后代码
-
常量池
编译期生成的class文件的各种字面量和符号引用
-
-
线程私有数据区
随着线程开始和结束而创建和销毁-
PC寄存器
当前线程所执行的字节码的行号指示器,占内存极小
-
虚拟机栈
存放栈帧,而栈帧主要包括了:局部变量表、操作数栈、动态链表、方法出又等。
-
本地方法栈
用于支持native方法的运行
-
GC
堆内存分代理由:提高GC性能
- GC算法
-
引用计数
应用 python、微软的com 缺点 每次对对象赋值时,均要维护引用计数器,且本身计数器也有一定消耗
-
可达分析(跟踪)
-
复制
原理 从根集合开始,通过跟踪从fromSpace中找到存活的对象,copy到toSpace中 from、to交换身份,下次内存分配从to开始 优点 没有标记-清除过程,效率高 没有内存碎片,可以利用bump-the-pointer实现快速分配内存 缺点 需要双倍空间 应用 eden、幸存区
-
标记-清除
原理 标记:从跟集合开始扫描,对存活的对象进行标记 清除:扫描整个内存空间,回收未被标记的对象,使用free-list记录可用区域 优点 不需要额外空间 缺点 两次扫描,损耗严重 产生内存碎片
-
标记-压缩
原理 标记:从跟集合开始扫描,对存活的对象进行标记 压缩:再次扫描,并往一端滑动存活的对象 优点 没有内存碎片,可以利用bump-the-pointer 缺点 需要移动对象的成本
-
标记-清除-压缩
原理 标记-清除、标记-压缩结合 当进行多次GC(标记、清除)后,才压缩 优点 减少了移动对象的成本 应用 老年代
-
直接内存
直接内存适合申请次数较少,访问较频繁的场合 直接内存跳过了java堆,使java程序可以直接访问原⽣内存空间,因此,直接内存访问速度会快于堆内存 直接内存常⽤于使⽤NIO的场景,例如:mina,netty框架;参考DirectBuffer、ByteBuffer
-
-
类加载(classloader)
- 类加载时机
-
类的生命周期
加载 验证 准备 解析 初始化 使用 卸载 连接
-
类立即初始化五种场景
主动引用、被动引用主动引用 1、遇到如下字节码指令 new getstatic putstatic invokestatic 2、使用java.lang.reflect包对类进行反射调用 3、初始化某个类,其父类未初始化,先触发父类初始化 4、虚拟机启动,用户指定一个要执行的类包含main()方法,优先初始化该主类 5、当使用 JDK 1.7 的动态语言支持时,如果一个 java.lang.invoke.MethodHandle 实例最后的解析结果 REF_getStatic、REF_putStatic、REF_invodeStatic 的方法句柄,并且这个方法句柄所对应的类没有进行过初始化,则需要先触发其初始化 被动引用 除上面五种主动引用之外,其他引用类的方式都不会触发类的初始化,称为类的被动引用
-
类加载过程
1、加载 将字节码文件装载入内存中,生成一个java.lang.Class对象 2、验证 文件格式验证 元数据验证 字节码验证 符号引用验证 3、准备 为类变量分配内存,并赋初值 4、解析 将常量池内符号引用替换为直接引用 5、初始化 真正开始执行类中定义的java程序代码
-
类加载器
-
类加载器的定义
虚拟机把描述类的数据从class字节码文件加载到内存,并对数据进行检验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。
-
类加载器的分类
1、从jvm的角度 启动类加载器 所有其他的类加载器 2、从开发者的角度 启动类加载器(Bootstrap ClassLoader) 扩展类加载器(Extension ClassLoader) 应用程序类加载器(Application ClassLoader)
-
双亲委派模型
1、定义 启动类加载器《-扩展类加载器《-应用程序类加载器《-自定义类加载器 2、优点 有一个很明显的好处,就是Java类随着它的类加载器(说白了,就是它所在的目录)一起具备了一种带有优先级的层次关系,这对于保证Java程序的稳定运作很重要
-
应用
1、依赖冲突 包冲突通过pandora(潘多拉),自定义类加载器为每个中间价自定义一个加载器 2、热加载 spring boot devtools RestartClassLoader为自定义的类加载器,其核心是loadClass的加载方式,我们发现其通过修改了双亲委托机制,默认优先从自己加载,如果自己没有加载到,从从parent进行加载。这样保证了业务代码可以优先被RestartClassLoader加载。进而通过重新加载RestartClassLoader即可完成应用代码部分的重新加载。 3、热部署 指在线上环境使用classloader的加载机制完成业务的部署 热部署除了与热加载具有发布更快之外,还有更多的更大的优势就是具有更细的发布粒度 4、加密保护 jar包反编译即可获得代码
-
-