掘金 后端 ( ) • 2024-04-26 17:59

Redis存储方式大揭秘,让你的数据飞上天!

哟,听说你最近的项目数据存储遇到了困难?那些老掉牙的关系型数据库已经跟不上你的脚步了?别怕,Redis来了!这位数据存储界的"网红",绝对能让你的数据嗨起来!

Redis这家伙啊,就是一个高性能的key-value内存数据库。它凭什么这么牛?就凭它那恐怖的读写速度和花里胡哨的数据类型!今天,咱们就一起扒一扒Redis存储方式的底裤,看看它是怎么让你的数据又快又好存的!

内存存储,就是这么任性!

Redis的第一大特点,那就是内存存储!没错,你的数据在Redis里,就是直接住在内存里的!这意味着什么?这意味着Redis读写数据快得一批!

想想看,硬盘IO速度才100MB/s左右,而内存IO速度可以达到几十GB/s!这差距,不是一般的大啊!所以,当Redis处理海量数据的读写请求时,那速度,嗖嗖的,眨眼间就完事了!

举个例子,假设你的应用需要频繁地读取用户的基本信息。如果你把这些信息存在MySQL里,每次读取都得走一遍硬盘IO,那性能肯定上不去。但如果你把这些信息缓存在Redis里,读取速度那是杠杠的,啥时延都别想有!

当然,内存存储也不是完美无缺的。内存容量不够大,价格又贵。但Redis早就想到了这茬,它提供了一些机制来解决这些问题,比如数据淘汰策略和数据持久化,咱们一会儿再说。

数据类型,花样百出!

Redis的另一大亮点,就是它那花里胡哨的数据类型支持。别的key-value存储,通常就只支持简单的字符串类型。但Redis可不是吃素的,它的数据类型,那是相当丰富:

  • 字符串(String):这是最基础的类型,就像Memcached一样,一个key对一个value。
  • 哈希(Hash):这个类型有点儿像Java里的Map,一个key对应一个Map。
  • 列表(List):这个类型就像一个双向链表,你可以在列表的头部或尾部添加元素。
  • 集合(Set):这个类型跟Java中的HashSet差不多,它里面的键值对是无序且唯一的。
  • 有序集合(Sorted Set):这个类型跟Set类似,但里面的元素是有序的,每个元素都有一个分数(score)来排序。

有了这一箩筐数据类型,Redis就成了一个"多面手",啥业务场景都能应对。

比如,你可以用String来缓存一些常用的对象,提高系统的响应速度:

// 将用户对象缓存到Redis
User user = new User(1, "Tom", 25);
String key = "user::" + user.getId();
redisTemplate.opsForValue().set(key, JSON.toJSONString(user));
​
// 从Redis获取用户对象
String userJson = redisTemplate.opsForValue().get(key);
User cachedUser = JSON.parseObject(userJson, User.class);

又比如,你可以用Hash来存储一个用户的详细信息:

// 存储用户信息到Hash
String userKey = "user::" + userId;
redisTemplate.opsForHash().put(userKey, "name", "Tom");
redisTemplate.opsForHash().put(userKey, "age", 25);
redisTemplate.opsForHash().put(userKey, "city", "New York");
​
// 获取用户信息从Hash
String name = (String) redisTemplate.opsForHash().get(userKey, "name");
int age = (int) redisTemplate.opsForHash().get(userKey, "age");
String city = (String) redisTemplate.opsForHash().get(userKey, "city");

再比如,你可以用List来实现一个简单的队列:

// 添加元素到队列
redisTemplate.opsForList().leftPush("queue", "task1");
redisTemplate.opsForList().leftPush("queue", "task2");
​
// 从队列获取元素
String task = redisTemplate.opsForList().rightPop("queue");

或者,你可以用Set来实现一个标签系统:

// 添加标签
redisTemplate.opsForSet().add("tags::user::1", "music", "movie", "travel");
redisTemplate.opsForSet().add("tags::user::2", "music", "sports");
​
// 获取共同的标签
Set<String> commonTags = redisTemplate.opsForSet().intersect("tags::user::1", "tags::user::2");

还有啊,你可以用Sorted Set来实现一个排行榜功能:

// 添加分数
redisTemplate.opsForZSet().add("leaderboard", "player1", 100);
redisTemplate.opsForZSet().add("leaderboard", "player2", 90);
redisTemplate.opsForZSet().add("leaderboard", "player3", 110);
​
// 获取排名
long rank = redisTemplate.opsForZSet().reverseRank("leaderboard", "player2");

看看,Redis的应用场景,是不是相当丰富?

数据淘汰,优胜劣汰!

咱们刚说了,内存存储的一个问题是容量有限。那Redis咋解决这个问题呢?答案就是:数据淘汰策略!

当Redis的内存使用到了某个程度,它就会自动触发数据淘汰机制。Redis有一堆数据淘汰策略让你挑:

  • volatile-lru:在设置了过期时间的数据中,挑最近最少使用的数据淘汰。
  • volatile-ttl:在设置了过期时间的数据中,挑快要过期的数据淘汰。
  • volatile-random:在设置了过期时间的数据中,随便挑数据淘汰。
  • allkeys-lru:在所有数据中,挑最近最少使用的数据淘汰。
  • allkeys-random:在所有数据中,随便挑数据淘汰。
  • noeviction:不淘汰数据,内存不够时,新写入操作会报错。

你可以根据自己的业务特点,选一个合适的淘汰策略。比如,如果你的数据都能再次获取,那选allkeys-lru就不错;如果你有一些"热点数据",那就用volatile-lru,优先保证这些数据在内存里常驻。

举个例子,如果你用Redis缓存用户信息,你可能希望经常访问的活跃用户的信息能够常驻内存,不那么活跃的用户的信息就不那么care了。这时候,你就可以这样设置:

# 设置淘汰策略为volatile-lru
redis-cli config set maxmemory-policy volatile-lru
​
# 设置key的过期时间
redis-cli expire user::1 3600
redis-cli expire user::2 7200

这样,Redis就会在内存不够时,优先淘汰那些不怎么访问的用户信息,保留活跃用户的信息在内存中。是不是很智能?

数据持久化,安全第一!

除了数据淘汰策略,Redis还提供了数据持久化功能,保证数据安全。Redis的持久化有两种方式:RDB和AOF。

RDB(Redis Database)就是每隔一段时间,把内存中的数据快照写到磁盘上。这玩意儿默认就开启了,你可以设置自动备份的时间和文件名。RDB的好处是备份速度快,适合定期备份;坏处是两次备份之间如果出问题,可能会丢点数据。

你可以在redis.conf里设置RDB:

# 900秒内如果至少有1个key被修改,则执行bgsave (background save)
save 900 1  
​
# 300秒内如果至少有10个key被修改,则执行bgsave  
save 300 10
​
# 60秒内如果至少有10000个key被修改,则执行bgsave
save 60 10000

AOF(Append Only File)则是把Redis的操作日志追加写到文件里。每次有写操作,AOF就会同步地把操作写到硬盘上的AOF文件里。AOF的好处是最大限度保证数据不丢,坏处是备份文件可能很大,恢复速度也没RDB快。

你也可以在redis.conf里设置AOF:

# 开启AOF
appendonly yes
​
# AOF文件名
appendfilename "appendonly.aof"
​
# 同步策略,这里是每秒同步一次
appendfsync everysec

实际用的时候,你可以根据自己的业务需求选RDB还是AOF,甚至可以两个一起用,既保证数据安全,又兼顾性能。比如,你可以这样设置:

# 开启RDB
save 900 1
save 300 10
save 60 10000
​
# 开启AOF
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec

这样,Redis就会既有RDB的快照,又有AOF的操作日志,双保险,数据更安全!

小结

Redis凭借其飞快的性能和一大票功能,已经成了互联网应用必备的神器。今天咱们主要扒了Redis的几大存储特性:内存存储、数据类型支持、数据淘汰策略和数据持久化。

希望通过这篇文章,你对Redis的存储方式有了更深入的了解。Redis简单易用,但也有很多需要注意的地方,比如数据淘汰策略的选择,持久化方式的权衡等等。

当然,Redis的精彩远不止这些,它还有很多高级特性等着你去发现,比如主从复制、哨兵机制、集群模式等等。这些都是优秀的分布式解决方案,能让你的应用更稳定,更高可用。

让咱们一起潜入Redis的世界,用Redis的力量来武装我们的应用吧!相信有了Redis这个大杀器,你的项目绝对能更上一层楼!还等啥,快去撸代码吧!