Redis学习笔记(一) 初遇篇

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: Redis学习笔记(一) 初遇篇

是什么?

Redis 是 Remote Dictionary Server , 直译为远程字典服务。

Redis is an open source (BSD licensed), in-memory data structure store, used as a database, cache and message brokerRedis是一个开源的,存储在内存中的数据结构存储器,常被用来做数据库、缓存、消息队列。

注意Redis自己认为自己是一个存储于内存中的数据结构结构存储器,再强调一遍,Redis是一个内存中的数据结构存储器。 各位明白我在强调什么了吗? 我在强调数据结构,为什么强调这个呢? 以java为例,各种各样的框架和中间件层出不穷,学着学着,就会有一种学不动的感觉了,这是正常的,但是我们一定要注重体会它的设计思想,注重基础,这里的基础就包括数据结构,这个在大学时代反复被强调的课程。

回忆一下,工作中的数据结构出现率也是很高的,MySQL索引的B+树,图数据库中的图,所以我不建议计算机专业的学生太过追求框架和潮流的技术,觉得学校不交框架就是和社会脱节了,你基础学的好,会发现学这些框架十分的简单。

有什么优点?

内存速度非常快,而Redis将数据存储在内存中,自然也快。

  • 文档全

现在我学习一项新技术,一般都先去官网先看看文档,Redis的文档真是丰富,我想知道的,文档上都有。

  • 结构丰富

截止当前,Redis提供的数据结构就有九种。

  • 功能完备
  • 多机功能:
  1. 复制
  2. Sentinel(哨兵)
  3. 集群
  • 数据库管理
  • 自动过期
  • 流水线
  • 事务
  • Lua脚本
  • 模块
  • 持久化
  • 发布与订阅

多级功能、Lua脚本、 模块、发布与订阅属于高级特性,本篇不讲。

推荐的学习资料:

Redis 官方中文网站

先安装在说

Redis推荐在Linux安装部署,其他操作系统上也能跑,只是性能不佳而已。 目前Redis最新版本是6.0.7,一般流行都落后于最新版本,我们本次选择的是5.0.9。 怎么安装,官网已经讲得很清楚了,不信你可以去看。

image.png

然后我们按照官网讲的步骤,来安装一下:

wget download.redis.io/releases/re…

tar redis-5.0.9.tar.gz   // 解压

mv redis-5.0.9  redis  // 文件重命名 cd redis

make  // 编译

make test  // 测试编译是否成功

src/redis-server // 启动redis 服务端   这个是前台启动,不改配置文件的话,启动后就一直卡这里。

Redis 的官方文档真的是十分丰富,你可以轻松的在Documentation中找到如何配置Redis

image.png

一般我们改配置文件,也就改三处:

  • 对应的是 注释 bind  127.0.0.1

网上的很多解释是bind是用来限制IP访问的,我尝试过发现是无效的,我找到了Redis对这个属性的解释: If the computer running Redis is directly exposed to the  internet, binding to all the interfaces is dangerous and will expose the instance to everybody on the internet. So by default we uncomment the  following bind directive, that will force Redis to listen only into  the IPv4 loopback interface address (this means Redis will be able to accept connections only from clients running into the same computer it is running). IF YOU ARE SURE YOU WANT YOUR INSTANCE TO LISTEN TO ALL THE INTERFACES JUST COMMENT THE FOLLOWING LINE. 如果运行在服务器上的redis并且直接向互联网暴露,绑定所有的接口是危险的,将会暴露给互联网上的所有人。 这里的接口我们可以理解为网卡,每个网卡拥有一个mac地址与IP地址相对应,bind 指定IP就是指监听这个该IP对应网卡的请求(一台服务器可以拥有多个网卡)。默认情况下,我们没有注释这段,这将会强制Redis只允许本机上的客户端连接(意思是客户端和服务端必须运行在一台主机上)

  • 设置密码  搜索 requirepass  属性

Warning: since Redis is pretty fast an outside user can try up to 150k passwords per second against a good box. This means that you should use a very strong password otherwise it will be very easy to break. 外部用户每秒可以尝试15万个密码,因为Redis十分快,如果你的密码不够健壮,他将很容易被攻破。 看到这里的我,流下来眼泪,当初Redis密码不够健壮,老是被挖矿的盯上,然后服务器CPU跑满。

  • 后台启动 daemonize  no 改为yesimage.pngimage.png设置我密码,我打算产生一个16位的随机字符串,保证我的密码足够健壮:

image.png

然后让Redis 服务端启动的时候按我们修改的配置文件走:

src/redis-server redis.conf   
redis-cli  连接服务端
auth 密码 登陆 
复制代码

可能有的教程,在装Redis的时候会让你关掉防火墙,但我不建议你这么做,之前我的阿里云服务器血与泪的教训。 防火墙对6379端口放行。 (1) 向防火墙添加 Redis 端口: firewall-cmd --zone=public --add-port=6397/tcp --permanent (2) 刷新防火墙规则: firewall-cmd --reload (3) 验证端口,查询防火墙开放端口: firewall-cmd --zone=public --list-port

如果你不想安装

redis 官方提供了在线版本:

image.png

image.png

基本数据类型和自动过期

大体上我们学习如何使用数据结构的时候,一般也就是能存什么,怎么取,怎么存。所以下面也是讲怎么取,怎么存的。 但是我不准备对Redis的命令做百科全书式的介绍,这有违本文的初衷。 截止目前为止,共提供了九种数据类型,本文只讲八种:

  • Binary-safe strings 字符串.
  • Lists  列表
  • Sets  集合
  • Sorted sets 有序集合
  • Hashes 散列
  • Bit arrays  位图
  • HyperLogLogs  (暂时想不到好的译名)
  • GEO(地理坐标)

流属于高级一点的数据结构,需要配合消息队列来讲,所以本篇不讲。

字符串

能存什么?

虽然这种数据类型叫字符串,但是可不是不同那种普通的字符串,因为这种数据类型还可以存数字、图片、视频、音频、压缩文件等更为复杂的二进制数据。

如何存?

一般操纵redis字符串命令格式如下: 单个新增:

set key value [EX seconds] [PX milliseconds] [NX|XX]
复制代码

批量新增

mset key1 value1 key2 value2......
复制代码

中括号内的代表的是可选参数,其他是必选参数。 EX 和 PX 代表存活时间,超出这个时间就无法获取了,EX是秒 XX是毫秒 NX代表如果不存在有变量名为name(一般来说Redis称之为键,下文我们也称之为键), XX则表示相反,存在了我也给你覆盖。 批量新增是MX 默认情况下为XX。 例子: 单个新增: 我向Redis请求新增一个名为name的字符串,如果数据库不存在则新增成功,新增成功后,保存时间为6秒,超过6秒后会被Redis自动清理

set name 'zs' ex 6 NX 
复制代码

批量新增:

mset name1 zs  name2 lisi
复制代码

如何取

取命令操作格式: 单个取:

get key 
复制代码

批量取

mget key1 key2
复制代码

基本操作

操纵整数

上面讲字符串可以存存数字,有同学可能会说,那肯定能啊,字符串不是包含一切嘛。 我的意思是Redis存储的字符串还可以实现自增, 我们先来做一下操作数字: 一般的命令格式: 递增

incr age 
复制代码
set  age 20 
 incr age 
 get age 
 会发现age变成21了 
 decr age 
 get age
 age又变成20了
复制代码

做过几个之后,你会发现 Redis的命令十分简单直观,完全是英语单词的缩写。 上面的增长幅度是1,我们可以自己设定增长幅度

incrby key number
decrby key number
复制代码

例子:

incrby age 2
加2
decrby age 2
减去2
复制代码

操作浮点数的命令差不多: 整数是incrby浮点数是incrbyfloat。

对字符串的操作
  • 获取字符串的长度
strlen age
复制代码
  • 截取字符串
getrange key start end
复制代码
  • 替换字符串上指定位置的字符
setrange  key offset value
复制代码

List

  • Lists collections of string elements sorted according to the order of insertion. They are basically linked lists.

存储字符串元素的集合,顺序和插入顺序一致,通常基于链表 这个list像java中的List但是又不完全是。

从左边存

lpush mylist a b c d e f
复制代码

创建一个名为mylist的集合,并将a b c d e f 从左侧依次放入 为什么强调从左侧呢? 因为取的时候也分左右,你可以从左边取,也可以从右边开始取。image.pnglpush 从左边存,rpush就是从右边存。

从左边取 lpop

我们上面说List的顺序和插入顺序一致,那么你从左边开始存,最后一个字符是f,那么我按照插入的顺序从左边取,也是f。 这里的从左边取是直接字面上的翻译 left pop,如果你比较熟悉数据结构,应该会记得pop是指出栈操作。lpop也继承了出栈操作指令,返回最右端的元素,并移除该元素。

一般命令格式:

lpop key
复制代码

例子:

lpop mylist 
复制代码

返回f。 lpop返回最右端的元素,rpop就是返回最左端的元素。

Set  无序集合

  • Sets: collections of unique, unsorted string elements.

集合元素唯一,无顺序 基本命令:

  • 新增 存
sadd key member
复制代码
  • 获取全部的元素 取
smembers key
复制代码
  • 查看该元素在集合中是不是存在的,不存在返回0
sismember  key number
复制代码

sorted Set  序集合

similar to Sets but where every string element is associated to a floating number value, called score. The elements are always taken sorted by their score, so unlike Sets it is possible to retrieve a range of elements (for example you may ask: give me the top 10, or the bottom 10). 与无序集合类似,有序集合中的元素都和一个浮点数相连,称作权值,元素按权值排序。 基本命令:

  • 新增 存
zadd key score member score member
复制代码
zscore key score
复制代码

散列

  • Hashes, which are maps composed of fields associated with values. Both the field and the value are strings. This is very similar to Ruby or Python hashes. hash是由值和相关联的字段组成的映射,值和相关联的字段都是字符串。和Ruby、python中的hashes非常像。image.png
  • 新增 存
hmset key filed value filed value
复制代码
hmget key filed field
复制代码

位图

  • Bit arrays (or simply bitmaps): it is possible, using special commands, to handle String values like an array of bits: you can set and clear individual bits, count all the bits set to 1, find the first set or unset bit, and so forth. 位数组(由1和0组成的数组),初始状态数组的长度为8,全为0,会自动进行扩展。

image.png

  • 新增
setbit key offset value
offset是位置, 假如你给的是10,会自动再扩展一字节,也就是8个位置 
复制代码
getbit key offset 
offset 只允许为正数
复制代码

HyperLogLogs

HyperLogLogs: this is a probabilistic data structure which is used in order to estimate the cardinality of a set. Don't be scared, it is simpler than it seems... See later in the HyperLogLog section of this tutorial. 这是一种估计常常用来估计集合的基数的数据结构,听起来很高端对不对,他非常简单。

通常情况下,博客网站常常会记录访客IP,这可以用来计算博客的阅读量等等。我们当然也可以用上面讲的集合来做,但是这比较消耗内存,为了高效的计算唯一访客IP这类问题,研究人员开发了很多不同的方法,其中高效的一种就是HyperLogLog,

HyperLogLog是一个专门为了计算集合的基数而创建的概率算法,对于一个给定的集合,HyperLogLog可以返回近似的基数,近似基数可能会比实际的基数小一点或大一点,但是估算基数和实际基数的误差会处在一个合理的范围。

HyperLogLogs的优点是它计算集合近似基数的内存并不会因为集合的大小而改变。具体到实现上Redis的每个HyperLogLog只需要使用12KB的内存空间,就可以对高达2的64次方个元素进行计数,而算法的标准误差仅为0.81%。 下面我们主要介绍的就是 对集合的元素进行计数 返回集合的近似基数

一般命令格式: 创建一个HyperLogLog 并对元素进行计数

pfadd key element
复制代码

返回HyperLogLog 的近似基数

pfcount key 
复制代码

坐标

RedisGEO是Redis在3.2版本新添加的特性,通过这一特性,用户可以将经纬度格式的地理坐标存储到Redis中,并对这些坐标执行距离计算、范围查找等操作。 常规操作:

  • 算距离 存命令的一般格式:
geoadd key longitude latitude  member 
复制代码

longitude  是经度 latitude   是度纬

取命令的一般格式:

getpos key member
复制代码

算距离的命令格式:

geodist key  member1  member2
复制代码

例子:

GEOADD  HENAN 113.2099647 23.965 pingdingshan 110.12 110.24 nanyang
-- 创建了henan这个坐标,并向里面添加了两个城市对应的经纬度
-- geopos HENAN pingdingshan
获取pingdingshan的经纬度
-- 计算nanyang 和 pingdingshan之间的直线距离
geodist HENAN pingdingshan nanyang
复制代码

流水线

注意到上面在介绍Redis的数据结构时,都是单独的执行每个命令,也就是说,先将一个命令发送至服务器,等服务器执行完毕并将结果返回至客户端之后,再执行下一个命令。这种执行命令的方式和批量插入有点类似,批量插入通常有两种思路:

  • 遍历,每个对象是一条SQL语句
  • 还是遍历,将所有的要插入到数据库的对象组成一条SQL语句(我们常常采用这种,这种性能最优) 你可以将流水线理解为批量执行命令。 虽然Redis服务器提供了流水线特性,幸运的是绝大多数Redis客户端都提供了对流水线的支持,在java操纵Redis这一节会详细介绍。

事务

通过MULTI开启一个事务,这个命令在成功开启之后将返回ok。

image.png当一个Redis客户端执行MULTI命令之后,就进入了事务模式,所有的命令会按顺序放入一个事务队列中,当执行exec(我们可以理解为提交事务时),所有的命令才会统一执行。

Redis也允许你丢弃事务,命令是discard。discard命令会丢弃事务队列中所有的命令。

具体的说Redis的事务具备ACID性质的A、C、I性质:

  • 原子性(Atomic) :  事务中的所有命令要么全部成功,如果有一个失败,则全部失败。
  • 一致性(consistent) : Redis服务器会对事务及其包含的命令进行检查,确保无论事务是否执行成功,事务本身都不会对数据库造成破坏
  • 隔离性: 每个Redis客户端都拥有自己独立的事务队列,并且每个Redis事务都是独立执行的,不同的事务之间不会相互影响。 为啥Redis的事务可能不具备D(持久性呢)? 因为Redis是存储在内存中,当Redis服务器运行在特定的持久化模式之下时,Redis的事务也具备持久性。

持久化

注意Redis将数据存储在内存中,存储在内存中的风险就是当系统断电,存储于Redis中的数据就没了,当我们将Redis当做数据库来用时,这是我们不愿意看到的,为了解决这个问题,Redis向用户提供了持久化功能,也就是说Redis可以将存储于内存的数据以文件的形式存储到硬盘上。

为了满足不同的持久化需求,Redis提供了RDB持久化、AOF持久化个RDB-AOF混合持久化等多种持久化方式供用户选择,如果你不喜欢,Redis也可以完全关闭持久化功能。

RDB-AOF属于高级一点的特性,本篇不讲。

粗略的说RDB是全量持久化,AOF是增量持久化。

当客户端向Redis服务端发送save命令时,此时Redis会执行RDB持久化,Redis会遍历所有的数据库并将各个数据包含的键值对全部记录到RDB文件中。在save命令执行期间,Redis服务器不再对外提供服务,如果在Redis在之前已经执行过save命令,那么redis会用新的覆盖旧的。

我们显然是难以接受在Redis持久化的时候,Redis不再提供服务,Redis提供了另一个异步的RDB持久化方式,命令是BGSAVE,该命令会让Redis服务器创建一个子进程来做持久化,虽然是异步的,但是如果Redis本身已经占用了大量的内存,那么创建子进程就会花费更多的时间,因此在执行BGSAVE时,Redis服务端仍然会由于创建子线程而拒绝对外提供服务。

RDB的缺点是每次都是扫描全部,但是这会消耗大量的计算资源和内存资源。

AOF是增量的,服务器在每次执行完毕之后,都会以协议文本的方式将被执行的命令追加到AOF的文件末尾。 但是AOF还是不完美的,我们考虑一下,随着服务器的不断运行,被执行的命令将变得越来越多,而负责记录这些命令的AOF也会变得越来越大。 AOF通过 APPENDONLY yes命令来打开。

这也是Redis引入ADB和AOF混合持久化的原因。

java 操纵 Redis

java操纵Redis也就是通过Redis客户端来做的,类似于mysql驱动一样,只不过Redis这里叫客户端。 推荐使用的客户端会标上星, 客户端在六个月内有更新的将会被标上一个笑脸。image.png

image.png

常规操作我们还是用maven工程,引入依赖。 jedis提供的API十分简单,原先redis的命令变成了方法。

JedisShardInfo jedisShardInfo = new JedisShardInfo("ip地址" , 6379);
        jedisShardInfo.setPassword("密码");
        Jedis jedis = new Jedis(jedisShardInfo);
        // 操纵Hy
        jedis.pfadd("hycount","ddd");
        // 操纵字符串
        jedis.set("name","zs");
        // 获取字符串
        jedis.get("name");
        Pipeline piple = jedis.pipelined();
复制代码

总结一下

本文主要介绍了Redis的简单使用,希望能对大家有所帮助。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
4月前
|
存储 NoSQL Linux
小白带你学习linux的Redis基础(三十二)
小白带你学习linux的Redis基础(三十二)
74 0
|
3月前
|
存储 NoSQL Redis
redis源码学习
redis源码学习
|
4月前
|
存储 NoSQL Ubuntu
在Ubuntu上安装Redis并学习使用get、set和keys命令
在Ubuntu上安装Redis并学习使用get、set和keys命令
|
5月前
|
缓存 NoSQL Redis
【Redis 系列】redis 学习十六,redis 字典(map) 及其核心编码结构
【Redis 系列】redis 学习十六,redis 字典(map) 及其核心编码结构
|
5月前
|
NoSQL 算法 Redis
【Redis 系列】redis 学习十四,sorted_set 初步探究梳理
【Redis 系列】redis 学习十四,sorted_set 初步探究梳理
|
5月前
|
存储 NoSQL Redis
【Redis 系列】redis 学习十五,redis sds数据结构和底层设计原理
【Redis 系列】redis 学习十五,redis sds数据结构和底层设计原理
|
5月前
|
负载均衡 NoSQL Redis
【Redis 系列】redis 学习十,Redis 集群搭建和主从复制
【Redis 系列】redis 学习十,Redis 集群搭建和主从复制
|
3月前
|
NoSQL 中间件 API
分布式锁【数据库乐观锁实现的分布式锁、Zookeeper分布式锁原理、Redis实现的分布式锁】(三)-全面详解(学习总结---从入门到深化)(下)
分布式锁【数据库乐观锁实现的分布式锁、Zookeeper分布式锁原理、Redis实现的分布式锁】(三)-全面详解(学习总结---从入门到深化)
82 2
|
3月前
|
NoSQL Java API
分布式锁【数据库乐观锁实现的分布式锁、Zookeeper分布式锁原理、Redis实现的分布式锁】(三)-全面详解(学习总结---从入门到深化)(上)
分布式锁【数据库乐观锁实现的分布式锁、Zookeeper分布式锁原理、Redis实现的分布式锁】(三)-全面详解(学习总结---从入门到深化)
74 0
|
5月前
|
存储 NoSQL 算法
[Redis 系列]redis 学习 17,redis 存储结构原理 1
[Redis 系列]redis 学习 17,redis 存储结构原理 1