Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
Redis的特点是支持事务,支持持久化,支持集群,效率相较于mysql而言非常高。
Redis是单线程的。
修改redis的绑定ip
修改为0.0.0.0,即可通过外网访问
databases 数据库个数,一般不修改
redis通过守护进程启动,daemonize改成yes,可以后台启动
设置redis的密码,建议设置,因为远程连接需要有密码
修改好配置文件之后,即可通过redis-server 配置文件路径启动redis
[root@zhouge ~]# redis-server /etc/redis.conf
然后使用redis-cli进入命令行界面
输入auth + 刚才在配置文件里修改的密码即可登录
登录redis数据库之后可以进行一些操作。
登录
auth + 密码
选数据库
select 数字
数据库索引从0开始
一共16个(可以在配置文件里修改)
增删改查
set
多次set同一个key可以修改,新值会覆盖掉旧值
get
del
查看key
keys * 查看所有
keys name
keys na* 查看所有以na开头的
清库
flushdb 删除当前数据库的数据
flushall 删除所有数据库的数据
判断key是否存在
exists + key_name
若 key 存在返回 1 ,否则返回 0 。
设置过期时间
expire key seconds
ttl key 查看剩余时间
setex key seconds value 设置key并指定过期时间
set + key + value,添加
get + key,获取value
del + key,删除
append + key +value1,在key的value后面拼接value1
strlen + key,获取value的长度
incr + key,value+1,累加操作,只能对数字使用
decr + key,value-1,累减操作,只能对数字使用
getrange + key + 起始位置 + 结束位置,截取value字符串指定范围的内容
setrange + key + 替换起始位置 + 替换字符串,从指定位置开始替换字符串
setex + key + seconds + value,设置并指定过期时间
setnx 没有创建,有的话就作废
如set name aaa,set name bbb则name为bbb
但是setnx name aaa,setnx bbb则name为aaa
插入
lpush + 集合名key + value,左进
rpush + key + value,右进
弹出
lpop + key + value,左出
rpop + key + value,右出
查看
lrange + key +起始索引 + 结束索引,双闭区间
lindex + key + 索引
长度
llen + key
删除
lrem + key + count + value
COUNT 的值可以是以下几种:
count > 0 : 从表头开始向表尾搜索,移除与 VALUE 相等的元素,数量为COUNT。
count < 0 : 从表尾开始向表头搜索,移除与 VALUE 相等的元素,数量为COUNT 的绝对值。
count = 0 : 移除表中所有与 VALUE 相等的值
一个list右侧弹出到另一个list左侧
rpoplpush + 源集合 + 目标集合
修改指定位置的值
lset + key + index + value
插入
linsert + key + before + value + value1,在key集合中value前面插入一个value1
after同理
sadd + key + member,添加
smembers + key,显示key的全部成员
sismember + key + member,判断是否为key的成员
scard + key,长度
srem + key + member,删除key集合中的member成员
smove + 源集合 + 目标集合 + member,移动
srandmember + key,返回随机元素
spop + key,移除元素并返回
sdiff + key + key1,key的差集,谁在前为谁的差集
sunion + key + key1,key和key1的并集
sinter + key + key1,key和key1的交集
hset + key表名 + field键 + value值,添加
hget + key + field,获取value
hgetall + key,获取表所有数据,所有键值对的键和值都会显示出来
hdel + key + field,删除对应的value
hlen + key,获取表长度
hkeys + key表名,获取该表所有键
hvals + key,获取该表所有值
hexists + key + field,判断key表中是否有以field为键的键值对
hsetnx同String的setnx
hincrby + key + field + int,累加整数
hincrbyfloat + key + field + float,累加浮点数
特点
有序,有序的基础是给每一个value都加上一个分数,依靠分数排序
不重复,分数可以重复,但是值不行
常用api
zadd + key + score + value,添加
zrange + key + start起始位置 + stop结束位置,双闭区间,按照排名的范围查找
withscore,加在末尾,显示带着分数的结果
zrevrange + key + start起始位置 + stop结束位置,双闭区间,按照排名的范围逆序查找
zrangebyscore + key + min + max,按照分数的范围查找
withscores,加在末尾,显示带着分数的结果
limit,后面可以加limit用来截取显示结果
zrem +key + member,删除
zcard + key,获取成员个数
zcount + key + min + max,双闭区间,获取指定分数区间的个数
zrank + key + member,获取排名,相当于获取索引
zrevrank + key + member,获取逆序排名
zscore + key + member,获取分数
面试中的问题
Redis如何进行数据持久化
持久化的方式主要有两种
是什么
Redis中的一种数据持久化的方式
流程
Redis会fork一个子进程,定期的从内存将数据存入到磁盘中,下次再次启动Redis的时候,可以从磁盘中把数据加载到内存
特点
性能好,fork了一份子进程,主进程是没有额外的IO负担的,所以备份的效率比较高
RDB文件比较紧凑,是比较节约空间的
备份数据有间隙的,可能会造成数据丢失
使用场景
适合大规模数据的备份,对数据不敏感的时候可以使用这种方式
代码实现
修改redis中的配置
通过日志的方式记录redis的数据变化,进行数据的持久化
流程
写到redis内存的同时,会先写一份aof的日志,后续如果需要恢复的化,从头到尾执行日志里的内容就行了
特点
数据不会丢失
写入的性能差
恢复的性能差
文件占用空间大
应用场景
对数据完整要求比较高的时候
重写机制
aof的文件会越来越大,当文件大小达到阈值的时候,会触发rewrite,这时候会文件进行压缩操作,删除被覆盖掉的、无意义的操作。
代码实现
Redis远程连接
关闭保护模式(不推荐)
redis 保护模式默认开启,启动之后远程服务需要密码才能连接,如果 没有设置密码又需要远程连接,则需要把保护模式关闭 :protected-mode no
或者不关闭保护模式,则需要设置密码,jedis 需要带密码连接 redis。
设置密码(推荐)
设置密码:config set requirepass 123456
清空密码(需要重启):config set requirepass ''
获取密码:config get requirepass
防火墙
防火墙会阻止远程连接的请求,解决这一问题有两种方式。
关闭防火墙:systemctl stop firewalld
不关闭防火墙添加开放端口:firewall-cmd --add-port=6379/tcp
代码实现
//导入jedis依赖
redis.clients
jedis
3.3.0
public class TestRedis {
public static void main(String[] args) {
// 添加redis的连接的基本信息
JedisShardInfo shardInfo = new JedisShardInfo("192.168.2.119",6379);
shardInfo.setPassword("root");
// 获取jedis对象,jedis就是redis操作封装的工具类,可以通过他执行redis的命令
Jedis jedis = shardInfo.createResource();
// 进行后续操作
// 选库,10数据的库
jedis.select(10);
// 添加一个name 为xxx
jedis.set("name", "xxx");
// 添加一个list
jedis.lpush("list", "aaa", "bbb");
String name = jedis.lpop("list");
System.out.println(name);
jedis.lpush("list", "aaa", "bbb");
List list = jedis.lrange("list", 0,-1);
System.out.println(list);
jedis.flushDB();
jedis.close();
}
}
获取事务对象jedis.multi()
transcation.exec()提交事务
transcation.discard() 事务回滚
public class TransactionTest {
public static void main(String[] args) {
JedisShardInfo jedisShardInfo = new JedisShardInfo("192.168.2.114",6379);
jedisShardInfo.setPassword("root");
Jedis jedis = jedisShardInfo.createResource();
//获取事务对象
Transaction transaction = jedis.multi();
transaction.select(10);
transaction.set("name","kkk");
transaction.set("age","10");
//提交
//transaction.exec();
//回滚
transaction.discard();
}
}
public class JedisPoolUtil {
/**
* 数据库连接对象
*/
private static volatile JedisPool jedisPool = null;
private JedisPoolUtil() {
}
/**
* 双重锁检查单例模式
*
* @return
*/
public static JedisPool getJedisPoolInstance() {
if (null == jedisPool) {
synchronized (JedisPoolUtil.class) {
if (null == jedisPool) {
JedisPoolConfig poolConfig = new JedisPoolConfig();
// 控制一个 pool 最多有多少个状态为 idle(空闲)的 jedis 实例
poolConfig.setMaxIdle(32);
// 表示当 borrow 一个 jedis 实例时,最大的等待时间,如果超过等待时间,则直接抛 JedisConnectionException
poolConfig.setMaxWaitMillis(1000);
// 获得一个 jedis 实例的时候是否检查连接可用性(ping());如果为 true,则得到的 jedis 实例均是可用的
poolConfig.setTestOnBorrow(true);
jedisPool = new JedisPool(poolConfig, "192.168.2.114", 6379, 2000, "root");
}
}
}
return jedisPool;
}
/**
* 关闭连接池
*
* @param jedisPool
*/
public static void close(JedisPool jedisPool) {
if (!jedisPool.isClosed()) {
jedisPool.destroy();
}
}
public static void main(String[] args) {
JedisPool jedisPool = JedisPoolUtil.getJedisPoolInstance();
JedisPool jedisPool2 = JedisPoolUtil.getJedisPoolInstance();
// 测试是否为单例模式:true
System.out.println(jedisPool == jedisPool2);
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
// PONG
System.out.println(jedis.ping());
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭连接池对象
JedisPoolUtil.close(jedisPool);
}
}
}
rc.local是每次开机的时候都会执行的脚本,可以把一些需要开机自启的程序的启动命令放在这里
注意事项
需要赋予 /etc/rc.d/rc.local 可以执行权限
chmod a+x /etc/rc.d/rc.local
在/etc/rc.local里添加启动命令
redis-server redis.conf
删除策略一般有三种。
定时器删除。
给每个文件设置一个定时器,文件一过期就立即删除。
优点:节省存储空间
缺点:大量设置定时器太耗费运算资源
惰性删除。
数据过期后,并不会立刻删除,等到下次访问的时候,redis才会删除该数据。
优点:节省cpu的资源
缺点:可能存在大量的,无人访问的数据会一直存在服务器。
定期删除。
每秒钟定期对redis中每个库的数据进行轮询 轮询的数据,对过期的数据随机删除一部分。如果随机删除的数据占轮训数据的比例超过一定值,继续轮询删除。
主从复制的优点。
读写分离。一般读的数据量要比写大很多,所以主机进行写操作,读操作交给多台从机去负责。这样保障了写操作的效率,缓解的读操作的运行压力。
容灾处理。因为任意虚拟机都有完整的数据备份,所以任意虚拟机宕机都不会影响数据的完整。
如何实现主从复制
用单机模拟了分布式的场景时为了避免单机启动多个redis的时候文件冲突的问题需要进行如下配置。
修改port,端口号
修改pidfile,设置进程的pid的文件
修改logfile,日志文件
修改dbfilename,持久化文件存储路径
slave节点需要配置master节点的密码
masterauth
在slave节点执行
slaveof host port
eg:slaveof 192.168.2.119 6379
在执行完之后通过info replication 查看情况
注意事项
网络是通的,比如使用同一个wifi
master的防火墙是关的(或者端口开放)
连接方式
一主多仆
一台主机多台从机
薪火相传
从机再连接从机,多级传递
反客为主
master宕机了,slave节点可以接任master节点
slaveof no one 不选择任何主节点
复制方式
第一次是全量复制,每次重连的时候是全量复制
运行的过程中都是增量复制
缺点
传输过程中会有延迟,当从节点链路过长的时候,延迟更严重
一个主节点从节点过多,也会造成主节点的负担
什么是哨兵
Sentinel(哨兵)是用于监控Redis集群中Master状态的工具,是Redis高可用解决方案,哨兵可以监视一个或者多个redis master服务,以及这些master服务的所有从服务。
某个master服务宕机后,会把这个master下的某个从服务升级为master来替代已宕机的master继续工作。
添加配置文件
在自己新建的sentinel.conf文件中添加
添加机器节点
sentinel monitor
设置密码
sentinel auth-pass
示例:
//一主二仆如下
sentinel monitor redis119-79 192.168.2.119 6379 1
sentinel auth-pass redis119-79 root
sentinel monitor redis145-79 192.168.2.188 6379 1
sentinel auth-pass redis145-79 root
sentinel monitor redis119-80 192.168.2.119 6380 1
sentinel auth-pass redis119-80 root
//若有更多自由添加即可
//所有的都要写在这个文件中
启动哨兵
redis-sentinel sentinel.conf