1.雪花id
雪花id是什么:snowflake是Twitter开源的分布式ID生成算法,结果是64bit的Long类型的ID,有着全局唯一和有序递增的特点。
缺点是强依赖机器时钟,如果机器上的时钟回拨,有可能会导致主键重复的问题
2、redis数据持久性
(1 RDB持久化,生产某个时间点的快照文件
执行rdb持久化时,redis会fork出一个子进程,子进程将内存中数据写入到一个紧凑的文件中,因此它保存的是某个时间点的完整数据。
redis启动时会从rdb文件中恢复数据到内存,因此回复数据时只需要将redis关闭后,将备份的rdb文件替换当前的rdb文件,再启动redis即可。
优点:
rdb文件体积小,适合备份及传输
性能比aof好(aof需要写入日志文件)
rdb恢复要比aof快
缺点
服务器故障时会丢失最后一次备份之后的数据
redis保存rdb时,fork子进程的这个操作期间,redis服务会停止响应,但如果数据量大且cpu时间紧张,则停止响应的时间可能长大1秒
(2 AOF持久化(append only file):日志追加模式(redis协议格式保存)
aof就是将客户端每一次操作记录追加到指定的aof(日志)文件中,在aof文件体积多大时可以自动在后台重写aof文件(不会影响正常服务,中途磁盘写满或者停机导致失败也不会丢失数据)
aof持久化的fsync策略支持:
fsync:同步内存中所有已经修改的文件数据到存储设备
aof文件过大时会触发自动重写,重写后的新aof文件包含了恢复当前数据集所需最少的命令集合
优点
充分保证数据的持久化,正确的配置一般最多丢失1s的数据
aof文件内容是以redis协议格式保存,易读
缺点
aof文件通常大于rdb文件
速度慢于rdb
重新启动redis时会以极低的概率导致无法将数据集恢复成保存时的原样
3、redis缓存雪崩
redis缓存可以理解为:由于原有的缓存失效,新缓存未到期间,原本应该访问缓存的请求都去查询数据库了,而对数据库cpu和内存造成的巨大压力,严重的会造成数据库宕机,从而形成一系列的连锁反应,造成整个系统崩溃。
解决办法:
加锁(参考链接:(redis分布式锁的原理及代码实现_风幕浦的博客-CSDN博客))或者队列的方式保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的请求并发到底层存储系统上。或者就是将缓存失效时间分散开。
4、redis缓存穿透
指用户查询数据,数据库没有,在缓存中也没有。这样导致用户查询时,缓存找不到,每次都要去数据库查询一遍,然后返回null,这样请求就会绕过缓存直接查数据库。
解决方法:
最常见的就是使用布隆过滤器,将所有可能存在的数据哈希到一个大的bitmap中,一个不存在的数据就会被拦截掉,从而避免了对底层的压力。
或者把这个空结果进行缓存,但过期时间短,最长不超过5分钟。直接把默认值放在缓存,这样第二次缓存中获取就会有值了,而不会访问数据库。
5、redis缓存击穿
redis中一个热点key在失效时,大量的请求过来,从而全部到达数据库,压垮数据库
解决方法:
(1 设置热点数据永不过期
对于某个频繁获取的信息,缓存在redis中,并且设置永不过期。但并不使用所有场景。
(2 定时更新
假如这个数据设定过期时间为1小时,那么每到59分时,通过定时任务去更新这个数据的key,并重新设置过期时间。
(3 互斥锁
这是比较常用的方法
在redis根据key获取的value值为空时,先锁上,然后从数据库加载,加载完毕猴,释放锁,如果其他线程也在请求该key时,发现获取锁失败,则会睡眠一段时间后重试。
6、reids常用的数据类型
String
常规的set/get操作,value可以是String也可以是数字。一般做一些复杂的计数功能的缓存。
hash
这里value存放的是结构化的对象,比较方便的就是操作其中的某个字段。博主在做单点登录的时候,就是用这种数据结构存储用户信息,以cookieId作为key,设置30分钟为缓存过期时间,能很好的模拟出类似session的效果。
list
使用List的数据结构,可以做简单的消息队列的功能。另外还有一个就是,可以利用lrange命令,做基于redis的分页功能,性能极佳,用户体验好。本人还用一个场景,很合适—取行情信息。就也是个生产者和消费者的场景。LIST可以很好的完成排队,先进先出的原则。
set
因为set堆放的是一堆不重复值的集合。所以可以做全局去重的功能。为什么不用JVM自带的Set进行去重?因为我们的系统一般都是集群部署,使用JVM自带的Set,比较麻烦,难道为了一个做一个全局去重,再起一个公共服务,太麻烦了。另外,就是利用交集、并集、差集等操作,可以计算共同喜好,全部的喜好,自己独有的喜好等功能。
sorted set
sorted set多了一个权重参数score,集合中的元素能够按 score进行排列。可以做排行榜应用,取TOP N操作。
7、redis过期策略
redis采用的是定期删除+惰性删除策略。
定期删除,redis默认每100ms检查(不是全部检查,而是随机抽查),是否有过期的key,有则删除。因此会导致很多key没有删除掉,于是就使用惰性删除,在你获取某个key时,redis会先检查是否过期,如果过期了就会删除。
8、跨域的常用解决方案
(1 JSONP(JSON with Padding):JSONP是一种使用<script>标签发起跨域请求的技术。通过动态创建<script>标签,将需要访问的数据作为回调函数的参数传递,从而实现跨域请求。
(2 CORS(跨域资源共享):CORS是一种由服务器端实现的跨域解决方案。通过在服务器的响应头中添加特定的CORS标头,告知浏览器允许特定域名的跨域请求。例如,在响应头中设置"Access-Control-Allow-Origin"标头来指定允许访问的域名。
(3 代理服务器:使用代理服务器是一种常见的跨域解决方案。将跨域请求发送到同源的服务器,然后由服务器代理请求目标资源,并将结果返回给客户端。这种方法需要在服务器端进行配置,但对于客户端来说是透明的。
(4 iframe跨域通信:通过在页面中嵌入隐藏的iframe,来实现跨域通信。通过修改iframe的URL、使用postMessage等方式,可以在不同域名下的页面之间进行数据传递和通信。
(5 WebSocket:WebSocket是一种在单个TCP连接上进行全双工通信的协议,它不受同源策略的限制。通过使用WebSocket,可以在不同域名之间实现实时的双向数据传输。
9、JWT 和 session 的区别
session:
因为http的无状态我们并不能知道是哪个用户发出的请求,所以为了让我们的应用能识别是哪个用户发出的请求。我们只能在服务器存储一份用户登录的信息,这份登录信息会在响应时传递给浏览器并告诉其保存为cookie,以便下次请求时发送给我们的应用,这样我们的应用就能识别请求来自哪个用户了
session的缺点:
第一对服务器的压力大:因为每个用户经过服务器认证之后,服务器都要做一次记录,通常这些记录都是保存在内存中,而随着认证用户的增多,服务器开销会明显增大。
第二程序扩展性变差:用户认证后,服务器做认证记录,如果认证的记录被保存在内存中的话,这意味着用户下次请求还必须在这台服务器上才能拿到授权的资源,这样在分布式的应用上,相应的限制了负载均衡器的能力,也就意味着限制了扩展的能力。
第三安全性偏低:因为是基于cookie来进行用户识别的,cookie如果被截获,用户就会很容易受到跨站请求伪造(CSRF)的攻击。
JWT:
jwt也是基于token的一种方式。为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准,可实现无状态、分布式的Web应用授权(。JWT只需要保存在客户端即可,减少了对服务器的压力。
jwt由三部分组成: Header:头部分通常有两部分组成,一个是使用到的签名算法("HS256"是JWT官方比较推荐的签名算法)一个是令牌的类型(这里目前就一种类型JWT)。
Payload:负载用来存放信息,官网介绍有三部分,这里就先大致理解为存放的是我们需要传递的内容信息,比如“userId, username, age ”之类的信息。
Signature:创建签名,我们在header中指定了一个秘钥,作用就是用来在创建签名的时候进行加密的。
10、JWT的优点
(1 可拓展性好
应用程序分布式部署的情况下,session需要多机共享数据,通常可以存在数据库或者redis里,而jwt不需要。
(2 无状态
jwt不在服务端存储任何状态,RESTful API的原则之一是无状态,发出请求 时,总会返回带有参数的响应,不会产生附加影响。用户的认证状态引入这种附加影响,则破坏了这一原则。另外jwt的载荷中可以存储一些常用信息,用于交换信息。
11、SpringCache的常用注解
1、@EnableCaching
开启spring Cache框架支持。解析对应的注解,实现缓存读写访问
2、@CacheConfig
缓存配置,可以配置当前类型中所用缓存注解的通用信息
3、@Cacheable
表示要对方法返回值进行缓存
例:
//执行方法时,返回结果做缓存
@Cacheable(cacheNames="cache:prefix",key = "'all:values'")
//方法参数id 作为key的一部分,做缓存
@CachePut(key = "'TestServiceImpl:getById:'+#id")
//方法参数id 作为key的一部分,做缓存,方法返回结果为null时,不做缓存
@Cacheable(key = "'testUnless('+#id+')'",unless = "#result==null")
//方法参数id大于0时 作为key的一部分,做缓存
@Cacheable(key = "'TestServiceImpl:getById:'+#id", condition = "#id > 0")
4、@CacheEvict
淘汰缓存注解
//执行方法时,根据key删除缓存
@CacheEvict(allEntries = true)
5、@CachePut
更新缓存,如果key存在覆盖缓存数据。key不存在,新增数据缓存
//方法参数id 作为key的一部分,根据key更新缓存
@CachePut(key = "'TestServiceImpl:getById:'+#id")