redis简介
简单来说 redis 就是一个非关系型数据库,不过与传统数据库不同的是 redis 的数据是存在内存中的,所以读写速度非常快,因此 redis 被广泛应用于缓存方向。
为什么要用redis?
1、一个项目的研发不可能不考虑高性能的问题,频繁的访问数据库中的某些数据。这个过程会比较慢,因为是数据库中的数据都是存在硬盘上的。而redis的数据是存在缓存中的,操作缓存就是直接操作内存,所以速度相当快。这样就提高了整个系统的性能
2、redis能很好的解决高并发的问题,因为缓存所能接受的请求远远大于数据库。
3、redis适用于分布式架构,因为redis 称为分布式缓存,在多实例的情况下,各实例共用一份缓存数据,缓存具有一致性。
理解redis为何那么快
- 编程语言: Redis使用C语言编写的,更接近底层,可以直接调用OS函数
- 基于内存:Redis的数据都是放在内存的,所以更快。
- 单线程: Redis是单线程的,避免了线程切换的消耗,也不会有竞争,所以更快。
- 网络模型:Redis的网络模型是epoll,是多路复用的网络模型。
- Redis数据结构的优化:Redis中提供了5种数据类型,其中zset用跳表做了优化,而Redis整个其实也都使用hash做了优化,使其的时间成本是O(1),查找更快。
- Redis6.0推出了I/O Threads ,所以更快。
redis 和 memcached 的区别
对于 redis 和 memcached 我总结了下面四点。现在公司一般都是用 redis 来实现缓存,而且 redis 自身也越来越强大了!
1、redis支持更丰富的数据类型(支持更复杂的应用场景):Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,zset,hash等数据结构的存储。memcache支持简单的数据类型,String。
2、Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用,而Memecache把数据全部存在内存之中。
3、集群模式:memcached没有原生的集群模式,需要依靠客户端来实现往集群中分片写入数据;但是 redis 目前是原生支持 cluster 模式的.
4、Memcached是多线程,非阻塞IO复用的网络模型;Redis使用单线程的多路 IO 复用模型。
利用redis实现分布式锁
可解决幂等性问题
通俗的说就是一个接口, 多次发起同一个请求, 必须保证操作只能执行一次
相比于单个jvm的多线程的情况下多jvm实现线程的同步就不能靠加线程锁来解决线程的同步问题了。这时我们就需要把锁抽取出来,让线程们在同一片内存相遇。但锁是不能凭空存在的,本质还是要在内存中,此时可以使用Redis缓存作为锁的宿主环境,这就是Redis能构造分布式锁的原因。
采用 redis 实现分布式锁,主要是利用其单线程命令执行的特性,一般是 setnx, 只会有一个线程会执行成功,也就是只有一个线程能成功获取锁。
加锁实际上就是在redis中,给Key键设置一个值,为避免死锁,并给定一个过期时间。
SET lock_key random_value NX PX 5000
random_value
是客户端生成的唯一的字符串在解锁时需要。NX
代表只在键不存在时,才对键进行设置操作。PX 5000
设置键的过期时间为5000毫秒。
这样,如果上面的命令执行成功,则证明客户端获取到了锁。
解锁的过程就是将Key键删除。但也不能乱删,不能说客户端1的请求将客户端2的锁给删除掉。这时候random_value
的作用就体现出来。先判断当前锁的字符串是否与传入的值相等,是的话就删除Key,解锁成功。
但是利用redis做分布式锁有许多缺陷
如:
锁未被释放:由于当前线程 获取到redis
锁,处理完业务后未及时释放锁,导致其它线程会一直尝试获取锁阻塞
B的锁被A给释放了:线程A在锁过期的时间前还没有释放锁,此时A线程的锁呗自动释放,此时线程B可以拿到锁,但是当A线程执行完后也会去释放锁,这样就会造成线程B的锁被线程A释放。
等问题。
此外也可以
通过Zookeeper生成的临时顺序节点来实现分布式锁。
通过数据库的乐观锁,包括主键防重,版本号控制。但是这两种方法各有利弊。