上虞第一城市门户欢迎您!   手机上虞广播网

redis实战技巧大合集

来源:上虞门户网  2019-04-29 10:31

1. 安装docker run -d --name redis -p 6379:6379 redis:2.8

node操作redis需要引入redis包; const redis = require('redis');

const client = redis.createClient( 6379, '127.0.0.1');

const util = require('util');

2. 鉴权登录

修改redis.conf配置文件,然后重启服务requirepass 123 指定密码123

3. 工具使用

redis-server: 用于启动redis服务端

redis-cli: redis 客户端, 使用命令 redis-cli -h 127.0.0.1 -p 6379 连接redis服务器

redis-check-dump: redis dump数据文件的修复工具,导入失败,用于修复导入文件

redis-check-aof: redis aof日志文件修复工具,重启服务失败时,用于修复日志文件

redis-sentinel: 用于实现redis集群高可用(自动切换master和服务发现)

redis-benchmark: redis性能检测工具

4. 性能优化

读写分离: redis支持主从模式。redis的Master会将数据同步到slave,而slave不会将数据同步到master。Slave启动时会连接master来同步数据。因此Master写内存快照,save命令调度rdbSave函数,会阻塞主线程的工作,当快照比较大时对性能影响是非常大的,会间断性暂停服务,所以Master最好不要写内存快照。

slave开启AOF备份数据,而非master。 Master AOF持久化,如果不重写AOF文件,这个持久化方式对性能的影响是最小的,但是AOF文件会不断增大,AOF文件过大会影响Master重启的恢复速度。Master最好不要做任何持久化工作,推荐为某个Slave开启AOF备份数据,策略为每秒同步一次。

redis主从在同一个局域网内: Redis主从复制的性能问题,为了主从复制的速度和连接的稳定性,Slave和Master最好在同一个局域网内

5. redis的优点

操作都是原子性,所谓原子性就是对数据的更改要么全部执行,要不全部不执行。

订阅发布模式

可设置缓存过期时间

单线程,事件驱动,IO多路复用,利用redis队列技术并将访问变为串行访问,消除了传统数据库串行控制的开销

redis速度快,因为数据存在内存中

redis支持丰富的数据类型

redis可持久化,

缓存以支持高并发

支持事务,所有的命令要么都被一起处理,要么全都没有被处理。如果在事务中可能会执行失败,但是Redis事务不会回滚,而是继续会执行余下的命令。如果操作执行一半中断后,重启服务后会Redis在重新启动时会检测这种情况,并报错,然后退出。使用 redis-check-aof工具可以检查AOF,并移除那不完整的事务,使服务可以再次启动

6. redis相关问题

可扩展性,所以出现了codis(redis+zookeeper)

缓存预热: 系统上线后,将相关的缓存数据直接加载到缓存系统。这样避免用户请求的时候,再去加载相关的数据

缓存雪崩问题: 缓存雪崩是指在某一个时间段,缓存集中过期失效,所有请求都去查询数据库,而对数据库CPU和内存造成巨大压力,严重的会造成数据库宕机。如果是单个缓存出现这样的问题一般问题不大,数据库能扛得住这个压力,如果必须单个点可以在缓存过期前重新set缓存,或者直接设置一个超长缓存或永久缓存;但如果某台redis服务器挂掉,则会出现严重的缓存雪崩问题, 只能做好监控,然后快速的添加机器恢复缓存数据。

缓存击穿问题: 缓存穿透是指用户查询数据,在数据库没有,自然在缓存中也不会有。这样就导致用户查询的时候,在缓存中找不到,每次都要去数据库再查询一遍,然后返回空。这样请求就绕过缓存直接查数据库,这也是经常提的缓存命中率问题。解决的办法就是:如果查询数据库也为空,直接设置一个默认值存放到缓存,再次查询就直接返回空了,这样第二次到缓冲中获取就有值了,而不会继续访问数据库。

缓存的并发竞争问题: 主要是并发写问题, 即假设有某个key = "price", value值为10,现在想把value值进行+10操作。正常逻辑下,就是先把数据key为price的值读回来,加上10,再把值给设置回去。如果只有一个连接的情况下,这种方式没有问题,可以工作得很好,但如果有两个连接时,两个连接同时想对price进行+10操作,就可能会出现问题了。这种问题比较通用的解决方法是事务。

redis机器master之间一致性问题(扩容缩容如何保持master一致性

redis分布式锁:事务中实现;

7. redis的key回收策略redis的key回收机制:redis采用的是定期删除+惰性删除策略。如果采用定时删除,则会耗CPU;故采用定期删除+惰性删除策略。

惰性淘汰机制: 在进行get或setnx等操作时,先检查key是否过期,若过期,删除key,然后执行相应操作; 若没过期,直接执行相应操作;

定期删除:是主动删除机制, redis每隔一段时间随机取一部分key进行过期判断,如果过期则删除;服务端定时的去检查失效的缓存,如果失效则进行相应的操作。【redis基于事件驱动的,一类是IO事件,一类是定时事件】

redis的key回收过程: 无论是惰性淘汰机制还是定期删除机制,都是先从expires中查找key的过期时间,如果不存在说明对应key没有设置过期时间,直接返回,如果是slave机器,则直接返回,因为Redis为了保证数据一致性且实现简单,将缓存失效的主动权交给Master机器,slave机器没有权限将key失效。如果当前是Master机器,且key过期,则master会做两件重要的事情:1)将删除命令写入AOF文件。2)通知Slave当前key失效,可以删除了。master从本地的字典中将key对于的值删除;

redis的key回收方式

配置文件里redis.conf的maxmemory_policy:noeviction用以设置缓存到期后的数据淘汰机制,默认为noeviction

volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰

volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰

volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰

allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰

allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰

noeviction(驱逐):禁止驱逐数据

8. redis的两种数据持久化方案

redis允许采用RDB和AOF两种方案提供了将数据定期自动持久化至硬盘的能力,两者的区别在于RDB同步的是数据,AOF同步的是操作。

1. RDB

说明: Redis会定期保存数据快照至一个rbd文件中,并在启动时自动加载rdb文件,恢复之前保存的数据

配置 # 时间策略

save 900 1 # 如果900s内有1条写入命令,就触发产生一次快照,进行一次备份;

save 300 10

save 60 10000

# save "" # 如果设置成""则禁用RDB

# 当备份进程出错时,主进程就停止接受新的写入操作,是为了保护持久化的数据一致性

stop-writes-on-bgsave-error yes

# 是否压缩

rdbcompression yes

# 导入时是否检查

rdbchecksum yes

# 文件名

dbfilename dump.rdb

# 文件会被写到dir里

dir

优点

对性能影响最小。如前文所述,Redis在保存RDB快照时会fork出子进程进行,几乎不影响Redis处理客户端请求的效率。

每次快照会生成一个完整的数据快照文件,所以可以辅以其他手段保存多个时间点的快照

使用RDB文件进行数据恢复比使用AOF要快很多。缺点

快照是定期生成的,所以在Redis crash时或多或少会丢失一部分数据

如果数据集非常大且CPU不够强(比如单核CPU),Redis在fork子进程时可能会消耗相对较长的时间,影响Redis对外提供服务的能力。

2. AOF

说明: AOF持久方式时,Redis会把每一个写请求都记录在一个日志文件里。在Redis重启时,会把AOF文件中记录的所有写操作顺序执行一遍,确保数据恢复到最新

AOF配置详解 # 开启AOF模式

appendonly: yes

# AOF文件名

appendfilename "appendonly.aof"

# 三种文件同步策略, no,不设置同步策略,由系统决定; everysec,后台线程每秒同步一次; always:每写入一条日志同步一次,数据安全性最高,速度最慢;

appendfsync everysec

# AOF自动重写机制

# 在重写阶段是否允许同步

no-appendfsync-on-rewrite no

# redis会记录上次重写时的AOF大小,默认配置是当AOF文件大小比基础大小大制定的百分比, 或者如果现在的大小比基础大小大制定的百分比,是上次rewrite后大小的一倍且文件大于64M时触发。默认64M。

auto-aof-rewrite-percentage 100

auto-aof-rewrite-min-size 64mb

# redis在恢复时,会忽略最后一条可能存在问题的指令

aof-load-truncated yes

优点同步所有写操作,安全性高缺点相同数据集的数据而言aof文件要远大于rdb文件,恢复速度慢于rdb

3. redis的导入导出

使用redis-dump

aof导入方式

redis.conf里配置appendonly yes,

cp appendonly.aof 到redis的数据库目录也就是配置文件里面的dir关键字

重启服务rdb导入方式

redis.conf里配置appendonly no,

cp dump.rdb 到redis的数据库目录也就是配置文件里面的dir关键字

重启服务

9. string(字符串)

一个字符串类型的值最大长度为512 M。

常见操作: get,set,mget,mset,incr(计数器++),decr(--)等等; client.set('hello', 5, function(err, obj) {

client.incr('hello', function(err,data) {

client.get('hello', function(err,data) {

console.log(data); // 6

})

})

})

10. hash(哈希)hash可用来存储对象,一个Redis 列表中最多可存储232-1(40亿)个元素 var obj = {

name:'sss',

age:223

}

client.hset("test", obj, function(err, obj) {

client.hgetall('test', (err, obj) => {

console.log(`hgetall:${JSON.stringify(obj)}`);

console.log(obj.age);

})

client.hget('test','name', function(err, name) {

console.log('hget test name');

console.log(name);

})

});

11. lists(列表)

对于lists,使用send_command进行操作;

队列操作

list,常用操作, list,常用操作, lpush(首位添加),rpush(末位添加),lset(修改首位值),lindex(删除首位元素),lpop(删除末位元素)

一个Redis 列表中最多可存储232-1(40亿)个元素 client.send_command('lset',['mylist',0,1], function(err,data) {

console.log(data); // OK

})

client.send_command('lpush',['mylist', 'one'], function(err, data) {

console.log(dada); //OK

})

// 使用命令行获取对应的索引下的结果

// lindex mylist 0 'one'

// lindex mylist 1 '1'

// lindex mylist 2 'xxx'

// lindex mylist 3 'xxx'

12. sets(集合)

sets 集合处理; 业务中用lodash进行交并补也是一个不错的选择。

常见操作: sadd、smembers、sinter(交)、sunion(并)、sdiff(补)、smove

集合中不允许重复成员的存在。当多次添加一个元素时,其结果会设置单个成员多次。一个Redis 集合中最多可包含232-1(40亿)个元素。 let db1 = ['mysql','redis'];

let db2 = ['mongo','redis'];

client.sadd('db1',db1, function(err,data) {

client.smembers('db1', function(err,data) {

console.log(toString.call(data)); // [object Array]

console.log('smemers:' + data); // 获取set中的成员, ['redis,mysql]

})

client.sadd('db2', db2, function(err, data) {

client.sinter('db1','db2', function(err,data) {

console.log('sinter:' + data) //交集: sinter:redis

});

client.sunion('db1','db2', function(err,data) {

console.log('sunion:' + data) // 并集: sunion:mongo,mysql,redis

});

client.sdiff('db1','db2', function(err,data) {

console.log('SDIFF:' + data) // 补集: SDIFF:mysql

})

})

});

13. 有序集合(SortedSets)常用操作: zadd(设置元素), zrange(获取范围内的元素),zrank(获取指定元素的排名,从0开始), zscore(获取指定元素的score,用户指定的score) client.zadd(['zdb',0,'mysql', 1,'mongo',2,'redis'], function(err, data) {

console.log(data); // 3

})

14. 事务事务(multi命令): 批量执行所有的命令,并统一返回结果 client.multi()

.set('xiao','xing')

.get('xiao')

.exec(function(err,replies) {

console.log(replies); // [ 'OK', 'xing' ]

})

15. 订阅发布模式

redis的订阅发布模式可用来做类似kafka的消息推送;

使用list + redis的订阅发布模式可以构建一个不错的消息队列; let sub = redis.createClient(6379, '127.0.0.1'); // 监听消费者

let pub = redis.createClient(6379, '127.0.0.1'); // 生产者

// 在sub开始监听时允许触发subscribe事件进行操作,类似连接数据库的connect事件

sub.on('subscribe', function(channel, count) {

console.log(`${channel}:${count}`); // test channel:1

pub.publish('test channel', 'channel message test')

})

sub.on('message', function(channel, message) {

console.log(`${channel}-message:${JSON.stringify(message)}`) // test channel-message:"channel message test"

})

sub.subscribe('test channel');

16. 对整个redis的所有客户端操作进行监听;monitor事件可以监听到redis收到的所有客户端命令 client.monitor(function(err, res) {

console.log(res); // ok

})

client.on("monitor", function (time, args) {

console.log(time + ": " + util.inspect(args)); // 1556285641.395573: [ 'lindex', 'myset', '2' ]

});

Copyright 2012-2013 上虞第一城市门户网站 版权所有

郑重声明:网站资源摘自互联网,如有侵权,麻烦通知删除,谢谢!