1.缓存穿透:
请求查询不存在的数据,由于缓存不命中,每次请求都会直接查询数据库,导致数据库压力过大;
避免办法:
缓存空对象,将查询为空的结果缓存一段时间,避免多次查询数据库
使用布隆过滤器,快速判断一个元素是否存在于一个集合中,可以在缓存就过滤掉请求不存在的数据
2.缓存雪崩:
指缓存大量数据同时失效,导致大量请求直接访问数据库,导致数据库压力过大
避免办法:
将不同的缓存数据设置不同的过期时间
使用分布式缓存,将缓存分散在多台缓存服务器上,避免单点故障导致大规模缓存失效
3. 缓存击穿:
指一个热点数据失效,导致大量请求同时涌入数据库
避免办法:
使用互斥锁,在缓存失效的瞬间,只允许一个请求去查询数据库,其他请求等待
使用热点数据永不过期,或设置较长的过期时间
当redis使用的内存超过了设置的最大内存,会触发redis的淘汰机制,而将机制设置为allkeys-lru时能保证redis中存储的数据都是热点数据
CONFIG SET maxmemory-policy allkeys-lru
LRU(Least Recently Used,最近一段时间没有访问过) 、TTL(过期时间)、LFU(Least Frequently Used,最近一段时间最少访问)
1. noeviction:当内存使用超过配置的时候会返回错误,不会驱逐任何键
2. allkeys-lru:加入键的时候,如果过限,首先通过LRU算法驱逐最久没有使用的键
3. volatile-lru:加入键的时候如果过限,首先从设置了过期时间的键集合中驱逐最久没有使用的键
4. allkeys-random:加入键的时候如果过限,从所有key随机删除
5. volatile-random:加入键的时候如果过限,从过期键的集合中随机驱逐
6. volatile-ttl:从配置了过期时间的键中驱逐马上就要过期的键
7. volatile-lfu:从所有配置了过期时间的键中驱逐使用频率最少的键
8. allkeys-lfu:从所有键中驱逐使用频率最少的键
当我们在使用分布式缓存时可能引发以下问题:
同一份数据可能在多个redis数据库造成数据冗余
无法保证对相同key的所有访问都发送到相同redis中
为了解决上述问题,最初我们使用hash算法,用hash值来指定数据保存在哪个redis数据库中,但是又存在着扩展性和容错性的问题,当服务器增加或减少时都需要重新计算hash值
容错性是指当系统中的某个服务出现问题时,不能影响其他系统;扩展性是指当加入新的服务器后,整个系统能正确高效运行。
一致性哈希就是将整个哈希空间组织成一个圆环,服务器在上面是一个个节点,数据也在环上,然后数据会顺时针存到距离最近的节点,一致性哈希的可扩展性和容错性都比较好,但是存在资源倾斜的问题,可以用过映射虚拟节点解决
哈希槽是一种数据分片的方法,用于分布式储存系统中实现负载均衡和高可用性,其基本思想是将整个哈希值空间划分为固定数量的槽,每个槽对应一个服务器节点,当需要储存或者查找一个键值对时,先对键值对进行哈希运算,根据哈希值找到对应的槽,再访问槽上的服务器节点
- 同步操作是顺序执行的,一个任务完成后才会执行下一个任务,而异步操作允许任务的提交和执行是独立的。
- 同步操作可能会阻塞后续任务的执行,而异步操作可以提高系统的并发性和响应性。
- 同步操作通常用于需要顺序执行、保证顺序一致性的场景,而异步操作通常用于提高系统性能、处理耗时操作的场景。
1.继承Thread类
2.实现Runnable接口
3.实现Callable接口,匿名类继承Thread
4.线程池创建
排序二叉树每个节点的值大于其左子树所有节点的值并小于其右子树所有节点的值
前序遍历:根左右
中序遍历:左根右
后序遍历:左右根
// 中序遍历
public void inorderTraversal(TreeNode root) {
if (root == null) {
return;
}
inorderTraversal(root.left);
System.out.print(root.val + " ");
inorderTraversal(root.right);
}
// 前序遍历
public void preorderTraversal(TreeNode root) {
if (root == null) {
return;
}
System.out.print(root.val + " ");
preorderTraversal(root.left);
preorderTraversal(root.right);
}
// 后序遍历
public void postorderTraversal(TreeNode root) {
if (root == null) {
return;
}
postorderTraversal(root.left);
postorderTraversal(root.right);
System.out.print(root.val + " ");
}
脏读:
一个事务读取到了另一个未提交的事务所做的修改,从而导致读取到了不一致或错误的数据
幻读:
是在同一个事务中,多次执行相同的查询语句,但得到的结果集却不同。
不可重复读:
在同一个事务中,多次读取同一条数据时,得到的结果不一致
第一类丢失更新:
撤销一个事务的时候,把其它事务已提交的更新数据覆盖了;(回滚丢失)
第二类丢失更新:
当两个事务同时更新同一数据时,后提交的事务的更新覆盖了先提交的事务的更新,从而导致了数据的丢失
READ_UNCOMMITTED:读未提交,什么问题都无法解决,效率最高
READ_COMMITTED:读已提交,可以解决脏读问题
REPEATABLE_READ:可重复读,可以解决脏读、不可重复读的问题
SERIALIZABLE:可序列化,最高级别,解决所有问题,但是效率最低