Redis

238 阅读11分钟

Redis 了解吗,作用?

Redis是基于C语言开发的的开源NoSQL数据库。与传统的数据库不同的是,Redis的数据是保存在内存中的,内存数据库,支持持久化,因此读写速度非常快。Redis存储的是KV键值对数据。为了满足不同的业务场景,Redis内置了很多数据类型的实现(比如String、Hash、Sorted Set、Bitmap、HyperLogLog、GEO)。并且还支持事务、持久化、Lua脚本多种开箱即用的集群方案(Redis Sentinel、Redis Cluster)。

Redis 除了做缓存,还能做什么?

分布式锁、限流、消息队列、延时队列、分布式Session

Redis数据结构有哪些

Redis共有5种基本数据类型:String(字符串)、List(列表)、Set(集合)、Hash(散列)、Zset(有序集合)。Redis 还支持 3 种特殊的数据类型:Bitmap(位图)、HyperLogLog(基数统计)、GEO(地理位置)。

Redis健壮性

Redis的内存管理策略——内存永不溢出

Redis主要有两种策略机制来保障存储的key-value数据不会把内存塞满,它们是:过期策略和淘汰策略。

  • 过期策略:指的就是Redis内部是如何实现将过期的key对应的缓存数据清除的,Redis主要是靠两种机制来处理过期的数据被清除:定期过期(主动清除)和惰性过期(被动清除)。
    • 惰性过期(被动清除) :就是每次访问的时候都去判断一下该key是否过期,如果过期了就删除掉。
    • 定期过期(主动清除) :每隔一定的时间,会扫描Redis数据库的expires字典中一定数量的key,并清除其中已过期的 key。
  • 淘汰策略:在Redis可能没有需要过期的数据的情况下,还是会把我们的内存都占满。比如每个key设置的过期时间都很长或不过期,一直添加就有可能把内存给塞满。该怎么解决呢?Reids官网上面列出的淘汰策略一共有8种,但从实质算法来看只有两种实现算法,分别是LRU和LFU。
    • LRU(Least Recently Used) :最久未使用,根据时间轴来走,淘汰那些距离上一次使用时间最久远的数据。
    • LFU(Least Frequently Used) :最不常用。是按着使用频次来算的,淘汰那些使用频次最低的数据。

过期策略 保证过期的key对应的数据会被及时清除;淘汰策略保证内存满的时候会自动释放相应空间,因此Redis的内存可以自运行保证不会产生溢出异常。

Redis的数据持久化策略——宕机可立即恢复数据到内存

看Redis是如何保障服务器宕机或重启,原来缓存在内存中的数据是不会丢失的。也就是Redis的持久化机制。Redis的持久化策略有两种:RDB(快照全量持久化)和AOF(增量日志持久化)。

  • RDB:是Redis 默认的持久化方案。当触发一定条件的时候,会把当前内存中的数据写入磁盘,生成一个快照文件dump.rdb。Redis重启会通过dump.rdb文件恢复数据。
    • 自动触发:达到配置文件触发规则时触发、执行shutdown命令时触发、执行flushall命令时触发。
    • 手动触发:执行save 或 bgsave命令。
      • save命令同步保存操作,会阻塞 Redis 主线程;
      • bgsave命令fork 出一个子进程,子进程执行,不会阻塞 Redis 主线程,默认选项。

优势:1.紧凑的文件类型,适合备份和灾难恢复;2.在生成RDB文件时,主进程不需要进行磁盘IO操作;3.在恢复大数据集时速度较快。

劣势:在于数据无法实时持久化或秒级持久化,需要以一定的间隔时间进行备份,因此如果Redis意外down掉,就会丢失最后一次快照之后的所有修改。

  • AOF(Append Only File):AOF采用日志的形式来记录每个写操作的命令,并追加到文件中。开启后,执行更改Redis数据的命令时,就会把命令写入到AOF文件中。Redis重启时会根据日志文件的内容把写指令从前到后执行一次以完成数据的恢复工作。
    • no 表示不执行 fsync,由操作系统保证数据同步到磁盘,速度最快,但是不太安全
    • always 表示每次写入都执行fsync,以保证数据同步到磁盘,效率很低;
    • everysec 表示每秒执行一次 fsync,可能会导致丢失这1s数据。通常选择 everysec,兼顾安全性和效率。

优势:能最大限度的保证数据安全,就算用默认的配置everysec,也最多只会造成1s的数据丢失。

劣势:数据量比RDB要大很多,所以性能没有RDB好。

Redis的哨兵模式——可战到最后一兵一卒的高可用集群

所谓的“哨兵模式”就是有一群哨兵(Sentinel)在Redis服务器前面帮我们监控这Redis集群各个机器的运行情况,并且哨兵间相互通告通知,并指引我们使用那些健康的服务。

  • Sentinel工作原理:PING
  • Sentinel的作用:监控、故障处理、配置管理

同步、异步

  • 同步:发出一个调用之后,在没有得到结果之前,该调用就不可以返回,一直等待。
  • 异步:调用在发出之后,不用等待返回结果,该调用直接返回。

创建线程的方法哪些

一般来说,创建线程有很多方法,例如继承Thread类、实现Runnable接口、实现Callable接口、使用线程池、使用CompletableFuture类等。不过,这些方法并没有真正创建出线程。准确的的来说,这些都是属于 Java创建线程有很多种方式啊,像实现Runnable、Callable接口、继承Thread类、创建线程池、使用CompletableFuture类等等,不过这些方式并没有真正创建出线程,严格来说,Java就只有一种方式可以创建线程,那就是通过new Thread().start()创建。 而所谓的Runnable、Callable对象,这仅仅只是线程体,也就是提供给线程执行的任务,并不属于真正的Java线程,它们的执行,最终还是需要依赖于new Thread(),线程是执行线程体的容器,线程体是一个可运行的任务。

线程池作用

线程池就是管理一系列线程的资源池,其提供了一种限制和管理线程资源的方式。

  • 降低资源消耗:通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
  • 提高响应速度:当任务到达时,任务可以不需要等到线程创建就能立即执行。
  • 提高线程的可管理性:线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。
阿里巴巴手册关于线程池

image.png

Spring SpringMVC SpringBoot

Spring是一个包含多个功能模块的框架,其中最重要的是Spring Core,它提供了IoC依赖注入的支持。其他模块如Spring MVC都依赖于它。Spring MVC赋予Spring快速构建MVC架构的Web程序的能力。由于使用Spring进行开发配置繁琐,因此出现了Spring Boot,它简化了Spring开发的配置。虽然Spring Boot简化了配置,但如果需要构建MVC架构的Web程序,仍然需使用Spring MVC,只是Spring Boot简化了很多配置。

AOP 、IoC

  • IoC(Inversion of Control):控制反转,是一种设计思想,而不是一个具体的技术实现。Ioc的思想就是将原本在程序中手动创建对象的权力交给Spring框架来管理。
  • AOP (Aspect-Oriented Programming):面向切面编程,能够将那些与业务无关的,却为业务模块所共同调用的逻辑或责任(事务处理、日志管理等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。

浅拷贝,深拷贝

  • 浅拷贝:浅拷贝会在堆上创建一个新的对象,不过,如果原对象内部的属性是引用类型的话,浅拷贝会直接复制内部对象的引用地址,也就是说拷贝对象和原对象共用同一个内部对象。
  • 深拷贝:深拷贝会完全复制整个对象,包括这个对象所包含的内部对象。
  • 引用拷贝:是两个不同的引用指向同一个对象。

List a, list b; a=b是浅拷贝还是深拷贝,怎么才能深拷贝

  • 本质应该来说属于引用拷贝。在Java中,当你执行a=b时,它涉及的是对象引用的复制,而不是对象本身的复制。因此,a=b会使a和b引用同一个对象。这被称为浅拷贝。
  • 深拷贝都会创建一个新的对象,并复制原始对象中的数据,这样两个对象将不再共享引用,互不影响。

接口、抽象类的区别,抽象类的作用

  • 接口和抽象类的共同点:
    • 都不能被实例化。
    • 都可以包含抽象方法。
    • 都可以有默认实现的方法(Java 8 可以用 default 关键字在接口中定义默认方法)。
  • 接口和抽象类的区别:
    • 接口主要用于对类的行为进行约束,你实现了某个接口就具有了对应的行为。抽象类主要用于代码复用,强调的是所属关系。
    • 一个类只能继承一个类,但是可以实现多个接口。
    • 接口中的成员变量只能是 public static final 类型的,不能被修改且必须有初始值,而抽象类的成员变量默认 default,可在子类中被重新定义,也可被重新赋值。
  • 抽象类的作用:抽象类的作用主要是为子类提供一个共同的模板,定义了一些通用的方法和属性。子类可以继承抽象类拥有这些通用属性并按需实现或覆盖其中的方法。抽象类是面向对象编程中重要的概念,能够提高代码的复用性和可读性,同时也能够对类的继承进行限制。

String StringBuffer StringBuilder

  • 可变性:String是不可变的。而StringBuffer和StringBuilder都继承自AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组保存字符串,不过没有使用final和private关键字修饰,最关键的是这个AbstractStringBuilder类还提供了很多修改字符串的方法比如append方法
  • 线程安全性:String中的对象是不可变的,也可以理解为常量,线程安全。StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder并没有对方法进行加同步锁,所以是非线程安全的。
  • 性能:每次对String类型进行改变的时候,都会生成一个新的String对象,然后将指针指向新的String对象。StringBuffer每次都会对StringBuffer对象本身进行操作,而不是生成新的对象并改变对象引用,比StringBuilder的性能差一些,但是线程安全。
  • 操作少量数据使用String 单线程操作大量数据:StringBuilder 多线程操作大量数据:StringBuffer

SpringBoot的注解哪些

  1. @SpringBootApplication:用于标记启动类,表示该类是Spring Boot应用程序的入口点。
  2. @RestController:用于标记控制器类,表示该类处理HTTP请求并返回RESTful响应。
  3. @RequestMapping:用于将HTTP请求映射到控制器的处理方法上。
  4. @Autowired:用于自动装配依赖,通过依赖注入的方式将bean实例注入到目标对象中。
  5. @Service:用于标记服务类,表示该类提供业务逻辑。
  6. @Repository:用于标记数据访问层(DAO)类,表示该类用于访问数据库或其他数据源。
  7. @Component:用于标记通用组件类,表示该类可以被Spring框架自动扫描并创建实例。
  8. @Configuration:用于标记配置类,表示该类包含一个或多个bean的定义。
  9. @Value:用于注入外部配置文件中的值到字段或方法参数中。
  10. @Valid:用于参数校验,表示对目标对象进行数据校验。
  11. @EnableAutoConfiguration:用于开启自动配置,基于类路径下的依赖自动生成(Spring Boot的核心特性之一)。

你项目中怎么向前端传数据的

后端向前端传数据的几种常用途径:

  • RESTful API:使用 HTTP 请求进行数据交换,前端可以通过 GET、POST、PUT 等方法请求服务端数据或者发送数据到服务端。
  • Websocket:提供全双工通信渠道,允许服务端和客户端之间进行实时数据传输。
  • Server-Sent Events (SSE):允许服务端向客户端推送实时数据更新,通常用于单向通信,如推送通知。