【深入浅出Redis 一】从版本特性到数据类型到线程模型,带你了解Redis的核心特性和应用场景!

欢迎来访小酒关于Redis的解读

是时候花一些时间整理整理了,我们好像从来都没有时间,好像时间一直都在那……

目录

Redis简介

Redis版本特性

Redis常用命令

三个框架

Redis和Memcached的区别

Redis使用场景(用在哪合适?)

Redis数据类型

Redis线程模型

多线程工作模型

单线程模型为什么效率会高

下面给大家介绍下redis,并带大家深入浅出redis的特性,特别是应用场景,也就是我们为什么要用redis?怎么用?什么时候用?

Redis简介

先了解下Redis的一些基础知识和特性,Redis是一个开源的,基于内存的高性能键值数据库。它支持多种数据类型,如字符串、列表、集合、散列、有序集合等等。Redis具有以下特点:

  • 高性能:Redis可以处理每秒数十万次的读写操作,因为它将所有数据存储在内存中,避免了磁盘I/O的开销。
  • 持久化:Redis可以将内存中的数据定期保存到磁盘中,或者将每次修改操作追加到日志文件中,以实现数据的持久化。这样,即使发生系统崩溃或重启,也可以恢复数据。
  • 主从复制:Redis支持主从复制模式,即一个主节点可以有多个从节点,从节点可以接收主节点的数据更新,并提供读服务。这样可以提高数据的可用性和扩展性。
  • 分布式:Redis支持分布式环境下的数据分片和负载均衡,通过一致性哈希算法将数据分配到不同的节点上,以实现水平扩展。
  • 事务:Redis支持事务功能,即可以将多个命令打包成一个原子操作,要么全部执行成功,要么全部失败。Redis的事务不支持回滚,也不保证隔离性。
  • 发布订阅:Redis支持发布订阅模式,即一个发布者可以向一个或多个频道发送消息,一个或多个订阅者可以接收特定频道的消息。这样可以实现消息的异步通信和广播。

redis性能极高 – Redis 能读的速度大概是 110000 次/s,写的速度大概是 81000 次/s

Redis版本特性

  • Redis 4.0:支持模块化扩展,增加了LFU缓存策略,改进了AOF重写机制,增加了混合持久化模式等。
  • Redis 5.0:支持Stream数据类型,增加了集群管理工具,改进了RDB和AOF的兼容性,增加了客户端缓存等。
  • Redis 6.0:支持多线程IO,增加了ACL访问控制,支持SSL/TLS加密,增加了客户端跟踪等。

Redis常用命令

Redis提供了丰富的命令来操作不同类型的数据。以下是一些常用命令的示例:

  • 字符串:SET key value 设置一个键值对;
    • GET key 获取一个键对应的值;
    • DEL key 删除一个键;
    • INCR key 将一个键对应的值增加1;
    • APPEND key value 将一个值追加到一个键对应的值后面。
  • 列表:LPUSH key value 将一个值插入到一个键对应的列表头部;
    • RPUSH key value 将一个值插入到一个键对应的列表尾部;
    • LPOP key 弹出并返回一个键对应的列表头部的值;
    • RPOP key 弹出并返回一个键对应的列表尾部的值;
    • LRANGE key start stop 返回一个键对应的列表中指定范围内的元素。
  • 集合:SADD key value 将一个值添加到一个键对应的集合中;
    • SREM key value 将一个值从一个键对应的集合中移除;
    • SISMEMBER key value 判断一个值是否属于一个键对应的集合;
    • SMEMBERS key 返回一个键对应的集合中所有元素;
    • SINTER key1 key2 ... 返回多个键对应的集合的交集。
  • 散列:HSET key field value 将一个字段和值设置到一个键对应的散列中;
    • HGET key field 获取一个键对应的散列中指定字段的值;
    • HDEL key field 删除一个键对应的散列中指定字段;
    • HGETALL key 返回一个键对应的散列中所有字段和值;
    • HINCRBY key field increment 将一个键对应的散列中指定字段的值增加指定数值。
  • 有序集合:ZADD key score value 将一个分数和值添加到一个键对应的有序集合中;
    • ZREM key value 将一个值从一个键对应的有序集合中移除;
    • ZRANK key value 返回一个值在一个键对应的有序集合中的排名(从小到大);
    • ZREVRANK key value 返回一个值在一个键对应的有序集合中的排名(从大到小);
    • ZRANGE key start stop 返回一个键对应的有序集合中指定范围内的元素(按分数从小到大排序);
    • ZREVRANGE key start stop 返回一个键对应的有序集合中指定范围内的元素(按分数从大到小排序)。

其他常用命令

dbsize 返回当前数据库 key 的数量。

# info 返回当前 redis 服务器状态和一些统计信息。

# monitor 实时监听并返回redis服务器接收到的所有请求信息。

# shutdown 把数据同步保存到磁盘上,并关闭redis服务。

# config get parameter 获取一个 redis 配置参数信息。(个别参数可能无法获取)

# config set parameter value 设置一个 redis 配置参数信息。(个别参数可能无法获取)

# config resetstat 重置 info 命令的统计信息。(重置包括:keyspace 命中数、 # keyspace 错误数、 处理命令数,接收连接数、过期 key 数)

# debug object keyg获取一个 key 的调试信息。

# debug segfault 制造一次服务器当机。

# flushdb 删除当前数据库中所有 key,此方法不会失败。小心慎用

# flushall 删除全部数据库中所有 key,此方法不会失败。小心慎用

工具命令

#redis-server:Redis 服务器的 daemon 启动程序

#redis-cli:Redis 命令行操作工具。当然,你也可以用 telnet 根据其纯文本协议来操作 #redis-benchmark:Redis 性能测试工具,测试 Redis 在你的系统及你的配置下的读写性能 $redis-benchmark -n 100000 –c 50 #模拟同时由 50 个客户端发送 100000 个 SETs/GETs 查询

#redis-check-aof:更新日志检查

#redis-check-dump:本地数据库检查

安装命令

redis下载地址:https://github.com/MicrosoftArchive/redis/releases

到redis目录下执行:redis-server.exe --service-install redis.windows.conf --loglevel verbose

启动服务:redis-server.exe  --service-start

关闭服务:redis-server.exe  --service-stop

登录:redis-cli.exe -h 127.0.0.1 -p 6379

查看密码:config get requirepass

设置密码:config set requirepass xxxx

生效密码:auth xxxx

查看信息:info

查看memory信息:info memory

永久生效,设置到文件中,config rewrite

具体栗子等会去应用场景看~~

三个框架

Jedis:是Redis的Java实现客户端,提供了比较全面的Redis命令的支持,

Redisson:实现了分布式和可扩展的Java数据结构。

Lettuce:高级Redis客户端,用于线程安全同步,异步和响应使用,支持集群,Sentinel,管道和编码器。

 各自的优点

  Jedis:比较全面的提供了Redis的操作特性,使用阻塞的I/O,且其方法调用都是同步的,程序流需要等到sockets处理完I/O才能执行,不支持异步。Jedis客户端实例不是线程安全的,所以需要通过连接池来使用Jedis。

  Redisson:促使使用者对Redis的关注分离,提供很多分布式相关操作服务,例如,分布式锁,分布式集合,可通过Redis支持延迟队列;它是基于Netty框架的事件驱动的通信层,其方法调用是异步的。Redisson的API是线程安全的,所以可以操作单个Redisson连接来完成各种操作

  Lettuce:主要在一些分布式缓存框架上使用比较多;基于Netty框架的事件驱动的通信层,其方法调用是异步的。Lettuce的API是线程安全的,所以可以操作单个Lettuce连接来完成各种操作

建议使用:Jedis + Redisson

Redis和Memcached的区别

Redis和Memcached都是基于内存的高性能键值数据库,但是它们也有一些区别,主要体现在以下方面:

  • 数据类型:Redis支持多种数据类型,如字符串、列表、集合、散列、有序集合等,而Memcached只支持字符串类型
  • 持久化:Redis可以将内存中的数据定期保存到磁盘中,或者将每次修改操作追加到日志文件中,以实现数据的持久化。而Memcached不支持持久化,一旦服务器重启或崩溃,所有数据都会丢失
  • 主从复制:Redis支持主从复制模式,即一个主节点可以有多个从节点,从节点可以接收主节点的数据更新,并提供读服务。而Memcached不支持主从复制,每个节点都是独立的,没有数据同步机制
  • 分布式:Redis支持分布式环境下的数据分片和负载均衡,通过一致性哈希算法将数据分配到不同的节点上,以实现水平扩展。而Memcached也支持分布式环境下的数据分片,但是需要客户端来实现一致性哈希算法,并且没有负载均衡机制
  • 事务:Redis支持事务功能,即可以将多个命令打包成一个原子操作,要么全部执行成功,要么全部失败。而Memcached不支持事务功能,每个命令都是独立的,并且没有回滚机制
  • 发布订阅:Redis支持发布订阅模式,即一个发布者可以向一个或多个频道发送消息,一个或多个订阅者可以接收特定频道的消息。而Memcached不支持发布订阅模式,没有消息通信机制

Redis使用场景(用在哪合适?)

基于上面这些特点,它可以应用于很多场景,例如:

  • 缓存:Redis可以作为缓存层来提高系统的响应速度和吞吐量,减少数据库的压力。例如可以将热点数据、静态资源、计算结果等缓存在Redis中,以提供快速访问、发短信1分钟内不可重复发送限制
  • 分布式锁,分布式锁可以用setNx来实现,注意分布式锁的写法要有过期时间,并在finally中判断if(true)再删除锁,最好用Redission的看门狗
  • 排行榜:Redis可以利用有序集合类型来实现排行榜功能,例如可以根据用户的积分、点击量、销量等指标来排序,并实时更新排名。举个简单的栗子

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
@Component
public class RankingService {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 更新排行榜
     * @param userNames 要更新的用户名列表
     * @param score 要增加的分数
     */
    public void updateRanking(List<String> userNames, int score) {
        Set<String> keys = userNames.stream().map(userName -> "ranking:" + userName).collect(Collectors.toSet());
        redisTemplate.opsForZSet().add(keys, score, System.currentTimeMillis() + 1000); // 设置过期时间,避免内存泄漏
    }
}

@Autowired
private RankingService rankingService;
public void updateScore() {
    List<String> userNames = Arrays.asList("user1", "user2", "user3"); // 要更新的用户名列表
    int score = 100; // 要增加的分数
    rankingService.updateRanking(userNames, score); // 更新排行榜
}
  • 计数器:Redis可以利用字符串类型或散列类型来实现计数器功能,例如,可以记录用户的登录次数、文章的浏览量、商品的库存量等等,并提供原子操作和过期机制。举个简单的栗子
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
@Component
public class Counter {
    @Autowired
    private RedisTemplate<String, Long> redisTemplate;    

    // 设置一个计数器,键为user_id,初始值为0
    public void set(String key, long value) {
        redisTemplate.opsForValue().set(key, value);
    }
    // 增加计数器的值
    public void incr(String key) {
        redisTemplate.opsForValue().increment(key);
    }
    // 获取计数器的值
    public long get(String key) {
        return (long)redisTemplate.opsForValue().get(key);
    }
}

public static void main(String[] args) throws Exception {
    Counter counter = new Counter();
    // 设置一个计数器,键为user_id,初始值为0
    counter.set("user:1", 0);
    // 增加用户1的访问量
    counter.incr("user:1");
    // 获取用户1的访问量
    System.out.println(counter.get("user:1")); // 输出:1
}
  • 队列:Redis可以利用列表类型来实现队列功能,例如,可以将任务、消息、事件等放入队列中,然后由消费者从队列中取出并处理。Redis还支持阻塞式的队列操作,即如果队列为空,消费者可以等待直到有元素可取
  • 社交网络:Redis可以利用其集合类型和有序集合类型来实现社交网络功能,例如,可以存储用户的好友关系、粉丝关系、兴趣标签等,并进行交集、并集、差集等操作。Redis还可以利用其发布订阅模式来实现消息的推送和广播。举个简单的栗子

user_friends: {user1: [user2, user3], user4: [user5]}
user_followers: {user1: [user6, user7], user8: [user9]}
// 添加好友
public void addFriend(String userId, String friendId) {
    redisTemplate.opsForSet().add(USER_FRIENDS, userId, friendId);
}
// 取消关注
public void unfollow(String userId, String followerId) {
    redisTemplate.opsForSet().remove(USER_FOLLOWERS, userId, followerId);
}
// 获取好友列表
public Set<String> getFriends(String userId) {
    return redisTemplate.opsForSet().members(USER_FRIENDS, userId);
}
// 获取某个用户的所有粉丝和所有好友的交集
public Set<String> getIntersection(String userId) {
    Set<String> friends = getFriends(userId);
    Set<String> followers = getFollowers(userId);
    return friends.stream().filter(followers::contains).collect(Collectors.toSet());
}
// 获取某个用户的所有粉丝和所有好友的并集
public Set<String> getUnion(String userId) {
    Set<String> friends = getFriends(userId);
    Set<String> followers = getFollowers(userId);
    return Stream.concat(friends.stream(), followers.stream()).collect(Collectors.toSet());
}
// 获取某个用户的所有粉丝和所有好友的差集
public Set<String> getDifference(String userId) {
    Set<String> friends = getFriends(userId);
    Set<String> followers = getFollowers(userId);
    return Stream.concat(friends.stream(), followers.stream()).filter((id) -> (!friends.contains(id))).collect(Collectors.toSet());
}
  • 地理位置:Redis可以利用其地理位置类型来实现地理位置功能,例如,可以存储用户的经纬度信息,并进行距离计算、范围查询、附近查询等操作。
  • 会话管理:Redis可以利用其字符串类型或散列类型来实现会话管理功能,例如,可以将用户的登录状态、权限信息、购物车信息等存储在Redis中,并设置过期时间。这样可以提高系统的安全性和一致性。

还有其他的一些应用场景,具体问题具体分析吧,现在各个企业越来越强依赖redis了,原来我同事去的一家打车公司更是这样,某块业务所有东西都放到redis中,只为高速实时,但是这带来的挑战是另一个层面了,我们后续再说

Redis数据类型

Redis支持多种数据类型,每种数据类型都有其特点和使用场景。下面是Redis数据类型的介绍:

  • 字符串String:字符串是Redis最基本的数据类型,它可以存储任何形式的数据,如文本、数字、二进制等。字符串的最大长度为512MB。字符串可以用于缓存、计数器、会话管理等场景。
  • 列表List:(双向链表)列表是一个有序的字符串序列,它可以在头部或尾部操作元素。列表可以用于队列、栈、最新消息等场景。
  • 集合Set:(底层实现是一个 value 永远为 null 的 HashMap)集合是一个无序的字符串集合,它可以添加或删除元素,也可以判断元素是否存在。集合可以用于标签、好友关系、去重等场景。
  • 散列Hash:散列是一个由字段和值组成的映射表,它可以操作字段对应的值。散列可以用于存储对象、计数器等场景。这个结构比较省空间,如果是那种大数据量的尽量选择使用散列
    • 优点:

      1.可以实现二分查找

      2.减少网络消耗

      3.维护集合时,查询比List更高效

  • 有序集合Sorted Set:(内部是HashMap 和跳跃表(SkipList)来保证数据的存储和有序)有序集合是一个按分数排序的字符串集合,可以添加删除元素,也可以根据分数或排名范围查询元素。可以用于排行榜、延时任务等场景。
  • 地理位置:地理位置是一个由经纬度坐标和名称组成的地理信息表,它可以添加或删除地理位置信息,也可以根据距离或范围查询附近的地理位置信息。可以用于地图服务、附近搜索等场景。

Redis线程模型

内部使用文件事件处理器file event handler,其是单线程的,大家所说的单线程其实是这部分,它采用IO多路复用机制同时监听多个socket,根据socket上的事件来选择对应的事件处理器进行处理

文件处理器结构:

  • 多个socket
  • IO多路复用程序
  • 文件事件分派器
  • 事件处理器

一次通信多个socket可能产生不同的操作,每个操作对应不同的文件事件,IO多路复用程序会监听多个socket,将其产生的事件放入队列中排队,事件分派器每次从队列中取出一个事件,交给对应的事件处理器进行处理,命令请求处理器读取key-value并在自己内存中完成key-value的设置,操作完成后将命令回复处理器关联

多线程工作模型

Redis 的多线程工作模型是指 Redis 采用多个 IO 线程来处理网络请求,提高网络请求处理的并行度。需要注意的是,Redis 多 IO 线程模型只用来处理网络读写请求,对于 Redis 的读写命令,依然是单线程处理。

这种架构的优点在于可以将网络通信和命令执行分离开来,从而提高了 Redis 的并发性能和可靠性

单线程模型为什么效率会高?

  • 简单:单线程模型避免了多线程之间的竞争和同步问题,使得代码更简洁易懂,也更容易维护和调试。
  • 快速:单线程模型避免了多线程之间的上下文切换和资源消耗,使得执行效率更高,也更容易实现高性能。
  • 一致:单线程模型保证了命令的顺序执行和原子性,使得数据的一致性和完整性更容易保证。

当然,单线程模型也有一些缺点,主要是:

  • 无法利用多核CPU的优势,只能使用一个核心的计算能力。
  • 无法处理阻塞式的操作,如磁盘I/O、网络I/O等,会导致线程挂起,影响服务质量。

为了解决这些问题,Redis采用了以下策略:

  • 将所有数据存储在内存中,避免磁盘I/O的开销。
  • 使用多路复用技术,如epoll、kqueue等,来同时监听多个客户端的连接和请求,避免网络I/O的阻塞。
  • 使用多进程或多线程来进行持久化操作,如RDB、AOF等,避免影响主线程的执行。
  • 使用多进程或多线程来进行主从复制操作,避免影响主线程的执行。

通过这些策略,Redis可以充分发挥单线程模型的优势,同时规避其缺点,从而实现高性能和高可用的服务。

感谢观看,欢迎研讨,下面是小酒其他的几篇关于redis的文章,欢迎指导👇🏻

一次redis OOM问题分析解决,rdbtools安装分析redis内存

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我是小酒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值