是什么?
是完全开源免费的,用c语言编写的,是一个单线程,高性能的(key/value)内存数据库,基于内存运行并支持持久化的nosql数据库
能干嘛?
主要是用来做缓存,但不仅仅只能做缓存,比如:redis的计数器生成分布式唯一主键,redis实现分布式锁,队列,会话缓存等等。
去哪下?
官网,也可以通过Linux yum直接下载安装 (Redishttps://redis.io/download)
1.redis安装
1.1 下载地址:http://redis.io/download ,把下载好的redis-5.0.3.tar.gz放在/usr/local/edwin-test文件 夹下, 执行 tar xzf redis-5.0.3.tar.gz 进行解压
1.2 准备安装
1.# 安装gcc 环境
yum install gcc
2.进入 redis-5.0.13 目录 , 进行编译与安装
make
3. 修改配置 并且启动
daemonize yes #后台启动
protected-mode no #关闭保护模式,开启的话,只有本机才可以访问redis
# 需要注释掉bind
#bind 127.0.0.1(bind绑定的是自己机器网卡的ip,如果有多块网卡可以配多个ip,代表允许客户端通过机器的哪些网卡ip去访问,内网一般可以不配置bind,注释掉即可)
配置文件中 还可以设置密码等 属性
# 启动服务 src/redis-server redis.conf
# 验证启动是否成功 ps -ef | grep redis
# 进入redis客户端
src/redis-cli
# 退出客户端
quit
# 退出redis服务:
src/redis-cli shutdown
其他命令:
redis-server :启动 redis 服务
redis-cli :进入 redis 命令客户端
redis-benchmark : 性能测试的工具
redis-check-aof : aof 文件进行检查
redis-check-dump : rdb 文件进行检查
redis-sentinel : 启动哨兵监控服务
2.5种数据结构
官方命令大全网址:http://www.redis.cn/commands.html
Redis 中存储数据是通过 key-value 格式存储数据的,其中 value 可以定义五种数据类型:
String(字符类型)
Hash(散列类型)
List(列表类型)
Set(集合类型)
SortedSet(有序集合类型,简称zset)
注意:在 redis 中的命令语句中,命令是忽略大小写的,而 key 是不忽略大小写的。
- string类型
字符串常用操作 SET key value //存入字符串键值对 eg: set test1 test MSET key value [key value ...] //批量存储字符串键值对 eg: set test2 123 test3 124 SETNX key value //存入一个不存在的字符串键值对 eg: setnx test4 abc GET key //获取一个字符串键值 MGET key [key ...] //批量获取字符串键值 DEL key [key ...] //删除一个键 EXPIRE key seconds //设置一个键的过期时间(秒) 原子加减 INCR key //将key中储存的数字值加1 DECR key //将key中储存的数字值减1 INCRBY key increment //将key所储存的值加上increment DECRBY key decrement //将key所储存的值减去decrement 字符串常用操作 SET key value //存入字符串键值对 MSET key value [key value ...] //批量存储字符串键值对 SETNX key value //存入一个不存在的字符串键值对 GET key //获取一个字符串键值 MGET key [key ...] //批量获取字符串键值 DEL key [key ...] //删除一个键 EXPIRE key seconds //设置一个键的过期时间(秒) 原子加减 INCR key //将key中储存的数字值加1 DECR key //将key中储存的数字值减1 INCRBY key increment //将key所储存的值加上increment DECRBY key decrement //将key所储存的值减去decrement 计数器 INCR article:readcount:{文章id} GET article:readcount:{文章id} Web集群session共享 spring session + redis实现session共享 分布式系统全局序列号 INCRBY orderId 1000 //redis批量生成序列号提升性能
- hash类型
HSET key field value //存储一个哈希表key的键值 eg: hset test name edwin ; HSETNX key field value //存储一个不存在的哈希表key的键值 eg: hsetnx test abc 122 key存在者不插入 HMSET key field value [field value ...] //在一个哈希表key中存储多个键值对 eg: hmset test name 124 age 20 sex 男 HGET key field //获取哈希表key对应的field键值 HMGET key field [field ...] //批量获取哈希表key中多个field键值 HDEL key field [field ...] //删除哈希表key中的field键值 HLEN key //返回哈希表key中field的数量 HGETALL key //返回哈希表key中所有的键值 HINCRBY key field increment //为哈希表key中field键的值加上增量increment HMSET user {userId}:name zhuge {userId}:balance 1888 HMSET user 1:name zhuge 1:balance 1888 HMGET user 1:name 1:balance 电商购物车 1)以用户id为key 2)商品id为field 3)商品数量为value 购物车操作 添加商品 hset cart:1001 10088 1 增加数量 hincrby cart:1001 10088 1 商品总数 hlen cart:1001 删除商品 hdel cart:1001 10088 获取购物车所有商品hgetall cart:1001 优点 1)同类数据归类整合储存,方便数据管理 2)相比string操作消耗内存与cpu更小 3)相比string储存更节省空间 缺点 过期功能不能使用在field上,只能用在key上 Redis集群架构下不适合大规模使用
- list类型
LPUSH key value [value ...] //将一个或多个值value插入到key列表的表头(最左边) RPUSH key value [value ...] //将一个或多个值value插入到key列表的表尾(最右边) LPOP key //移除并返回key列表的头元素 RPOP key //移除并返回key列表的尾元素 LRANGE key start stop //返回列表key中指定区间内的元素,区间以偏移量start和stop指定 获取列表中的某一片段。将返回`start`、`stop`之间的所有元素(包含两端的元素),索引从`0`开始。索引可以是负数,如:“`-1`”代表最后边的一个元素 BLPOP key [key ...] timeout //从key列表表头弹出一个元素,若列表中没有元素,阻塞等待 timeout秒,如果timeout=0,一直阻塞等待 BRPOP key [key ...] timeout //从key列表表尾弹出一个元素,若列表中没有元素,阻塞等待 timeout秒,如果timeout=0,一直阻塞等待 lrem: 删除列表中指定个数的值 LREM 命令会删除列表中前 count 个值为 value 的 执行方式会有所不同: 语法示例: - 当count>0时, LREM会从列表左边开始删 - 当count<0时, LREM会从列表后边开始删 - 当count=0时, LREM删除所有值为value eg: LREM abc 1 test 删除1个 值为 test, key为abc数据 LINDEX 示例: 1 获得指定索引的元素值 LINDEX key index eg: lindex abc 2 设置指定索引的元素值 语法:LSET key index value eg: lset abc 2 test LTRIM 语法: 只保留列表指定片段,指定范围和LRANGE一致 LTRIM key start stop eg: ltrim abc 0 -1 常用数据结构 Stack(栈) = LPUSH + LPOP Queue(队列)= LPUSH + RPOP Blocking MQ(阻塞队列)= LPUSH + BRPOP
- set类型
Set常用操作 SADD key member [member ...] //往集合key中存入元素,元素存在则忽略,若key不存在则新建 eg: sadd test abc 1 2 SREM key member [member ...] //从集合key中删除元素,成功返回0 eg: srem test 2 SMEMBERS key //获取集合key中所有元素 eg: smembers test SCARD key //获取集合key的元素个数 SISMEMBER key member //判断member元素是否存在于集合key中 SRANDMEMBER key [count] //从集合key中选出count个元素,元素不从key中删除 SPOP key [count] //从集合key中选出count个元素,元素从key中删除 Set运算操作 SINTER key [key ...] //交集运算 eg: sadd a 1 2 3 sadd b 3 4 5 sinter a b ==> 3 SINTERSTORE destination key [key ..] //将交集结果存入新集合destination中 SUNION key [key ..] //并集运算 eg: sunion a b => 1 2 3 4 5 SUNIONSTORE destination key [key ...] //将并集结果存入新集合destination中 SDIFF key [key ...] //差集运算 -- 集合的差集运算 A-B:属于A并且不属于B的元素构成的集合 eg: sdiff a b ==> 1,2 sditt b a ==> 4,5 SDIFFSTORE destination key [key ...] //将差集结果存入新集合destination中 微信抽奖小程序 1)点击参与抽奖加入集合 SADD test zhangsan lisi wangwu 2)查看参与抽奖所有用户 SMEMBERS test 3)抽取count名中奖者 SRANDMEMBER key [count] / SPOP key [count] eg: spop test 1 三个抽1个 集合中剩余2个 SRANDMEMBER 不会从集合中删除 微信微博点赞,收藏,标签 1) 点赞 SADD like:{消息ID} {用户ID} 2) 取消点赞 SREM like:{消息ID} {用户ID} 3) 检查用户是否点过赞 SISMEMBER like:{消息ID} {用户ID} 4) 获取点赞的用户列表 SMEMBERS like:{消息ID} 5) 获取点赞用户数 SCARD like:{消息ID} 集合操作实现电商商品筛选 SADD brand:huawei P50 SADD brand:xiaomi max4 SADD brand:iPhone iphone13 SADD os:android P50 max4 SADD cpu:brand:intel P50 max4 SADD ram:8G P50 max4 iphone13 SINTER os:android cpu:brand:intel ram:8G {P50,max4}
- zset类型
ZADD key score member [[score member]…] //往有序集合key中加入带分值元素 eg: zadd scoreboard 80 zhangsan 89 lisi 94 wangwu zadd scoreboard 97 lisi 修改分值 ZREM key member [member …] //从有序集合key中删除元素 移除有序集合key中的一个或多个成员,不存在的成员将被忽略。 eg: zrem scoreboard lisi ZSCORE key member //返回有序集合key中元素member的分值 eg: zscore scoreboard lisi ZINCRBY key increment member //为有序集合key中元素member的分值加上increment eg: ZINCRBY scoreboard 4 lisi ZCARD key //返回有序集合key中元素个数 eg: ZCARD scoreboard ZRANGE key start stop [WITHSCORES] //正序获取有序集合key从start下标到stop下标的元素(包含两端的元素) eg: zrange scoreboard 0 2 ZREVRANGE key start stop [WITHSCORES] //倒序获取有序集合key从start下标到stop下标的元素(包含两端的元素) eg: zrevrange scoreboard 0 2 eg: zrange scoreboard 0 1 WITHSCORES Zset集合操作 ZUNIONSTORE destkey numkeys key [key ...] //并集计算 其中给定 key 的数量必须以 numkeys 参数指定,并将该并集(结果集)储存到 destkey 中。 ZINTERSTORE destkey numkeys key [key …] //交集计算 Zset集合操作实现排行榜 1)点击新闻 ZINCRBY hotNews:20210819 1 小吴事件 2)展示当日排行前十 ZREVRANGE hotNews:20210819 0 9 WITHSCORES 3)七日搜索榜单计算 ZUNIONSTORE hotNews:20210813-20210819 7 hotNews:20190813 hotNews:20210814... hotNews:20210819 4)展示七日排行前十 ZREVRANGE hotNews:20210813-20210819 0 9 WITHSCORES
6.geo
GEOADD locations 116.419217 39.921133 beijin GEOPOS locations beijin GEODIST locations tianjin beijin km 计算距离 GEORADIUSBYMEMBER locations beijin 150 km 通过距离计算城市 注意:没有删除命令 它的本质是zset (type locations) 所以可以使用zrem key member 删除元素 zrange key 0 -1 表示所有 返回指定集合中所有value
Redis 单线程为什么还能这么快?
因为它所有的数据都在内存中,所有的运算都是内存级别的运算,而且单线程避免了多线程的切换性能损耗问题。正因为 Redis 是单线程,所以要小心使用 Redis 指令,对于那些耗时的指令(比如keys),一定要谨慎使用,一不小心就可能会导致 Redis 卡顿。
Redis 单线程如何处理那么多的并发客户端连接?
Redis的IO多路复用:redis利用epoll来实现IO多路复用,将连接信息和事件放到队列中,依次放到文件事件分派器,事件分派器将事件分发给事件处理器。(这点跟NGINX一样)。 Redis 是跑在单线程中的,所有的操作都是按照顺序线性执行的,但是由于读写操作等待用户输入或输出都是阻塞的,所以 I/O 操作在一般情况下往往不能直接返回,这会导致某一文件的 I/O 阻塞导致整个进程无法对其它客户提供服务,而 I/O 多路复用就是为了解决这个问题而出现的。
整理几个Redis客户端命令对应的RedisTemplate中的方法列表:
现在一般都是基于springboot开发 整理集合常用的命令对照表(具体怎么在项目中使用配置可以自行百度下):
RedisTemplate中定义了对5种数据结构操作
redisTemplate.opsForValue(); //操作字符串
redisTemplate.opsForHash();//操作hash
redisTemplate.opsForList();//操作list
redisTemplate.opsForSet();//操作set
redisTemplate.opsForZSet();//操作有序set
StringRedisTemplate继承自RedisTemplate,也一样拥有上面这些操作。
StringRedisTemplate默认采用的是String的序列化策略,保存的key和value都是采用此策略序列化保存的。
RedisTemplate默认采用的是JDK的序列化策略,保存的key和value都是采用此策略序列化保存的
String类型结构 | |
Redis | RedisTemplate rt |
set key value | rt.opsForValue().set("key","value") |
get key | rt.opsForValue().get("key") |
del key | rt.delete("key") |
strlen key | rt.opsForValue().size("key") |
getset key value | rt.opsForValue().getAndSet("key","value") |
getrange key start end | rt.opsForValue().get("key",start,end) |
append key value | rt.opsForValue().append("key","value") |
Hash结构 | |
hmset key field1 value1 field2 value2... | rt.opsForHash().putAll("key",map) //map是一个集合对象 |
hset key field value | rt.opsForHash().put("key","field","value") |
hexists key field | rt.opsForHash().hasKey("key","field") |
hgetall key | rt.opsForHash().entries("key") //返回Map对象 |
hvals key | rt.opsForHash().values("key") //返回List对象 |
hkeys key | rt.opsForHash().keys("key") //返回List对象 |
hmget key field1 field2... | rt.opsForHash().multiGet("key",keyList) |
hsetnx key field value | rt.opsForHash().putIfAbsent("key","field","value" |
hdel key field1 field2 | rt.opsForHash().delete("key","field1","field2") |
hget key field | rt.opsForHash().get("key","field") |
List结构 | |
lpush list node1 node2 node3... | rt.opsForList().leftPush("list","node") |
rt.opsForList().leftPushAll("list",list) //list是集合对象 | |
rpush list node1 node2 node3... | rt.opsForList().rightPush("list","node") |
rt.opsForList().rightPushAll("list",list) //list是集合对象 | |
lindex key index | rt.opsForList().index("list", index) |
llen key | rt.opsForList().size("key") |
lpop key | rt.opsForList().leftPop("key") |
rpop key | rt.opsForList().rightPop("key") |
lpushx list node | rt.opsForList().leftPushIfPresent("list","node") |
rpushx list node | rt.opsForList().rightPushIfPresent("list","node") |
lrange list start end | rt.opsForList().range("list",start,end) |
lrem list count value | rt.opsForList().remove("list",count,"value") |
lset key index value | rt.opsForList().set("list",index,"value") |
Set结构 | |
sadd key member1 member2... | rt.boundSetOps("key").add("member1","member2",...) |
rt.opsForSet().add("key", set) //set是一个集合对象 | |
scard key | rt.opsForSet().size("key") |
sidff key1 key2 | rt.opsForSet().difference("key1","key2") //返回一个集合对象 |
sinter key1 key2 | rt.opsForSet().intersect("key1","key2")//同上 |
sunion key1 key2 | rt.opsForSet().union("key1","key2")//同上 |
sdiffstore des key1 key2 | rt.opsForSet().differenceAndStore("key1","key2","des") |
sinter des key1 key2 | rt.opsForSet().intersectAndStore("key1","key2","des") |
sunionstore des key1 key2 | rt.opsForSet().unionAndStore("key1","key2","des") |
sismember key member | rt.opsForSet().isMember("key","member") |
smembers key | rt.opsForSet().members("key") |
spop key | rt.opsForSet().pop("key") |
srandmember key count | rt.opsForSet().randomMember("key",count) |
srem key member1 member2... | rt.opsForSet().remove("key","member1","member2",...) |