REST 全称是
Representational State Transfer
,中文意思是表征性状态转移。它首次出现在 2000 年 Roy Fielding 的博士论文中,Roy Fielding 是 HTTP 规范的主要编写者之一。 他在论文中提到:我这篇文章的写作目的,就是想在符合架构原理的前提下,理解和评估以网络为基础的应用软件的架构设计,得到一个功能强、性能好、适宜通信的架构。REST 指的是一组架构约束条件和原则。
如果一个架构符合 REST 的约束条件和原则,我们就称它为 RESTful 架构。
REST 本身并没有创造新的技术、组件或服务,而隐藏在 RESTful 背后的理念就是使用 Web 的现有特征和能力,更好地使用现有 Web 标准中的一些准则和约束。虽然 REST 本身受 Web 技术的影响很深,但是理论上 REST 架构风格并不是绑定在 HTTP 上,只不过目前 HTTP 是唯一与 REST 相关的实例。所以我们这里描述的 REST 也是通过 HTTP 实现的 REST。
Reference
https://www.runoob.com/w3cnote/restful-architecture.html
为了提高数据响应速度,会将一些高频访问的数据保存在缓存中。这样就不用每次请求都去查询数据库,可以提高服务接口的响应速度。目前最常使用的缓存就是 Redis。缓存一般是用来对数据库中的高频数据做一个优化的,也仅存储一些数据库中被高频访问的数据的。
Cache-Aside
最经典的一个缓存 + 数据库的读写模式就是 Cache-Aside 模式了。
读取的时候一般没有问题,有问题的是数据更新。在这个模式中,更新数据采用的是先更新数据库再删除缓存的模式。问题主要存在两个:
① 为什么是删除缓存而不是更新缓存?
Reference
https://blog.csdn.net/qq_38420688/article/details/108803569
② 为什么不删除旧缓存再更新数据库?
延迟双删
其实无论是先更新数据库再删除缓存,还是先删除缓存再更新数据库,在并发环境下都有可能存在问题。假设有 A、B 两个并发请求:
当然前面已经分析过了,尽量先操作数据库再操作缓存,但是即使这样也还是有可能存在问题,解决问题的办法就是延迟双删。
延迟双删是先执行缓存清除操作,再执行数据库更新操作,延迟 N 秒之后再执行一次缓存清除操作,这样就不用担心缓存中的数据和数据库中的数据不一致。一般来说,N 要大于一次写操作的时间,如果延迟时间小于写入缓存的时间,会导致请求 A 已经延迟清除了缓存,但是此时请求 B 缓存还未写入。具体需要结合自己的业务来统计这个数值。
Reference
https://blog.csdn.net/zxd1435513775/article/details/123840314
Filter 过滤器, Interceptor 拦截器,两者区别:
两者的执行顺序如下:过滤前——拦截前——action 执行——拦截后——过滤后
加载
加载是指 JVM 查找 .class
文件,并且根据字节流创建 java.lang.Class
对象的过程。这个过程将类的 .class
文件中的二进制数据读入内存,放在运行时数据的方法区内。然后在堆中创建 java.lang.Class
对象,用来封装类在方法区的数据结构。
类加载阶段:
.class
文件读入内存,并为之创建一个 Class 对象;验证
验证阶段是保证 .class
文件字节流包含的信息符合 JVM 规范,不会给 JVM 造成危害。如果验证失败,就会抛出一个 java.lang.VerifyError
异常或其子类异常。验证过程分为四个阶段:
.class
文件格式的规范,并且能被当前虚拟机正确的处理。准备
准备阶段为变量分配内存并设置类变量的初始化。在这个阶段分配的仅为 static 修饰的变量,而不包括类的实例变量。对于非 final 的变量,JVM 会将其设置成零值,而不是其赋值语句的值。例如 pirvate static int size = 12;
在这个阶段,size 的值为 0,而不是 12。但 final 修饰的 static 变量将会赋值成真实的值。
解析
解析过程是将常量池内的符号引用替换成直接引用。主要包括四种类型引用的解析:类或接口的解析、字段解析、方法解析、接口方法解析。
初始化
初始化是为标记为常量值的字段赋值的过程,即只对 static 修饰的变量或语句块进行初始化。如果初始化一个类的时候,其父类尚未初始化,则优先初始化其父类。如果同时包含多个静态变量和静态代码块,则按照自上而下的顺序依次执行。
Reference
https://blog.csdn.net/weixin_30720461/article/details/121142420
1.纯内存操作
Redis 是一个内存数据库,它的数据都存储在内存中,这意味着我们读写数据都是在内存中完成,这个速度是非常快的。
Redis 底层采用了高效的数据结构,例如哈希表和跳表,这是它实现高性能的一个重要原因。
2.采用 IO 多路复用机制
Redis 基于 Reactor 模式开发了自己的网络事件处理器:这个处理器被称为文件事件处理器(file event handler)。文件事件处理器使用 I/O 多路复用(multiplexing)程序来同时监听多个套接字,并根据套接字目前执行的任务来为套接字关联不同的事件处理器。
当被监听的套接字准备好执行连接应答(accept)、读取(read)、写入(write)、关闭(close)等操作时,与操作相对应的文件事件就会产生,这时文件事件处理器就会调用套接字之前关联好的事件处理器来处理这些事件。
虽然文件事件处理器以单线程方式运行,但通过使用 I/O 多路复用程序来监听多个套接字,文件事件处理器既实现了高性能的网络通信模型,又可以很好地与 Redis 服务器中其他同样以单线程方式运行的模块进行对接,这保持了 Redis 内部单线程设计的简单性。
3.非 CPU 密集型任务
采用单线程的缺点很明显,无法使用多核 CPU。由于 Redis 的大部分操作并不是 CPU 密集型任务,而 Redis 的瓶颈在于内存和网络带宽。
在高并发请求下,Redis 需要更多的内存和更高的网络带宽,否则瓶颈很容易出现在内存不够用和网络延迟等待的情况。如果单个 Redis 实例的性能不足以支撑业务,推荐部署多个 Redis 节点,组成集群的方式来利用多核 CPU 的能力,而不是在单实例上使用多线程。
4.单线程的优点
Redis 的单线程已经达到了足够高的性能,所以采用了单线程模型来完成请求的处理工作。另外,单线程模型还带了以下好处:
5.多线程优化
在进行一些 AOF 的刷盘工作时,是使用的多线程,特别是在 4.0 版本之后,有更多的优化措施。