20.1.1 Redis 学习
redis是分布式的内存数据库
Redis安装与配置
- 首先安装 gcc环境:
yum -y install gcc automake autoconf libtool make
- 将桌面上的包复制到/opt 目录下
- 解压 /opt 目录下的包
解压完成:
- 然后输入 make 进行安装,看到以下界面说明成功:
- 继续输入 make install,看到以下界面说明Redis安装成功:
安装好 Redis安装到哪里去了:在 /usr/local/bin 下面
- 安装好后进行配置文件的备份:
进入刚才解压出来的文件夹里 找到 redis.conf 进行复制到 /myredis 文件夹下。
7. 然后进行配置文件的修改
找到 daemonize no 改成 daemonize yes 将其变成守护进程。
然后 wq! 保存退出
8. 再次进入 /usr/local/bin 目录,启动Redis的服务端:(启动哪一个 :启动之前改过配置文件的那个)
9. 启动Redis 客户端,看到以下则成功:
看与客户端是否连接成功: ping
看进程:
redis.conf 文件配置
放在这里
启动redis 服务端
以/myredis/redis.conf 这个配置文件规定的打开redis
注意是在目录下:
启动redis 客户端
-p 端口号 -a 密码
判断是否连接: ping,如果得到 PONG 则连接成功。
查看redis是否启动
有划红线的则启动成功。
关闭redis
select 选库
默认16个数据库,从0开始,到15结束。用select 换库
之前默认是在第0个数据库。
dbsize查看当前数据库的key的数量
keys * 将所有的key 罗列
FLUSHDB 清空当前库
FLUSHALL 清空所有库
Redis 五大数据类型
String
Hash
List
Redis 常用指令
Redis 字符串 string
append
incr key key 对应的value加1
decr key key 对应的value减1
incrby key N key 对应的value加N
decrby key N key 对应的value减N
setex key 秒数 value 设置一个key 的存活时间。
setnx key value 如果存在 则设置不成功,如果不存在 则设置成功
mset 设置多个
mget 得到多个
msetnx 都不存在 才都可以设置 一部分存在一部分不存在 都不能设置进去。
Redis 列表 List
lpush
先进后出, 相当于将rpush表的元素都反过来。
lrange 范围 只有lrange 没有 rrange.
rpush
先进先出 相当于正常的队列
lpop
rpop
lindex
llen 计算表有几个元素
lrem
lrem list N value 删除list中N个值为value的元素。
ltrim
ltrim list 开始索引 结束索引
截取开始索引和结束索引中间的值,重新赋值给list。
rpoplpush 源list 目标list
list01 右边出4 然后从左边压入list02
lset list 索引位置 value
将list 索引位置替换为value。
linsert list before/after value1 value2
在
Redis 集合(Set)
sadd set values
在set添加元素 ,如果遇到重复的元素 只添加进去一个
smembers set
展示集合里的元素。
sismember set value
看value是否在set中 在的话返回1 不在的话返回0
scard set
获取集合中的元素个数。
srem set value
删除集合中值为value的元素 删除成功返回1 不然返回0
srandmember set N
在set中随机选出 N个元素输出
spop set
set 中随机出栈一个元素。
smove set01 set02 value
将set01中的元素value转给set02 成功返回1.
sdiff set01 set02
sinter set01 set02
求交集
sunion set01 set02
求并集
Redis 哈希(Hash)
教程1
之前的kv是一个key对应一个value。现在的hash是一个key对应一个键值对。
比如一个key:user 对应一个键值对:name z3.
hset 设置
hget 读取
hmset 一个hash 表包含多个键值对
hmget key key1 key2 …
hgetall
hlen 看有几个键值对
hexists
hkeys / hvals 单独得到key值和value值。
Redis Zset
解析配置文件
linux系统中/var/run/目录下的*.pid文件是一个文本文件,其内容只有一行,即某个进程的PID。.pid文件的作用是防止进程启动多个副本,只有获得特定pid文件(固定路径和文件名)的写入权限(F_WRLCK)的进程才能正常启动并将自身的进程PID写入该文件,其它同一程序的多余进程则自动退出。
在学习阶段请保持出厂设置即可 ,因为不会有成千上万的机器连。
单机版的自己连自己主机。所以这里不修改
timeout 0 代表一直连接,如果是别的值 N 意思是超过N时间的空闲,将断开连接来减轻服务器的负担。
现在是一台redis, 以后可能是集群,keepalive 是进行检测 是否之间的网络还连接。
日志级别
默认16个库,从0开始 用select命令切换库。
缓存过期清洁策略
参数说明
redis.conf 配置项说明如下:
-
Redis默认不是以守护进程的方式运行,可以通过该配置项修改,使用yes启用守护进程
daemonize no -
当Redis以守护进程方式运行时,Redis默认会把pid写入/var/run/redis.pid文件,可以通过pidfile指定
pidfile /var/run/redis.pid -
指定Redis监听端口,默认端口为6379,作者在自己的一篇博文中解释了为什么选用6379作为默认端口,因为6379在手机按键上MERZ对应的号码,而MERZ取自意大利歌女Alessia Merz的名字
port 6379 -
绑定的主机地址
bind 127.0.0.1
5.当 客户端闲置多长时间后关闭连接,如果指定为0,表示关闭该功能
timeout 300 -
指定日志记录级别,Redis总共支持四个级别:debug、verbose、notice、warning,默认为verbose
loglevel verbose -
日志记录方式,默认为标准输出,如果配置Redis为守护进程方式运行,而这里又配置为日志记录方式为标准输出,则日志将会发送给/dev/null
logfile stdout -
设置数据库的数量,默认数据库为0,可以使用SELECT 命令在连接上指定数据库id
databases 16 -
指定在多长时间内,有多少次更新操作,就将数据同步到数据文件,可以多个条件配合
save
Redis默认配置文件中提供了三个条件:
save 900 1
save 300 10
save 60 10000
分别表示900秒(15分钟)内有1个更改,300秒(5分钟)内有10个更改以及60秒内有10000个更改。 -
指定存储至本地数据库时是否压缩数据,默认为yes,Redis采用LZF压缩,如果为了节省CPU时间,可以关闭该选项,但会导致数据库文件变的巨大
rdbcompression yes -
指定本地数据库文件名,默认值为dump.rdb
dbfilename dump.rdb -
指定本地数据库存放目录
dir ./ -
设置当本机为slav服务时,设置master服务的IP地址及端口,在Redis启动时,它会自动从master进行数据同步
slaveof -
当master服务设置了密码保护时,slav服务连接master的密码
masterauth -
设置Redis连接密码,如果配置了连接密码,客户端在连接Redis时需要通过AUTH 命令提供密码,默认关闭
requirepass foobared -
设置同一时间最大客户端连接数,默认无限制,Redis可以同时打开的客户端连接数为Redis进程可以打开的最大文件描述符数,如果设置 maxclients 0,表示不作限制。当客户端连接数到达限制时,Redis会关闭新的连接并向客户端返回max number of clients reached错误信息
maxclients 128 -
指定Redis最大内存限制,Redis在启动时会把数据加载到内存中,达到最大内存后,Redis会先尝试清除已到期或即将到期的Key,当此方法处理 后,仍然到达最大内存设置,将无法再进行写入操作,但仍然可以进行读取操作。Redis新的vm机制,会把Key存放内存,Value会存放在swap区
maxmemory -
指定是否在每次更新操作后进行日志记录,Redis在默认情况下是异步的把数据写入磁盘,如果不开启,可能会在断电时导致一段时间内的数据丢失。因为 redis本身同步数据文件是按上面save条件来同步的,所以有的数据会在一段时间内只存在于内存中。默认为no
appendonly no -
指定更新日志文件名,默认为appendonly.aof
appendfilename appendonly.aof -
指定更新日志条件,共有3个可选值:
no:表示等操作系统进行数据缓存同步到磁盘(快)
always:表示每次更新操作后手动调用fsync()将数据写到磁盘(慢,安全)
everysec:表示每秒同步一次(折衷,默认值)
appendfsync everysec -
指定是否启用虚拟内存机制,默认值为no,简单的介绍一下,VM机制将数据分页存放,由Redis将访问量较少的页即冷数据swap到磁盘上,访问多的页面由磁盘自动换出到内存中(在后面的文章我会仔细分析Redis的VM机制)
vm-enabled no -
虚拟内存文件路径,默认值为/tmp/redis.swap,不可多个Redis实例共享
vm-swap-file /tmp/redis.swap -
将所有大于vm-max-memory的数据存入虚拟内存,无论vm-max-memory设置多小,所有索引数据都是内存存储的(Redis的索引数据 就是keys),也就是说,当vm-max-memory设置为0的时候,其实是所有value都存在于磁盘。默认值为0
vm-max-memory 0 -
Redis swap文件分成了很多的page,一个对象可以保存在多个page上面,但一个page上不能被多个对象共享,vm-page-size是要根据存储的 数据大小来设定的,作者建议如果存储很多小对象,page大小最好设置为32或者64bytes;如果存储很大大对象,则可以使用更大的page,如果不 确定,就使用默认值
vm-page-size 32 -
设置swap文件中的page数量,由于页表(一种表示页面空闲或使用的bitmap)是在放在内存中的,,在磁盘上每8个pages将消耗1byte的内存。
vm-pages 134217728 -
设置访问swap文件的线程数,最好不要超过机器的核数,如果设置为0,那么所有对swap文件的操作都是串行的,可能会造成比较长时间的延迟。默认值为4
vm-max-threads 4 -
设置在向客户端应答时,是否把较小的包合并为一个包发送,默认为开启
glueoutputbuf yes -
指定在超过一定的数量或者最大的元素超过某一临界值时,采用一种特殊的哈希算法
hash-max-zipmap-entries 64
hash-max-zipmap-value 512 -
指定是否激活重置哈希,默认为开启(后面在介绍Redis的哈希算法时具体介绍)
activerehashing yes -
指定包含其它的配置文件,可以在同一主机上多个Redis实例之间使用同一份配置文件,而同时各个实例又拥有自己的特定配置文件
include /path/to/local.conf
持久化
RDB
是什么
如果不持久话,一断电内存就失效,数据就没了。
例如五分钟持久化(备份)一次,将这次临时文件替换上次的临时文件,在备份的过程中要求主进程不进行IO操作,这是因为保持源文件不变。
Fork
隐患:导致缓存紧张。如果宿主文件很大,备份的也很大。
Rdb 保存的就是dump.rdb 文件
配置位置
返回解析配置文件,
更改策略
先将 /usr/local/bin 目录下的dump.rdb删除,如果满足上述中的一个,那么这个路径会重新生成一个新的dump.rdb 文件 也就是备份。
验证:
第一步: 删除目录中的dump.rdb文件
第二步 对数据库进行更改 然后重新查看 发现有了新的 dump/rdb文件,备份完成。
真实数据恢复的时候,会从硬盘加载会内存。
从这里看出 每次找dump.rdb 文件。
企业中干活的生产机器和备份机器是两个不同的机器,
如果备份在同一台机器上,机器损坏,虽然文件备份了 但是备份的文件在坏的机器上 无法恢复。
先flushall 然后shutdown 然后重新登录,发现没数据库被清空。
由于flushall 触发持久化 生成新的dump.rdb文件1,所以有21.58分的文件1(这个文件应该是flushall之后的数据,为空)
然后shutdown 触发持久化,生成新的文件2 这个文件2是空的,会覆盖之前的文件1 ,所以重新启动加载文件2 的配置文件 得到 数据库为空。
由于修改数据库将dump.rdb 备份到另一台机器上。
可以使用 save 指令 马上备份。
如何触发RDB快照
save 前台不能灌入数据
bgsave 可以
优势
劣势
如何停止
总结
AOF
是什么
继续看配置文件
开始的默认是NO 说明恢复的策略是RDB策略。
当改成yes aof启动 这时候两者同时共存。
aof文件和rdb文件可以并存,启动的时候,按照哪个进行数据恢复呢 是rdb还是aof?
操作
在aof文件下瞎写,模拟写日志的时候突然断电 aof文件损坏。
然后启动服务端,如果启动成功 说明先找dump.rdb 如果报错 先找aof
没有启动成功
说明先加载的aof。
如何恢复??
将所有不符合aof语法规范的错误都修复。
配置文件中 说两者可以共存。
配置位置
配置文件
回看配置文件
appendonly 默认no
appendfilename 默认不用改
默认出厂设置 是第二种方式
AOF 启动 修复 恢复
跟dump一样 aof也要复制一份到别的机器上进行备份。
Rewrite
64Mb 是默认 实际的公司3Gb起步。
优势
劣势
总结
两种持久化方法的总结
AOF解决了RDB的老问题,但是带来了新问题,所以接下来用主从复制来解决AOF的新问题。
事务
是什么
按顺序进行批处理多个命令,要么一起成功,要么一起失败。
能干嘛
怎么玩
常用命令
正常执行
MULTI 开启事务
输入命令不会被马上执行,只会返回queue入队。
使用EXEC进行事务的执行。
放弃事务
命令写到一半,不想执行了,直接discard退出事务不执行。
全体连坐
只要有一个命令有错误,事务中的所有命令都不会被执行。
冤头债主
k1 不能加1 ,出现该错误 5个命令只有错误的不被执行 正确的都会被执行。
跟上面的区别:
之前的全体连坐是 敲入某命令后 直接报错,不会返回 queue.然后再exec执行会使所有的都不会被执行。
冤头债主是敲入某命令后返回 queue.然后再exec执行错误的命令不被执行 正确的被执行。
类似于一个编译出错,一个编译没错但是运行时出错。
说明redis对事务是部分支持
watch监控
大家都在改,为了防止冲突和覆盖,需要进行监控。
悲观锁、乐观锁和CAS(check and set)
数据库中:
表锁 锁整张表,一致性最好,并发性最差
行锁,只锁一行
一般工作都是用乐观锁。
初始化信用卡可用余额和欠额
修改的时候先加watch进行监控,如果提交不成功,说明有别人插手修改,这时候要重新watch,重新修改,直到修改成功。
自己演示
三个特性
Redis 发布订阅
Redis的复制(主从复制,读写分离)
怎么玩
-
配从库不配主库
假设有1台主机和两台从机,对从机进行相应配置,对主机不作修改。 -
从库配置
在从机上打该命令,例如认IP为81的机器为老大 ,加上老大发布的redis的服务。
细节:如果断开,那么每次断开,从机都要重新配置该命令,除非写进配置文件,每次启动都自动配置。 -
修改配置文件细节操作
第一步,复制多个配置文件
第二步:修改6379配置文件
6379配置好,下面是6380:
6380修改好,下面修改6381:
-
常用三招
第一招:一主二仆
想象三台机器,各自开了一个redis服务。
类似的启动80 81
看效果:
都输入 info replication
可以看到三者都是master
将6380 6381 变成 6379 的从机, 在6380 和6381中输入命令:
slaveof 127.0.0.1 6379
随后80 81 会将79 所有的数据备份
读写分离 只有主机可以写,从机不能。
如果主机死了 那么从机是原地待命 不会变成主机。
当主机重新回来,继续:
说明之前的主仆关系依旧存在。
如果一个从机挂了
那么重新连接上 他会变成master 只有重新连接主机 才能变成从机。
第二招:薪火相传
如何从之前的一主两仆的关系变成薪火相传的关系:
80挂79, 81挂80 直接在81输入命令
slaveof 80
80 还是slave
第三种:反客为主
主机挂了,使用在80输入命令 slaveof no one
可以看到80变成了master
这时候在81 输入 slaveof 127.0.0.1 6380
81变成了80的小弟。
这时候79回来了 会怎么办?
79一套体系 80 81一套体系。互不相关。
复制原理
第一次全量复制 其后都是增量复制
只要断开重连 都是全量复制。
哨兵模式(重要)
反客为主的自动版
演示:
现在的模式 是主 79 从80 81
建一个文件 文件名一定不要错。
然后打开文件,将命令复制进去。如图所示
配置哨兵 填写内容
启动哨兵
看到以下界面:
或者
哨兵选出80为主机。
如果79回来后:发现自己是slave了,这一点跟主动选主机的模式不一样(回来后还是master 只是手下没有slave)
缺点
Java redis 测试连通
想在Java上使用redis 需要安装redis驱动 ,首先:
跟上个项目一样 建立一个dynamic web project
注意一定要把src文件夹显示出来 并将下面三个添加 有教程。 按照教程(搜ecplise 不显示src文件 和 如何添加JRE System Library)总是不显示 但是重新建一个Java项目后 就都可以显示了 奇怪!!!
然后在下图的第三步 右键lib 点粘贴,将两个jar包加入
然后建包
建好后建一个类
然后启动redis服务
在建好的Java文件里加以下代码 如果是在Linux下的本机连的 输入127.0.0.1 如下图所示,如果是在远程 请输入Linux的IP地址 在Linux下使用 ifconfig 命令查询。
随后运行该文件 得到 pong 说明连接成功!
Jedis 常用API
然后运行
这里也可以查到。
这就是可以通过Java将数据灌入缓存。一定记住redis中的数据一般放热点、高频的数据。
Jedis 事务提交
package com.redis.test;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;
public class TestTx {
public static void main(String[] args){
Jedis jedis=new Jedis("127.0.0.1",6379);
Transaction transaction =jedis.multi();
transaction.set("k4", "v4");
transaction.set("k5", "v5");
transaction.set("k6", "v6");
transaction.exec();
}
}
执行后
package com.redis.test;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;
public class TestTx {
public boolean transMethod() {
Jedis jedis=new Jedis("127.0.0.1",6379);
int balance;
int debt;
int amtToSubtract=10;
jedis.watch("balance");
balance=Integer.parseInt(jedis.get("balance"));
if(balance<amtToSubtract) {
jedis.unwatch();
System.out.println("modify");
return false;
}
else {
System.out.println("*********transaction");
Transaction transaction =jedis.multi();
transaction.decrBy("balance",amtToSubtract);
transaction.incrBy("debt",amtToSubtract);
transaction.exec();
balance = Integer.parseInt(jedis.get("balance"));
debt = Integer.parseInt(jedis.get("debt"));
System.out.println("********* "+ balance);
System.out.println("********* "+ debt);
return true;
}
}
public static void main(String[] args) {
TestTx test=new TestTx();
boolean retValue=test.transMethod();
System.out.println("main retValue---: "+retValue);
}
}
运行
Jedis 主从复制
package com.redis.test;
import redis.clients.jedis.Jedis;
public class TestMS {
public static void main(String[] args){
Jedis jedis_M =new Jedis("127.0.0.1",6379);
Jedis jedis_S =new Jedis("127.0.0.1",6380);
jedis_S.slaveof("127.0.0.1",6379);
jedis_M.set("class", "1122");
String result=jedis_S.get("class");
System.out.println(result);
}
}
为啥一个可以 Java不可以? 内存数据库太快了!!!
JedisPool