Redis基础知识(二)(上)

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: Redis基础知识(二)

Redis事务


redis中的事务是一组命令的集合,事务中的命令要么全部执行,要么都不执行,Redis 通过 MULTI 、DISCARD 、EXEC 和 WATCH 四个命令来实现事务功能,multi表示事物的开启,exec表示事物的执行,exec执行后返回事务执行的结果,discard表示放弃事务执行,清空事务队列中已有的所有命令并退出队列,watch用于监视给定的键,如果键被其他客户端修改,将不会执行事务。


127.0.0.1:6379> multi
OK
127.0.0.1:6379> set key 1
QUEUED
127.0.0.1:6379> get key
QUEUED
127.0.0.1:6379> exec
1) OK
2) "1"
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set key1 1
QUEUED
127.0.0.1:6379> discard
OK
127.0.0.1:6379> get key1
(nil)


这里我在另一个客户端修改了被监视的key,导致在这个客户端事务没有执行


127.0.0.1:6379> set key 1
OK
127.0.0.1:6379> watch key
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr key
QUEUED
127.0.0.1:6379> incr key  #客户端2
(integer) 2
127.0.0.1:6379> exec
(nil)
127.0.0.1:6379> get key
"2"


由于事务在执行时会独占服务器,所以尽量避免在事务中执行过多命令,以免服务器阻塞


Redis Pipline


redis是一个cs模式的tcp server,使用和http类似的请求响应协议。一个client可以通过一个socket连接发起多个请求命令。每个请求命令发出后client通常会阻塞并等待redis服务处理,redis处理完后请求命令后会将结果通过响应报文返回给client。如果网络延迟较大,那将会花费太多的时间,redis提供了pipline可以解决这个问题,redis可以在pipline中发送多个消息而无需等待每个消息的答复的过程。这里我使用python的redis库写了个demo来演示使用pipline的效果


from redis import Redis
import time
conn=Redis(host="60.205.177.100",port="6379")
def usepipline():
    start_time=time.time()
    pipline=conn.pipeline()
    for i in range(300):
        pipline.incr("key")
    pipline.execute()
    print("usepipline:",time.time()-start_time)
def withoutpipline():
    start_time=time.time()
    for i in range(300):
        conn.incr("key1")
    print("withoutpipline:",time.time()-start_time)
usepipline()
withoutpipline()


响应结果


usepipline: 1.2412519454956055
withoutpipline: 7.2261717319488525


可以看到使用pipline效果是很明显的


Redis发布订阅模式


Redis通过PUBLISH 、SUBSCRIBE 等命令实现了订阅与发布模式,发布者可以向多个频道发布消息,订阅者可以订阅多个频道,当然一个频道也可以有多个订阅者,发布者和订阅者的这种分离可以允许更大的可伸缩性和更动态的网络拓扑。


640.png


命令


向频道发送消息


publish channel message


例如


返回的是接收到消息的订阅者数量


127.0.0.1:6379> publish CCTV1 worldnews
(integer) 0
127.0.0.1:6379> publish CCTV1 chinanews
(integer) 0


订阅频道


subscribe channel [channel ...]


例如


127.0.0.1:6379> subscribe CCTV1
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "CCTV1"
3) (integer) 1
1) "message"
2) "CCTV1"
3) "chinanews"


退订频道


UNSUBSCRIBE [channel [channel ...]]


例如


127.0.0.1:6379> UNSUBSCRIBE CCTV1 CCTV2
1) "unsubscribe"
2) "CCTV1"
3) (integer) 0
4) "unsubscribe"
5) "CCTV2"
6) (integer) 0


订阅模式


redis支持使用glob的方式来一次订阅多个频道


PSUBSCRIBE pattern [pattern ...]


例如


127.0.0.1:6379> publish CCTV2 chinanew
(integer) 1
127.0.0.1:6379> publish CCTV1 worldnews
(integer) 1
127.0.0.1:6379> PSUBSCRIBE CCTV*
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "CCTV*"
3) (integer) 1
1) "pmessage"
2) "CCTV*"
3) "CCTV2"
4) "chinanews"
1) "pmessage"
2) "CCTV*"
3) "CCTV2"
4) "chinanew"


退订模式


PUNSUBSCRIBE [pattern [pattern ...]]


例如


127.0.0.1:6379> PUNSUBSCRIBE CCTV*
1) "punsubscribe"
2) "CCTV*"
3) (integer) 0


python demo


redis_pub.py


from redis import Redis
import time
conn=Redis(host="60.205.177.100",port="6379")
def publish():
    while True:
        conn.publish("CCTV3","test")


redis_sub.py


from redis import Redis
import time
conn=Redis(host="60.205.177.100",port="6379")
def subscribe():
    subscribe=conn.pubsub()
    subscribe.subscribe('CCTV3')
    message=subscribe.parse_response()
    print(message)


Redis复制


虽然已经有了aof和rdb做持久化了,但是为了防止单点故障,这就需要复制多个数据副本来保证数据安全


redis复制的基本特征


  • Redis使用异步复制,并以每秒一次的频率向主服务器确认复制进度。
  • 一个主服务器可以有多个从服务器。从服务器也可以有多个从服务器,从服务器还可以以类似级联的结构连接到其他从服务器。
  • Redis复制在主服务器端无阻塞。这意味着当一个或多个副本执行初始同步或部分重新同步时,主服务器将继续处理查询。
  • 复制在从服务器基本上也没有阻塞。当副本执行初始同步时,如果配置了replica-serve-stale-data参数为yes,则从服务器可以使用数据集的旧版本处理查询。或者配置replica-serve-stale-data参数为no,在复制连接断开时,向客户端发送一个错误,但是,在初始同步之后,从服务器删除旧版本数据集并载入新版本数据集的那段时间内, 连接请求会被阻塞。
  • 复制功能可以单纯地用于数据冗余(data redundancy), 也可以通过让多个从服务器处理只读命令请求来提升扩展性(scalability)
  • 可以使用复制来避免让主数据库执行持久化,而是复制到从服务器之后由从服务器进行持久化,但是最好还是开启主服务器的持久化,因为重新启动的主服务器将以空数据集开始,如果从服务器尝试与其同步,导致从服务器的数据也将被清空。
  • 缺点也很明显,Redis主从模式仍具有单点风险,一旦主服务器挂掉将无法进行写数据操作


redis复制原理


完全同步


主服务器后台发送RDB文件给从服务器。从服务器接收rdb数据期间,主服务器会将新数据保存到复制客户端缓冲区,当从服务器接收完rdb文件后,将其保存在磁盘上,然后将其加载到内存中。加载完rdb文件后,如果开启aof,从服务器会进行重写操作。主服务器会把缓冲区的新数据发送给从服务器


部分同步


当主从连接中断后,从服务器使用psync命令向主服务器发送上次复制的偏移量,以及记录的masterID,如果上次复制的偏移量仍存在主服务器的缓冲区中,并且masterID与主服务器的masterID一致,将会从缓冲区中上次断开的位置开始增量复制,否则将会发生完全同步


psync命令


psync masterID offset


当从服务器与主服务器建立连接时,会判断是不是初次复制,如果是的话,将会发送psync ? -1进行完全同步,如果不是的话,会发送psync masterID offset尝试部分同步,如果发送的masterID与主服务器一致且offset存在于主服务器的复制缓冲区中,将进行部分同步,否则将会进行完全同步「首先我们查看主服务器的masterID和offset」


640.png


「然后将masterID和offset复制到从服务器,期间我在主服务器写了两条数据」


640.png


「可以看到从服务器已经有了主服务器的数据」

相关实践学习
基于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
相关文章
|
存储 缓存 NoSQL
Redis 基础知识和核心概念解析:理解 Redis 的键值操作和过期策略
Redis 基础知识和核心概念解析:理解 Redis 的键值操作和过期策略
138 1
|
存储 缓存 NoSQL
Redis第一讲:相关的基础知识/数据类型/缓存的过期策略/双写一致性/内存存储和持久化
Redis第一讲:相关的基础知识/数据类型/缓存的过期策略/双写一致性/内存存储和持久化
116 0
|
存储 缓存 NoSQL
Redis 基础知识和核心概念解析:探索 Redis 的数据结构与存储方式
Redis 基础知识和核心概念解析:探索 Redis 的数据结构与存储方式
237 0
|
存储 缓存 NoSQL
【Redis从头学-14】一文带你学会Redis Cluster集群模式、数据分片基础知识以及三主三从结构分片集群搭建全过程
【Redis从头学-14】一文带你学会Redis Cluster集群模式、数据分片基础知识以及三主三从结构分片集群搭建全过程
375 0
|
缓存 NoSQL API
【Redis基础知识 六】Redis底层数据编码之链表
【Redis基础知识 六】Redis底层数据编码之链表
70 0
【Redis基础知识 六】Redis底层数据编码之链表
|
存储 NoSQL API
【Redis基础知识 十】Redis底层数据编码之压缩列表
【Redis基础知识 十】Redis底层数据编码之压缩列表
101 0
|
NoSQL 安全 API
【Redis基础知识 九】Redis底层数据编码之整数集合
【Redis基础知识 九】Redis底层数据编码之整数集合
89 0
|
存储 NoSQL API
【Redis基础知识 八】Redis底层数据编码之跳跃表
【Redis基础知识 八】Redis底层数据编码之跳跃表
108 0
|
NoSQL 算法 Serverless
【Redis基础知识 七】Redis底层数据编码之字典
【Redis基础知识 七】Redis底层数据编码之字典
105 0
|
存储 NoSQL 安全
【Redis基础知识 五】Redis底层数据编码之动态字符串
【Redis基础知识 五】Redis底层数据编码之动态字符串
102 0