1.1. 什么是redis:
redis是一个开源(BSD许可)的,内存中的数据结构存储系统
1.2. Redis的用途:
数据库、缓存和消息中间件
在“怎样让Redis在你的系统中发挥作用”一文中,Salvatore 'antirez’ Sanfilippo告诉我们如何利用Redis独有的数据结构处理能力来解决一些常见问题。一些Redis原语命令比如LPUSH、LTRIM和LREM等等能够用来帮助开发者完成需要的任务——这些任务在传统的数据库存储中非常困难或缓慢。这是一篇非常有用并且实际的文章。那么要如何在你的框架中完成这些任务呢?
下面列出11种Web应用场景,在这些场景下可以充分的利用Redis的特性,大大提高效率。
1.在主页中显示最新的项目列表。
Redis使用的是常驻内存的缓存,速度非常快。LPUSH用来插入一个内容ID,作为关键字存储在列表头部。LTRIM用来限制列表中的项目数最多为5000。如果用户需要的检索的数据量超越这个缓存容量,这时才需要把请求发送到数据库。
2.删除和过滤。
如果一篇文章被删除,可以使用LREM从缓存中彻底清除掉。
3.排行榜及相关问题。
排行榜(leader board)按照得分进行排序。ZADD命令可以直接实现这个功能,而ZREVRANGE命令可以用来按照得分来获取前100名的用户,ZRANK可以用来获取用户排名,非常直接而且操作容易。
4.按照用户投票和时间排序。
这就像Reddit的排行榜,得分会随着时间变化。LPUSH和LTRIM命令结合运用,把文章添加到一个列表中。一项后台任务用来获取列表,并重新计算列表的排序,ZADD命令用来按照新的顺序填充生成列表。列表可以实现非常快速的检索,即使是负载很重的站点。
5.过期项目处理。
使用unix时间作为关键字,用来保持列表能够按时间排序。对current_time和time_to_live进行检索,完成查找过期项目的艰巨任务。另一项后台任务使用ZRANGE...WITHSCORES进行查询,删除过期的条目。
根据这个特性,支持web项目的session信息的持久化,可以设定超时时间,根据sessionid值来唯一标示,这种用法,我再flask-session的 RedisSessionInterface 提供的redis持久化的接口,php yii框架中,其中也可以使用redis做类似的功能实现.
6.计数。
进行各种数据统计的用途是非常广泛的,比如想知道什么时候封锁一个IP地址。INCRBY命令让这些变得很容易,通过原子递增保持计数;GETSET用来重置计数器;过期属性用来确认一个关键字什么时候应该删除。
7.特定时间内的特定项目。
这是特定访问者的问题,可以通过给每次页面浏览使用SADD命令来解决。SADD不会将已经存在的成员添加到一个集合。
8.实时分析正在发生的情况,用于数据统计与防止垃圾邮件等。
使用Redis原语命令,更容易实施垃圾邮件过滤系统或其他实时跟踪系统。
9.Pub/Sub。
在更新中保持用户对数据的映射是系统中的一个普遍任务。Redis的pub/sub功能使用了SUBSCRIBE、UNSUBSCRIBE和PUBLISH命令,让这个变得更加容易。
10.队列。
在当前的编程中队列随处可见。除了push和pop类型的命令之外,Redis还有阻塞队列的命令,能够让一个程序在执行时被另一个程序添加到队列。你也可以做些更有趣的事情,比如一个旋转更新的RSS feed队列。
11.缓存。
Redis缓存使用的方式与memcache相同。
网络应用不能无休止地进行模型的战争,看看这些Redis的原语命令,尽管简单但功能强大,把它们加以组合,所能完成的就更无法想象。当然,你可以专门编写代码来完成所有这些操作,但Redis实现起来显然更为轻松。
未完待续...
转载于:https://blog.51cto.com/caochun/1903550
windows 安装redis 链接
https://blog.csdn.net/qq_43220278/article/details/90444937
安装 windows phpredis扩展
https://www.php.cn/jishu/php/412784.html
如果在命令行窗口输入redis-server.exe redis.windows.conf指令执行报错误[13164] 27 Dec 20:57:07.820 # Creating Server TCP listening socket 127.0.0.1:637 9: bind: No error。那么可以输入如下的命令依次执行第一条指令:redis-cli.exe,第二条指令:shutdown第三条指令:exit
一、为什么使用解决应用服务器的cpu和内存压力
减少io的读操作,减轻io的压力
关系型数据库的扩展性不强,难以改变表结构
二、优点:
nosql数据库没有关联关系,数据结构简单,拓展表比较容易
nosql读取速度快,对较大数据处理快
三、适用场景:
数据高并发的读写
海量数据的读写
对扩展性要求高的数据
四、不适场景:
需要事务支持(非关系型数据库)
基于sql结构化查询储存,关系复杂
五、Redis结构:
Redis是一个开源的key—value型数据库,支持string、list、set、zset和hash类型数据。对这些数据的操作都是原子性的,redus为了保证效率会定期持久化数据。
六、使用场景:
配合关系型数据库做高速缓存
缓存高频次访问的数据,降低数据库io
分布式架构,做session共享
可以持久化特定数据。
利用zset类型可以存储排行榜
利用list的自然时间排序存储最新n个数据
七、Linux下redis:
redis目录:usr/local/bin
linux下redis常用命令:
redis-benchmark:性能测试工具
redis-server:启动redis服务器
redis-cli:启动redis客户端,操作入口
八、Redis基础知识
端口:6379
默认16个数据库,下标从0开始
单线程:redis是单线程+io多路复用:检查文件描述的就绪状态
Memchached:多线程+锁
redis数据类型:String set list hash zset
九、Redis命令:
key操作
keys * 查看当前库所有的键
exists 判断是否存在key
del 删除某个键
expire 设置键过期时间 单位是s秒
ttl 查看还有多少秒过期 -1表示用不过期 -2表示已经过期
move 把键移到另一个库下
dbsize 查看数据库key的数量
flushdb 清空当前库
flushall 通杀所有库
String类型:String是二进制安全的,可以包含任何数据源,最大512mget 查看对应的键值
set 添加键值对
append 将给定的value 追加到原值的末尾
strlen < key > 获取值得长度
setnx 当key 不存在的时候设置key值
incr 将key中储存的数字加1,如果为空,则值为1
decr 将key中储存的数字减1,如果为空,则值为-1
incrby/decrby <步长> 将key中的数字增减
String批量处理:mset 同时设置多个键值对
mget <key 2> 同时获得多个值
msetnx 当给定的key都不存在
getrange类似sunstring
setrange类似sunstring覆盖原始值
setex <过期时间> 设置键值的同时,给定过期时间
getset 以旧换新,设置了新的值同时得到旧值
List:链表1、特点:
单键多值
Redis列表是简单的字符串列表,从左或者从右插入
底层是双向链表,对两端的操作性能很高,通过下标查询性能很低
lpush/rpush … 从左或从右插入多个值
lpop/rpop 从左边或右边吐出一个值,值光键亡
rpoplpush 从key1 右边吐出一个值到key2的左边
lrange 按照索引下标获取元素 从左到右
lindex 按照索引下标获取元素 从左到右
llen 获取列表长度 获取列表长度
linsert before 在key中value前插入newvalue
Set:类似list的无序集合,保证列表中不会有重复数据,底层是一个value为null的hash表sadd 将多个元素加入到key中,重复值忽略
smembers 取出该集合的所有值
sismember 判断集合key中是否有该value值 有就1 没有0
scard 返回该集合的元素个数
srem 删除集合中的某个元素
spop 随机吐出该集合一个值
srandmember 随机从集合中取出n个值,不会从集合中删除
smove 将key1中的value 移动到key2 中
sinter 返回两个集合的交集元素
sunion 返回两个集合的并集
hash:键值对集合,类似map<String,Object>hset 给key 集合中的file 键赋值value
hget 从key1 集合file取出value
hmset 批量设置hash的值
hexists 查看key中的field 是否存在
hkeys 列出key中所有的filed
hvals 列出该hash集合中所有的value
zset:与set集合非常相似,每个成员都关联了score,可以用来排序zadd 将一个或多个元素以及score加入zset
zrangewithscore 返回下标在区间内的集合,带有score
zrangebyscore [withscore] [limit offset count] 返回key中 score介于min和max中的成员,升序排列
zrevrangerbyscore [withscore] [limit offset count] 降序
zincrby 在key集合中的value上增加increment
zrem 删除key集合下的指定元素
zcount 统计 区间内的元素个数
zcord 获取集合中的元素个数
zrank 查询value在key中的排名,从0开始
十、redis持久化:两种方式:rdb(redis database)和aof(append of file)
RDB:在指定时间间隔内,将内存中的数据作为一个快照文件(snapshot)写入到磁盘,读取的时候也是直接读取snapshot文件到内存中
①持久化过程:redis单独创建(fork)一个进程来持久化,会先将数据写入临时文件中,待上次持久化结束后,会将该临时文件替换上次持久化文件,比aof高效,但是最后一次数据可能会丢失
②Fork:在linux中,fork()会产生一个跟主进程一样的子进程,出于效率考虑,主进程和子进程会公用一段物理内存,当发生改变的时候,才会把主进程“”写时复制”一份给子进程
③Redis备份的文件:在redis.conf中设置,dbfilename默认为:dump.rdb
④ Rdb保存策略:
900s 1 file change
300s 10file change
60s 10000file change
⑤Rdb的备份:
config get dir 得到备份的文件夹
复制备份文件
⑥Rdb恢复:
关闭redis
将备份文件复制到工作目录下
启动redis,自动加载
AOF : 以日志形式记录每个写操作,启动时通过日志恢复操作
开启AOF:默认不开启,进入redis.conf找到appendonly yes打开
修复AOF:redis-check-aof –fix appendonly.aof
同步频率:每秒记录一次,如果宕机该秒记可能失效
Rewrite:bgrewriteaof 因为日志是追加方式,文件会越来越大,当超过了设置的阈值时,日志文件会压缩,保留仅可以恢复的日志
RDB和AOF对比
节省磁盘空间
恢复速度快
RDB优点:
ROD缺点:
数据太大时,比较消耗性能
一段时间保存一次快照,宕机时最后一次可能没有保存
c) AOF优点:
i. 备份机制更加稳健
ii. 可读的日志文件,通过aof恢复更加稳健,可以处理失误
d) AOF缺点:
i. 比RDB更占磁盘
ii. 备份速度较慢
iii每次都同步日志,有性能压力
RDB和AOF哪个好
官方推荐都启用
对数据不敏感,单独用RDB
不建议单独使用AOF
若作为纯缓存使用,可以都不开启
十一、Redis事务:输入multi,输入的命令都会依次进入到队列中,但不会执行,直到输入exec,redis会将之前命令队列中的命令依次执行,通过discard可以放弃组队。
主要作用:序列化操作,串联多个命令防止别的命令插队
悲观锁:每次拿到数据的时候都会上锁,或者等待别人处理完再去拿锁,传统的关系型数据库里边很多用到了这种锁机制,比如行锁、表锁、读锁、写锁
乐观锁:每次拿数据的时候总认为别人不会修改数据,所以不会上锁。但是更新的时候回去判断别人有没有更改数据,使用版本号机制。乐观锁适用于多读的应用类型,可以提高吞吐量。
Redis使用乐观锁:redis就是利用check-and-set机制实现事务
三大特性:
单独的隔离操作:事务中的所有命令都会序列化,按顺序执行。不会被其他客户端打断
没有隔离级别概念:队列中的命令没有提交之前不会被执行,事务外不能查看事务内的更新
不能保证原子性:跳过错误,依旧执行,没有回滚
十二、Redis订阅/发布:
是进程中的一种消息通信模式,发送者pub发送消息,订阅者sub接收消息 剩下的略。。。
十三、Redis主从复制:
是什么:主从复制就是主机数据更新后根据配置和策略,自动同步到备份机的master/slaver机制,master写为主,slave读为主
用处:
读写分离,性能拓展。
容灾快速恢复
配置服务器(配从不配主):
拷贝多个redis.conf文件
开启daemonize yes
Pid文件名字
指定端口
Log文件名字
Dump.rdb名字
Appendonly 关掉或者换名字
十四、Jedis:
所需jar包:
common-pool-1.6jar包
jedis-2.1
获取jedis对象:Jedis jedis = new Jedis(“ip” ,端口号);
十五、集群分布:
实现对redis的水平拓展,启动n’的redis节点,将整个数据分布在这n个节点中
配置conf文件:
拷贝多个redis.conf文件
开启daemonize yes
Pid文件名字
指定端口
Log文件名字
Dump.rdb名字
Appendonly 关掉或者换名字
配置cluster文件:
cluster-enable yes 打开集群模式
cluster-config-file xxx.conf 设置生成的节点配置文件名
cluster-node-timeout 15000设置节点失联时间,超多该时间(毫秒),集群自动进入主从切换
1.1. 什么是redis:
redis是一个开源(BSD许可)的,内存中的数据结构存储系统
1.2. Redis的用途:
数据库、缓存和消息中间件
转载于:https://www.cnblogs.com/cslgzl/p/10533131.html
分布式锁(string)
setnx key value,当key不存在时,将 key 的值设为 value ,返回1。若给定的 key 已经存在,则setnx不做任何动作,返回0。
当setnx返回1时,表示获取锁,做完操作以后del key,表示释放锁,如果setnx返回0表示获取锁失败。设置过期时期,当遇到宕机时,会在过期后释放锁。
计数器(string)
如知乎每个问题的被浏览器次数

set key 0
incr key // incr readcount::{帖子id} 每阅读一次
get key // get readcount::{帖子id} 获取阅读量
分布式全局唯一id(string)
分布式全局唯一id的实现方式有很多,这里只介绍用redis实现

每次获取userId的时候,对userId加1再获取,可以改进为如下形式

直接获取一段userId的最大值,缓存到本地慢慢累加,快到了userId的最大值时,再去获取一段,一个用户服务宕机了,也顶多一小段userId没有用到
incr :自增1
incrby:自增一小段
set userId 0
incr usrId //返回1
incrby userId 1000 //返回10001
消息队列(list)
在list里面一边进,一边出即可
# 实现方式一
# 一直往list左边放
lpush key value
# key这个list有元素时,直接弹出,没有元素被阻塞,直到等待超时或发现可弹出元素为止,上面例子超时时间为10s
brpop key value 10
# 实现方式二
# 一直往list右边放
rpush key value
blpop key value 10

新浪/Twitter用户消息列表(list)

假如说小编li关注了2个微博a和b,a发了一条微博(编号为100)就执行如下命令
lpush msg::li 100
b发了一条微博(编号为200)就执行如下命令:
lpush msg::li 200
假如想拿最近的10条消息就可以执行如下命令(最新的消息一定在list的最左边):
# 下标从0开始,[start,stop]是闭区间,都包含
lrange msg::li 0 9
抽奖活动(set)
# 参加抽奖活动
sadd key {userId}
# 获取所有抽奖用户,大轮盘转起来
smembers key
# 抽取count名中奖者,并从抽奖活动中移除
spop key count
# 抽取count名中奖者,不从抽奖活动中移除
srandmember key count
实现点赞,签到,like等功能(set)

# 1001用户给8001帖子点赞
sadd like::8001 1001
# 取消点赞
srem like::8001 1001
# 检查用户是否点过赞
sismember like::8001 1001
# 获取点赞的用户列表
smembers like::8001
# 获取点赞用户数
scard like::8001
实现关注模型,可能认识的人(set)

seven关注的人
sevenSub -> {qing, mic, james}
青山关注的人
qingSub->{seven,jack,mic,james}
Mic关注的人
MicSub->{seven,james,qing,jack,tom}
# 返回sevenSub和qingSub的交集,即seven和青山的共同关注
sinter sevenSub qingSub -> {mic,james}
# 我关注的人也关注他,下面例子中我是seven
# qing在micSub中返回1,否则返回0
sismember micSub qing
sismember jamesSub qing
# 我可能认识的人,下面例子中我是seven
# 求qingSub和sevenSub的差集,并存在sevenMayKnow集合中
sdiffstore sevenMayKnow qingSub sevenSub -> {seven,jack}
电商商品筛选(set)

每个商品入库的时候即会建立他的静态标签列表如,品牌,尺寸,处理器,内存
# 将拯救者y700P-001和ThinkPad-T480这两个元素放到集合brand::lenovo
sadd brand::lenovo 拯救者y700P-001 ThinkPad-T480
sadd screenSize::15.6 拯救者y700P-001 机械革命Z2AIR
sadd processor::i7 拯救者y700P-001 机械革命X8TIPlus
# 获取品牌为联想,屏幕尺寸为15.6,并且处理器为i7的电脑品牌(sinter为获取集合的交集)
sinter brand::lenovo screenSize::15.6 processor::i7 -> 拯救者y700P-001
排行版(zset)
redis的zset天生是用来做排行榜的、好友列表, 去重, 历史记录等业务需求

# user1的用户分数为 10
zadd ranking 10 user1
zadd ranking 20 user2
# 取分数最高的3个用户
zrevrange ranking 0 2 withscores
发布,订阅消息(消息通知)
比如你关注了迪丽热巴,迪丽热巴发微博你就会收到推送

引用: https://www.cnblogs.com/xinde123/p/8489054.html
redis的发布与订阅(发布/订阅)是它的一种消息通信模式,一方发送信息,一方接收信息。
下图是三个客户端同时订阅同一个频道

下图是有新信息发送给频道1时,就会将消息发送给订阅它的三个客户端

java实现 redis的发布订阅
回顾java如何操作redis:
redis是一种缓存数据库,它也是C/S的结构,也就是客户端和服务端,一般来说,在java中,我们通常使用
jedis(客户端)去操作redis(服务端),这其中操作的时候,两者之间肯定要建立连接,就像数据库链接一样,在关系型数据库中,我们一般都维护一个连接池,以达到链接的复用,来省去建立连接和关闭连接的时间。所以在jedis中,同样也存在一个jedispool(jedis连接池)的概念,我们都是从池中去取连接使用。
引入jedis依赖
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.8.0</version>
</dependency>
建立一个Publisher (发布者)
package pubsub;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* Created by Yuk on 2019/1/10.
*/
public class Publisher extends Thread{
private final JedisPool jedisPool;
public Publisher(JedisPool jedisPool) {
this.jedisPool = jedisPool;
}
@Override
public void run() {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
Jedis jedis = jedisPool.getResource(); //连接池中取出一个连接
while (true) {
String line = null;
try {
line = reader.readLine();
if (!"quit".equals(line)) {
jedis.publish("mychannel", line); //从 mychannel 的频道上推送消息
} else {
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
再建立一个订阅者
package pubsub;
import redis.clients.jedis.JedisPubSub;
/**
* Created by Yuk on 2019/1/10.
*/
public class Subscriber extends JedisPubSub {
public Subscriber(){}
@Override
public void onMessage(String channel, String message) { //收到消息会调用
System.out.println(String.format("receive redis published message, channel %s, message %s", channel, message));
}
@Override
public void onSubscribe(String channel, int subscribedChannels) { //订阅了频道会调用
System.out.println(String.format("subscribe redis channel success, channel %s, subscribedChannels %d",
channel, subscribedChannels));
}
@Override
public void onUnsubscribe(String channel, int subscribedChannels) { //取消订阅 会调用
System.out.println(String.format("unsubscribe redis channel, channel %s, subscribedChannels %d",
channel, subscribedChannels));
}
}
这里订阅者需要继承JedisPubSub,来重写它的三个方法。用途 注释上已经写了,很简单。
我们这里只是定义了一个订阅者,下面去订阅频道。
package pubsub;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
/**
* Created by Yuk on 2019/1/10.
*/
public class SubThread extends Thread {
private final JedisPool jedisPool;
private final Subscriber subscriber = new Subscriber();
private final String channel = "mychannel";
public SubThread(JedisPool jedisPool) {
super("SubThread");
this.jedisPool = jedisPool;
}
@Override
public void run() {
System.out.println(String.format("subscribe redis, channel %s, thread will be blocked", channel));
Jedis jedis = null;
try {
jedis = jedisPool.getResource(); //取出一个连接
jedis.subscribe(subscriber, channel); //通过subscribe 的api去订阅,入参是订阅者和频道名
} catch (Exception e) {
System.out.println(String.format("subsrcibe channel error, %s", e));
} finally {
if (jedis != null) {
jedis.close();
}
}
}
}
最后,再写一个测试类去跑一下。键盘输入消息,订阅者就会触发onMessage方法
package pubsub;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
/**
* Created by Yuk on 2019/1/10.
*/
public class PubSubDemo {
public static void main( String[] args )
{
// 连接redis服务端
JedisPool jedisPool = new JedisPool(new JedisPoolConfig(), "127.0.0.1", 6379);
System.out.println(String.format("redis pool is starting, redis ip %s, redis port %d", "127.0.0.1", 6379));
SubThread subThread = new SubThread(jedisPool); //订阅者
subThread.start();
Publisher publisher = new Publisher(jedisPool); //发布者
publisher.start();
}
}

原文地址: https://blog.csdn.net/yu_kang/article/details/86254297
转载于:https://www.cnblogs.com/sunpengblog/p/11161829.html