一个项目笔记

本文深入探讨了MySQL的存储引擎InnoDB,强调了事务的ACID特性及四种隔离级别,详细阐述了锁的类型及其在并发控制中的作用。此外,还介绍了Redis的过期策略和淘汰策略,以及如何应对缓存穿透、缓存击穿和缓存雪崩的问题。最后,讨论了分布式锁的概念和实现方式,特别是Redis在实现分布式锁中的角色和策略。
摘要由CSDN通过智能技术生成

MySQL

存储引擎

MySQL是一个基于存储引擎的数据库,有许多存储引擎供我们选择。由于InnoDB支持事务,所以我们选择这个存储引擎,并将其设置为默认的,它也支持外键。

事务

事务的特性

原子性
一致性
隔离性
永久性

事务的隔离级别

并发异常:第一类丢失更新、第二类丢失更新、脏读、不可重复读、幻读
隔离级别:Read Unicommitted  Read Committed  Repeatable Read  Serializable

要实现隔离性就需要加锁
从范围上来看,MySQL的锁分为两种:

·表级锁:开销小,加锁快,发生锁冲突的概率高、并发度低、不会出现死锁
·行级锁:开销大、加锁慢、发生锁冲突的概率低、并发度高、会出现死锁

对InnoDB来讲

	·共享锁(S):行级,读取一行;
	·排他锁(X):行级,更新一行;
	·意向共享锁(IS):表级,准备加共享锁;
	·意向排他锁(IX):表级,准备加排他锁;
	·间隙锁(NK):行级,使用范围条件时,对范围内不存在的记录加锁。一是为了防止幻读,二是为了满足恢复和复制需要。

列表示事务一,行表示事务二,事务一加了某个锁之后事务二能加什么锁
列表示事务一,行表示事务二,事务一加了某个锁之后事务二能加什么锁:

第一行中:事务一加了意向共享锁(IS)(准备读),事务二不能加排他锁(X),也就是说我想读取表中的某一行数据,那么事务二不能加排他锁,因为别人正在读,他不能写;
第二行中:事务一加了意向排他锁(准备写),那么事务二不能加共享锁和排他锁(不能读不能写,可以准备读,准备写)
第三行,事务一加了共享锁(正在读),那么事务二不能加排他锁和意向排他锁(不能写也不能准备写,可以准备读或读)
第四行,事务一加了排他锁,事务二什么也不能做。

加锁

·增加行级锁之前,InnoDB会自动给表加意向锁
·执行DML语句时,InnoDB会自动给数据加排他锁
·执行DQL语句时,
		共享锁(S):SELECT ...FROM ... WHERE ... LOCK IN SHARE MODE
		排他锁(X):SELECT ...FROM ... WHERE ... FOR UPDATE
		间隙锁(NK):上述SQL采用范围条件时,InnoDB对不存在的记录自动增加间隙锁

死锁
·场景
事务1:UPDATE T SET … WHERE ID=1;UPDATE T SET … WHERE ID=2;
事务2:UPDATE T SET … WHERE ID=2;UPDATE T SET … WHERE ID=1;
·解决方案
1.一般InnoDB会自动检测到,并使一个事务回滚,另一个事务继续
2.设置超时等待参数,innodb_lock_wait_timeout;
·避免死锁
1.不同的业务并发访问多个表时,应约定以相同的顺序来访问这些表
2.以批量的方式处理数据时,应事先对数据排序,保证线程按固定的顺序来处理数据;
3.在事务中,如果要更新记录,应直接申请足够级别的锁,即排他锁

MySQL加的锁都是悲观锁,认为一定会出问题
乐观锁需要自定义

1.版本号机制
	UPDATE ... SET ...,VERSION=#{version+1} WHERE ... AND VERSION=${version}
2.CAS算法(compare and swap)
是一种无锁算法

索引

B+Tree(InnoDB)

·数据分块存储,每一块称为一页
·所有的值都是按顺序存储的,并且每一个叶子到根的距离相同
·非叶节点存储数据的边界,叶子节点存储只想数据行的指针
·通过边界缩小数据的范围,从而避免全表的扫面,加快了查找的速度

Redis

常见数据类型

在这里插入图片描述

过期策略

Redis会把设置过期时间的key放入一个独立的字典里,在key过期时并不会立刻删除它,会有两种策略来删除过期的key:
·惰性删除
客户端访问某个key时,Redis会检查该key是否过期,若过期则删除
·定期扫描
Redis默认每秒执行10次过期扫描(配置hz选项),扫描策略如下:
1.从过期字典中随机选择20个key
2.删除这20个key中已过期的key
3.如果过期的key的比例超过25%,则重复步骤1

淘汰策略

当Redis占用的内存超出最大限制(maxmemory)时,可采用如下策略(maxmemory-policy),让Redis淘汰一些数据,以腾出空间继续提供读写服务:
·noeviction:对可能导致增大内存的命令返回错误(大多数写命令。DEL除外);
·voltile-ttl:在设置了过期时间key中,选择剩余寿命(TTL)最短的key,将其淘汰;
·volatile-lru:在设置了过期时间key中,选择最少使用的key,将其淘汰;
·volatile-random:在设置了过期时间的key中,随机选择一些key,将其淘汰;
·allkeys-lru:在所有的key中,选择最少使用的key***(LRU)***,将其淘汰;
·allkeys-random:在所有的key中,随机选择一些key,将其淘汰。

在这里插入图片描述

缓存穿透

·场景
查询根本不存在的数据,使得请求直达存储层导致其负载过大,甚至宕机。
·解决方案
1.缓存空对象
	存储层未命中后,仍然将空值存入缓存层。再次访问该数据,缓存层会直接返回空值。
2.布隆过滤器
	将所有存在的key提前存入布隆过滤器,在访问缓存层之前,先通过过滤器拦截,若请求的是不存在的key,则直接返回值。

在这里插入图片描述

缓存击穿

·场景
一份热点数据,他的访问量非常大。在其缓存瞬间失效的瞬间,大量请求直达存储层,导致服务崩溃。
·解决方案
1.加互斥锁
对数据的访问加互斥锁,当一个线程访问该数据时,其他线程只等待,这个线程访问过后,缓存中的数据将被重建,届时其他线程就可以直接从缓存取值。
2.永不过期
不设置过期时间,所以不会出现上述问题,这是物理上的不过期,为每个value设置逻辑过期时间,当发现该值逻辑过期时,用单独的线程重建缓存。

缓存雪崩

·场景
由于某些原因,缓存层不能提供服务,导致所有的请求直达存储层,造成存储层宕机。
·解决方案
1.避免同时过期
设置过期时间时,附加一个随机数,避免大量的key同时过期。
2.构建高可用的Redis缓存
部署多个Redis实例,个别节点宕机,依然可以保持服务的整体可用。
3.构建多级缓存
增加本地缓存,在存储层前面多加一-级屏障,降低请求直达存储层的几率。
4.启用限流和降级措施
对存储层增加限流措施,当请求超出限制时,对其提供降级服务。

分布式锁

·场景
修改时,经常需要先将数据读取到内存,在内存中修改后再存回去。在分布式应用中,可能多个进程同时执行上述操作,而读取和修改非原子操作,所以会产生冲突。增加分布式锁,可以解决此类问题。
·基本原理
同步锁:在多个线程都能访问到的地方,做一个标记,标识该数据的访问权限。
分布式锁:在多个进程都能访问到的地方,做一个标记,标识该数据的访问权限。
·实现方式
1.基于数据库实现分布式锁;
2.基于Redi s实现分布式锁;
3.基于zookeepe r实现分布式锁;

Redis实现分布式锁的原则
1.安全属性:独享。在任一-时刻,只有一一个客户端持有锁。
2.活性A:无死锁。即便持有锁的客户端崩溃或者网络被分裂,锁仍然可以被获取。
3.活性B:容错。只要大部分Redis节点都活着,客户端就可以获取和释放锁。

单Redis实例实现分布式锁 
1.获取锁使用命令: 
SET resource name my random value NX PX 30000 
NX:仅在key不存在时才执行成功。PX: 设置锁的自动过期时间。 
2.通过Lua脚本释放锁:
if redis.call ("get", KEYS[1]) == ARGV[1] then
	return redis.call ("del",KEYS[1] )
else return 0 end
可以避免删除别的客户端获取成功的锁:
A加锁->A阻塞->因超时释放锁->B加锁->A恢复->释放锁

多Redi s实例实现分布式锁
Redlock算法,该算法有现成的实现,其Java版本的库为Redisson。
1.获取当前Unix时间,以毫秒为单位。
2.依次尝试从N个实例,使用相同的key和随机值获取锁,并设置响应超时时间。如果服务器没有在规定时间内响应,客户端应该尽快尝试另外一个Redis实例。
3.客户端使用当前时间减去开始获取锁的时间,得到获取锁使用的时间。当且仅当大多数的Redis节点都取到锁,并且使用的时间小于锁失效时间时,锁才算取得成功。
4.如果取到了锁,key的真正有效时间等于有效时间减去获取锁使用的时间。
5.如果获取锁失败,客户端应该在所有的Redi s实例上进行解锁。

Spring

Spring IOC

在这里插入图片描述

Spring AOP

在这里插入图片描述

Spring MVC

整个SpringMVC处理请求的过程
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值