1、什么是雪花id,简述雪花id的优缺点?
snowflake是Twitter开源的分布式ID生成算法,结果是64bit的Long类型的ID,有着全局唯一和有序递增的特点。
-
最高位是符号位,因为生成的 ID 总是正数,始终为0。
-
41位的时间序列,精确到毫秒级,41位的长度可以使用69年。时间位还有一个很重要的作用是可以根据时间进行排序。
-
10位的机器标识,10位的长度最多支持部署1024个节点。
-
12位的计数序列号,序列号即一系列的自增ID,可以支持同一节点同一毫秒生成多个ID序号。
优点:
- 全局唯一:能保证高并发分布式系统环境下雪花ID不重复
- 生产id效率高:在高并发以及分布式环境下,除了生成不重复 id,每秒可生成百万个不重复 id,生成效率极高。
- 不依赖第三方库:不依赖于数据库等第三方系统,以服务的方式部署,稳定性更高,算法简单,在内存中进行。
缺点:
- 依赖于服务器时间,服务器时钟回拨时可能会生成重复 id。
- 雪花id不能全局递增,只能在单机上显示递增,在分布式环境下,不同服务器的时间不能同步,不能保证全局递增。
2、JWT 和 session 的区别是什么?
- JWT字符串包含了关于用户的信息,比如用户名,权限,角色等,包含的信息越多,字符串越长。session依赖于cookie,能够存储的信息量比较小
- JWT生产的token是存储在客户端的,session是存储在服务器的
- JWT适用于分布式架构,可以在任何服务器之间传递。session要实现在不同服务器之间传递,需要在不同的服务器中同步session,实现比较困难。
- JWT和session都是用于身份认证和授权的机制,二者的实现方式不同,JWT 则是通过在客户端和服务器之间传递一个加密的、自包含的 Token 来实现身份认证和授权,避免了服务器存储用户状态的问题,同时也降低了网络传输和服务器负载等问题。session 是服务器存储用户状态的一种方式,通常通过在服务器上创建一个唯一的会话 ID,将用户的身份信息保存在会话中,然后将会话 ID 发送给客户端,客户端在后续请求中携带会话 ID,服务器通过会话 ID 来获取用户的身份信息。
3、SpringCache的常用注解
- 4\@EnableCaching:@EnableCaching是启用缓存的注解,将注解标注在SpringBoot项目中的启动类上,就可以开启SpringBoot项目的缓存
- @Cacheable定义在方法上,每次执行该方法前,会先去缓存中查有没有方法结果的缓存数据,有缓存数据直接拿缓存的数据,没有缓存数据的话执行方法,并将执行结果返回并存储到缓存中。
- @CachePut注解在方法上面,每调用一次方法,就会执行一次方法,并将方法执行的结果存储到springboot 的缓存中,此时缓存会和数据库保持一致,@CachePut注解大部分用在改变数据库数据的方法上。
- @CacheEvict是用来标注在需要清除缓存元素的方法上。只要调动方法,就会清除指定名称的缓存。
4、JWT 的优点是什么?
- jwt适用于集群和分布式架构,它给每一个客户端设置唯一的token,存储在客户端,客户端可以携带token访问不同的服务器
- 唯一性,jwt生成的token是唯一的,不管变动jwt的哪一个部分,生成的token都是不同的,
- 安全性高,不容易被破解,每个jwt都有属于自己的签名,通过算法对整个jwt进行签名和加密。
- 无状态,jwt不在服务端存储任何状态
- jwt是基于json格式的,因为json格式通用,因此不同语言之间都可以使用
5、简述Redis的持久化策略?
redis是支持数据持久化的,redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的日志文件,可以将内存中的数据同步到磁盘保证数据的持久化。redis对数据持久化有两种策略:一是RDB(快照策略),二是AOF(追加策略)
RDB策略
redis默认的情况下,是快照RDB的持久化策略,RDB持久化策略是在一个特定的时间内,会fork出一个子进程,子进程将这段时间内内存里面的数据以快照的方式写入一个二进制RDB文件当中,这种持久化策略并不能完全的数据持久化,因为他是定时保存,如果redis突然关闭,就会倒是最后一段时间内的数据没有保存,导致数据的丢失。
优点:
-
RDB文件是二进制文件,所以体积比较小, 适合备份及远距离传输
-
RDB是定时存储数据,它可以很快恢复不同版本或者不同时间段数据
-
适合于容灾恢复,备份文件可以很快的进行远距离传输,也可以在其他服务器恢复
-
RDB 能使 Redis 的性能发挥的最大化,在进行数据备份的时候,Redis 只需要 fork 出一个子进程,让子进程来完成数据的备份。Redis 主要进程是不需要进行与磁盘的IO流操作。
缺点:
-
RDB是定时保存,如果设备突发故障恢复数据的时候会丢失一部分数据
-
RDB经常会fork出子进程进行数据备份操作,大量的数据操作,fork进程也会损耗大量的时间
-
每次执行持久化操作的间隔时间较长。
AOF策略:
-
AOF就是将服务器每一次的操作都追加到AOF日志文件当中,当AOF日志文件过大,它会在后台重写AOF文件。在服务器重新启动的时候,会将AOF文件当中的操作重新执行一遍,从而达到备份数据。
优点:
-
AOF是追加日志文件,因此可以较为完整的备份数据,不会丢失过多的数据
-
AOF持久化策略灵活,可以选择多种fsync策略,使 Redis 可用性更高
-
AOF日志文件过大时,会在后台重写AOF日志文件
-
如果不小心通过命令将数据清空了,也可以通过将日志文件中清空数据的命令删除,重新加载redis,数据就可以会恢复了
缺点:
-
6\相比较RDB文件来说,AOF日志文件比较大,不容易远程传输
-
整体上来看AOF的数据会比RDB要慢,具体要看fsync策略的选择
-
使用文本格式还原数据,所以数据还原速度一般
6、Redis的常用数据类型?
String(字符串)
字符串类型是Redis中最为基础的数据存储类型,字符串是通过键值对存储的,每个键最大可存储数据512MB,字符串在Redis中是二进制安全的,因此,可存储JPG图片或者序列化的对象。
常见命令:
列 | 命令 | 描述 |
---|---|---|
1 | set key value | 设置指定 key 的值 |
2 | get key | 获取指定 key 的值。 |
3 | mget key1 key2 … keyn | 获取所有(一个或多个)给定 key 的值。 |
4 | setnx key value | 只有在 key 不存在时设置 key 的值。 |
5 | strlen key | 返回 key 所储存的字符串值的长度。 |
6 | incr key | 将 key 中储存的数字值增一。 |
7 | decr key | 将 key 中储存的数字值减一 |
List(列表)
List是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象或者map。Redis中的散列可以看成具有String key和String value的map容器,可以将多个key-value存储到一个key中 。
常见命令:
序列 | 命令 | 描述 |
---|---|---|
1 | llen key | 获取列表长度 |
2 | lpush key value1… value2 | 将一个或多个值插入到列表头部 |
3 | lpop key | 移出并获取列表的第一个元素 |
4 | lrange key start stop | 获取列表指定范围内的元素 |
5 | lrem key count value | 移除列表元素 |
6 | rpush key value1… value2 | 尾部添加 |
7 | rpop key [count] | 尾部移除[count]元素 |
Set(无序列表)
Set列表是string类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。
常见命令:
序列 | 命令 | 描述 |
---|---|---|
1 | sadd key member1… member2 | 向集合添加一个或多个成员 |
2 | scard key | 获取集合的成员数 |
3 | smemebers key | 返回集合中的所有成员 |
4 | sismember key member | 判断member元素是否是集合key的成员 |
5 | spop key | 移除并返回集合中的一个随机元素 |
sorted set(有序列表)
sorted set与普通集合set非常相似,是一个没有重复元素的字符串集合。不同之处是有序集合的每个成员都关联了一个评分(score ) ,这个评分( score )被用来按照从最低分到最高分的方式排序集合中的成员。集合的成员是唯一的,但是评分可以是重复的。
常见命令:
序列 | 命令 | 描述 |
---|---|---|
1 | zadd key score1 member1… score2 member2 | 向有序集合添加一个或多个成员,或者更新已存在成员的分数 |
2 | zcard key | 获取集合的成员数 |
3 | zcount key min max | 计算在有序集合中指定区间分数的成员数 |
4 | zrangebylenx key min max[limit offset count] | 通过字典区间返回有序集合的成员 |
5 | zrem key member1 member2 | 移除有序集合中的一个或多个成员 |
6 | ZREMRANGEBYSCORE key min max | 移除有序集合中给定的分数区间的所有成员 |
7 | zscore key member | 返回有序集中,成员的分数值 |
Hash(哈希表)
Hash是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象或者map。Redis中的散列可以看成具有String key和String value的map容器,可以将多个key-value存储到一个key中。
常见命令:
序列 | 命令 | 描述 |
---|---|---|
1 | hdel key field1 field2… fieldn | 删除一个或多个哈希表字段 |
2 | hexist key field | 查看哈希表 key 中,指定的字段是否存在 |
3 | hget key field | 获取存储在哈希表中指定字段的值 |
4 | hgetall key | 获取在哈希表中指定 key 的所有字段和值 |
5 | hincrby key field increment | 为哈希表 key 中的指定字段的整数值加上增量 increment |
6 | hkeys key | 获取所有哈希表中的字段(field) |
7 | hlen key | 获取哈希表中字段的数量 |
8 | hmget key field1 field2 | 获取所有给定字段的值 |
9 | hset key field value | 将哈希表 key 中的字段 field 的值设为 value 。 |
10 | hsetnx key field value | 只有在字段 field 不存在时,设置哈希表字段的值。 |
11 | hvals key | 获取哈希表中所有值 |
7、跨域的常用解决方案?
1、添加@CrossOrigin
注解实现跨域
@CrossOrigin是用来处理跨源资源共享(CORS)的注解。注解在方法上表示该方法的请求可以跨域,注解在类上表示该类的所有方法的请求都可以跨域。
2、添加一个config类,类实现WebMvcConfigurer 接口,在类中定义能够跨域的请求和url
@Configuration
public class BmWebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("*")
.allowedMethods("GET","POST","PUT","DELETE")
.allowedHeaders("*");
}
}
8、什么是redis的缓存雪崩?如何解决
当某一个时刻出现大规模的缓存失效的情况,那么就会导致大量的请求直接打在数据库上面,导致数据库压力巨大,如果在高并发的情况下,可能瞬间就会导致数据库宕机。这时候如果运维马上又重启数据库,马上又会有新的流量把数据库打死。这就是缓存雪崩。
解决方案:
-
可以设置不同的缓存过期时间,避免所有缓存在同一时间失效,从而减轻数据库的压力。
-
对于一些热点数据,可以设置其永不过期,从而保证其在缓存中一直存在,减少数据库的压力。
-
加入缓存预热机制,缓存预热指的是在系统启动前,将一些常用的数据提前加载到缓存中。这样可以避免在系统运行过程中,缓存失效导致请求落到数据库上。
9、什么是redis的缓存穿透?如何解决
Redis大部分情况都是通过Key查询对应的值,假如发送的请求传进来的key是不存在Redis中的,那么就查不到缓存,查不到缓存就会去数据库查询。假如有大量这样的请求,这些请求像“穿透”了缓存一样直接打在数据库上,这种现象就叫做缓存穿透。
解决方案:
在请求访问redis之前用布隆过滤器进行拦截判断,布隆过滤器判断请求记过不存在,则直接进行拦截,不让请求访问redis,相当于白名单,布隆过滤器判断为false就一定不存在,判断为true也不一定就存在。
10、什么是redis的缓存击穿?如何解决
缓存雪崩是大规模的key失效,而缓存击穿是一个热点的Key,有大并发集中对其进行访问,突然间这个Key失效了,导致大并发全部打在数据库上,导致数据库压力剧增。这种现象就叫做缓存击穿
解决方案:
-
在缓存失效时,通过加锁来保证只有一个请求可以访问数据库。其他请求将等待第一个请求完成后再进行查询。
-
将一些热点数据的key的过期时间设置的长一些。
11、Redis的数据过期策略
redis对有些key都设置了过期时间,时间一到自动删除key,但是redis保存了大量的key,要精准保证每个键的过期删除机制太消耗CPU,这对单线程的redis来说付出的代价比较大,因此Redis采用惰性删除和定时任务删除机制实现过期键的内存回收。
- 惰性删除:
过期的key不删除,当redis读取到这些设用过期时间的key,redis会进行判断,如果超过了key设定的过期时间,会执行删除操作并返回空,这种策略是出于节省CPU成本考虑,不需要单独维护每个键的过期删除机制来处理过期键的删除。
这种机制的优点是删除key只发生在客户端读取到了过期时间的key的时候会发生,所以删除操作占用的cpu会很少,缺点就是若大量的key过期不删除,而且在很长的一段时间都不没有被获取到,这些过期的key会占用大量的内存,导致内存泄漏(无用的垃圾数据占用了大量的内存空间)。正因为如此,Redis还提供另一种定时任务删除机制作为惰性删除的补充。
- 定时任务删除:
Redis内部维护一个定时任务,默认每秒运行10次(根据具体服务器运行情况而定)。定时任务中删除过期键逻辑采用了自适应算法,根据键的过期比例,随机抽取一些设置了过期时间的key,检查是否过期,如果过期就删除。。
这种机制的优点是可以通过控制删除操作的时间和频率,来降低对CPU的占用,相比较key过期就删除的机制来说,对cpu的占用会少。定期删除key可以清除一些无用的垃圾,也并不是所有过期很长时间的key都会被清除,也会有很多会遗漏,这些过期的key没有被删除的也没有走惰性删除,最后也还是会堆积在内存里面,这时候就需要内存淘汰策略了。