redis高级

redis管道-事务

-要么都成功要么都失败---》mysql通过回滚实现的
-客户端的命令先放到管道中,---》一次性发送到服务端执行---》保证了要么都成功,要么都失败
import redis
pool = redis.ConnectionPool(host='10.211.55.4', port=6379)
r = redis.Redis(connection_pool=pool)
# pipe = r.pipeline(transaction=False)
#创建pipeline
pipe = r.pipeline(transaction=True)
#开启事务
pipe.multi()
pipe.set('name', 'jeff')
#其他代码,可能出异常

pipe.set('role', 'nb')

pipe.execute()

与原生操作对比

通过pipeline提交多次命令,在服务端执行的时候,可能会被拆成多次执行,而mget等操作,是一次性执行。所以pipeline执行的命令是非原子性的

发布订阅模式

publish souhu:tv "hello world"  发布命令
subscribe souhu:tv   订阅频道
  
订阅之后,再在这个频道上发布消息,只要订阅了,都能收到

--发布订阅和消息队列的区别?

微信公众号订阅:公众号发了一篇文章,只要订阅了的,都可以收到更新(发布订阅模式,观察者模式)
	-自己实现的,写了新文章,主动给所有订阅的用户推送
  
设计模式:单例模式,工厂模式;   观察者模式,代理模式,迭代器模式(flask源码部分,request对象,用的是代理模式)

bitmap位图

独立用户统计

HyperLogLog(日活统计)

数据量大的时候采用:极小的空间完成独立数量统计

数据量小:用集合

Redis geo经纬度

# 存储经纬度,计算两个点之间的距离,统计某个点周围多少距离的其他点

geoadd key longitude latitude member
举例:
geoadd cities:locations 116.28 39.55 beijing 
  
--你实际的项目,地理位置信息从哪里来的?前端传过来的
	-app,移动端,申请权限,用户允许了,直接调用收集提供的接口,得到经纬度---》调后台接口传给你--》拿到经纬度,放到redis中即可
  
# 我现在是张三,我跟李四是朋友---》李四所在的位置,李四距离我多远,我方圆5公里内,我的好友有谁

取出某个位置的坐标
geopos cities:locations beijing 
计算两个人之间的距离
geodist cities:locations beijing tianjin km
  
计算方圆多少公里内有谁
georadiusbymember cities:locations beijing 150 km

redis主从

主:只能写入,增删改。主库增删该数据,从库跟着改
多个从:查

# 1 为了提高性能,扩展机器
# 2 数据流向是单向的,从master到slave
# 3 两种方式:(需要两台机器)(启动两个redis进程)
		-第一种:在客户端cli里执行命令
  		-在本地起两个redis服务(进程)6380是从,6379是主
    	-登陆到从库(6380库),执行
      -slaveof 127.0.0.1 6379  主库增删该数据,从库跟着改
      
      -取消复制:slaveof no one  # 不会把之前的数据清除
      
      
  	-第二种:配置文件
    	-在从节点配置(重启即可)
      slaveof ip port #配置从节点ip和端口
			slave-read-only yes #从节点只读,因为可读可写,数据会乱
      
      slaveof 10.0.0.101 6379
			slave-read-only yes
# 4 一主多从呢?(从库只能读)
	只需要在多个从库上配置即可

redis哨兵

架构图

使用背景

# Redis主从复制可将主节点数据同步给从节点,从节点此时有两个作用: 
	1.一旦主节点宕机,从节点作为主节点的备份可以随时顶上来。
	2.扩展主节点的读能力,分担主节点读压力。

# 但是问题是: 
	一旦主节点宕机,从节点上位,那么需要人为修改所有应用方的主节点地址(改为新的master地址),还需要命令所有从节点复制新的主节点 
	那么这个问题,redis-sentinel就可以解决了

# 而redis-sentinel就是一个独立运行的进程,用于监控多个master-slave集群,自动发现master宕机,进行自动 切换slave > master。

功能实现

#不时的监控redis是否良好运行,如果节点不可达就会对节点进行下线标识 
#如果被标识的是主节点,sentinel就会和其他的sentinel节点“协商”,如果其他节点也人为主节点不可
达,就会选举一个sentinel节点来完成自动故障转义 
#在master-slave进行切换后,master_redis.conf、slave_redis.conf和sentinel.conf的内容
都会发生改变,即master_redis.conf中会多一行slaveof的配置,sentinel.conf的监控目标会随之
调换

配置文件

# 1 哨兵是为了保证redis'服务的高可用,一个master挂掉,服务依然可以用
# 2 哨兵搭建步骤
	-1 先做一主两从
		6379是主mastre 
		6380是从slave
  	6381是从slave
  -2 启用哨兵(哨兵是一个redis进程)
  	#26379端口--一个哨兵
    配置文件:
    port 26379
    daemonize yes
		dir data
    protected-mode no
    bind 0.0.0.0
    logfile "redis_sentinel.log"
    sentinel monitor mymaster 127.0.0.1 6379 2
    sentinel down-after-milliseconds mymaster 30000
    sentinel parallel-syncs mymaster 1
    sentinel failover-timeout mymaster 180000
    #26380端口--一个哨兵
   	port 26380
   	daemonize yes
		dir data
    protected-mode no
    bind 0.0.0.0
    logfile "redis_sentinel.log"
    sentinel monitor mymaster 127.0.0.1 6379 2
    sentinel down-after-milliseconds mymaster 30000
    sentinel parallel-syncs mymaster 1
    sentinel failover-timeout mymaster 180000
    #26381端口--一个哨兵
    port 26381
    daemonize yes
		dir data
    protected-mode no
    bind 0.0.0.0
    logfile "redis_sentinel.log"
    sentinel monitor mymaster 127.0.0.1 6379 2
    sentinel down-after-milliseconds mymaster 30000
    sentinel parallel-syncs mymaster 1
    sentinel failover-timeout mymaster 180000
    
  	-redis-sentinel 配置文件来启动哨兵
    -启动哨兵:
    redis-sentinel 配置文件
    redis-sentinel sentinel_26379.conf
    redis-sentinel sentinel_26380.conf
    redis-sentinel sentinel_26381.conf
    
    -从客户端登录到一个哨兵上
    redis-cli -p 26379
    -输入info
    最后一行看到
    master0:name=mymaster,status=ok,address=127.0.0.1:6379,slaves=2,sentinels=3
        
    -把主库手动停掉
    shutdown
    
    -连到哨兵上,输入info(主master自动变成了6381)
    master0:name=mymaster,status=ok,address=101.133.225.166:6381,slaves=4,sentinels=3
        
    -原来的主库如果启动,主库会变为从库,继续运行redis服务

# python客户端连接(直接连了主库,主库挂掉,不能改代码吧)
    
import redis
from redis.sentinel import Sentinel

# 连接哨兵服务器(主机名也可以用域名)
# 10.0.0.101:26379
sentinel = Sentinel([('10.0.0.101', 26379),
                     ('10.0.0.101', 26378),
                     ('10.0.0.101', 26377)
		     ],
                    socket_timeout=5)

print(sentinel)
# 获取主服务器地址
master = sentinel.discover_master('mymaster')
print(master)

# 获取从服务器地址
slave = sentinel.discover_slaves('mymaster')
print(slave)

# 获取主服务器进行写入
# master = sentinel.master_for('mymaster', socket_timeout=0.5)
# w_ret = master.set('foo', 'bar')
#
# slave = sentinel.slave_for('mymaster', socket_timeout=0.5)
# r_ret = slave.get('foo')
# print(r_ret)
    

缓存更新淘汰策略

# LRU:Least Recently Used,没有被使用时间最长的

# LRU配置
maxmemory-policy:volatile-lru
(1)noeviction: 如果内存使用达到了maxmemory,client还要继续写入数据,那么就直接报错给客户端
(2)allkeys-lru: 就是我们常说的LRU算法,移除掉最近最少使用的那些keys对应的数据,ps最长用的策略
(3)volatile-lru: 也是采取LRU算法,但是仅仅针对那些设置了指定存活时间(TTL)的key才会清理掉
(4)allkeys-random: 随机选择一些key来删除掉
(5)volatile-random: 随机选择一些设置了TTL的key来删除掉
(6)volatile-ttl: 移除掉部分keys,选择那些TTL时间比较短的keys
  
  
# LFU:Least Frequenty User,一定时间段内使用次数最少的

# LFU配置 Redis4.0之后为maxmemory_policy淘汰策略添加了两个LFU模式:
volatile-lfu:对有过期时间的key采用LFU淘汰算法
allkeys-lfu:对全部key采用LFU淘汰算法
# 还有2个配置可以调整LFU算法:
lfu-log-factor 10
lfu-decay-time 1
# lfu-log-factor可以调整计数器counter的增长速度,lfu-log-factor越大,counter增长的越慢。
# lfu-decay-time是一个以分钟为单位的数值,可以调整counter的减少速度


# FIFO:First In First Out

MySQL里有2000w数据, redis中只存20w的数据,如何保证 redis中都是热点数据?

方案:
限定 Redis占用的内存,Redis会根据自身数据淘汰策略,留下热数据到内存。所以,计算一下 50W 数据大约占用的内存,然后设置一下Redis内存限制即可,并将淘汰策略为volatile-lru或者allkeys-lru。

allkeys-lru: 就是我们常说的LRU算法,移除掉最近最少使用的那些keys对应的数据,ps最长用的策略
volatile-lru: 也是采取LRU算法,但是仅仅针对那些设置了指定存活时间(TTL)的key才会清理掉


设置Redis最大占用内存: 打开redis配置文件,设置maxmemory参数,maxmemory是bytes字节类型

缓存穿透,缓存击穿,缓存雪崩

# 缓存穿透:
	-缓存和数据库都没有数据,爬虫,恶意攻击
  -解决:
  	-1 接口层增加校验,id小于0的直接处理掉
    -2 对应数据库中也不存在的,也在缓存中放一份,只不过value值是空
    -3 通过布隆过滤器实现,把所有用户id都放到布隆过滤器中,来了一个请求,拿着id
    	去布隆过滤器看,没有表示是恶意请求,直接返回
# 缓存击穿
	-缓存没有,数据库有,缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力
  -解决:
  	-设置热点数据永远不过期。
# 缓存雪崩
	-缓存雪崩是指缓存中数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至down机
  -解决方案:
    1 缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
    2 如果缓存数据库是分布式部署,将热点数据均匀分布在不同搞得缓存数据库中。
    3 设置热点数据永远不过期。

mysql主从搭建

# 1 主从同步的原理
  mysql主从配置的流程大体如图:
  1)master会将变动记录到二进制日志里面;
  2)master有一个I/O线程将二进制日志发送到slave;
  3) slave有一个I/O线程把master发送的二进制写入到relay日志里面;
  4)slave有一个SQL线程,按照relay日志处理slave的数据;
# 2 主从配置(两台服务器,用docker模拟),尽量环境完全一样,mysql版本一定一致
	-主库是docker中映射到宿主机的33307端口
  -从是docker中映射到宿主机的33306端口
  
# 3 搭建步骤
3.1 启动主库
    1 在宿主机上创建目录
    mkdir /home/mysql
    mkdir /home/mysql/conf.d
    mkdir /home/mysql/data/
    创建my.cnf配置文件
    touch /home/mysql/my.cnf

    2 主库的配置
    [mysqld]
    user=mysql
    character-set-server=utf8
    default_authentication_plugin=mysql_native_password
    secure_file_priv=/var/lib/mysql
    expire_logs_days=7
    sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
    max_connections=1000
    server-id=100
    log-bin=mysql-bin

    3 启动主库
    docker run  -di -v /home/mysql/data/:/var/lib/mysql -v /home/mysql/conf.d:/etc/mysql/conf.d -v /home/mysql/my.cnf:/etc/mysql/my.cnf -p 33307:3306 --name mysql-master -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
              
3.2 启动从库
    1 在宿主机上创建目录
    mkdir /home/mysql2
    mkdir /home/mysql2/conf.d
    mkdir /home/mysql2/data/
    创建my.cnf配置文件
    touch /home/mysql2/my.cnf

    2 从库的配置
    [mysqld]
    user=mysql
    character-set-server=utf8
    default_authentication_plugin=mysql_native_password
    secure_file_priv=/var/lib/mysql
    expire_logs_days=7
    sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
    max_connections=1000
    server-id=101  
    ## 开启二进制日志功能,以备Slave作为其它Slave的Master时使用
    log-bin=mysql-slave-bin   
    ## relay_log配置中继日志
    relay_log=edu-mysql-relay-bin 

    3 启动主库
    docker run  -di -v /home/mysql2/data/:/var/lib/mysql -v /home/mysql2/conf.d:/etc/mysql/conf.d -v /home/mysql2/my.cnf:/etc/mysql/my.cnf -p 33306:3306 --name mysql-slave -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
              
              
3.3 连到主库,进行配置
mysql -h 101.133.225.166 -P 33307 -u root -p123456
#在主库创建用户并授权
##创建test用户
create user 'test'@'%' identified by '123';
##授权用户
grant all privileges on *.* to 'test'@'%' ;
###刷新权限
flush privileges;
#查看主服务器状态(显示如下图)
show master status; 

3.4 连接到从库,进行配置
mysql -h 101.133.225.166 -P 33306 -u root -p123456

change master to master_host='101.133.225.166',master_port=33307,master_user='test',master_password='123',master_log_file='mysql-bin.000003',master_log_pos=0;

django实现读写分离

# 1 写相关的操作,放到主库,读相关的操作,到从库上

# 2 配置文件中:

数据迁移的时候,通过它来指定,同步到哪个库
migrate --database=db1

# 3 主库,从库
default是主库
db1是从库

migrate app01 --databse="db1"


# 4 手动操作(queryset对象)
ret=Book.objects.all().using("db1")

# 4 自动做(通过配置,程序,读去从库读,写去主库写)
# 写一个router
在项目路径下创建db_router.py
在里面写一个类
class Router1:
		def db_for_read(self, model, **hints):
				return 'db1'

		def db_for_write(self, model, **hints):
				return 'default'

#在setting中配置
DATABASE_ROUTERS = ['db_router.Router1',]
# 只要是写的操作,都到default上,只要是读的操作,都到db1上了

# 5 具体到某个表,只去某个库读,写
一主多从,通过random
分库分表:user在其中一个库,book表在另一个库 

分库分表方案

# 1  单表数据量到达千万级  (分库:一个库有table1,table2表,另一个库有table3,table4表)

# 2 分表方案
  -垂直分表:把原来一个大表,做成一对一关系
  -水平分表:水平切,假设把2000万的数据,分到两个表中(按id分,按hash分)

分库分表实战-mycat数据库中间件

# 1 通过mycat数据库中间件实现(生根于阿里)
# 2 基于java开发,需要安装jdk
# 3 实现了 MySQL 公开的二进制传输协议,巧妙地将自己伪装成一个  MySQL Server,目前市面上绝大多数 MySQL  客户端工具和应用都能兼容
# 4 javase(基础,io,网络,并发) javaee(web相关) javame

# 5 需要有两台服务器(docker模拟两个mysql)

# 分库:
	垂直分库:(用户相关表,订单相关表,支付相关表)
  水平分库 :(用户表拆到了不同的库中)

# 6 安装mycat
	-1 安装jdk8以上
  -2 下载,解压即可
  -3 启动 ./mycat start    stop    console(前台运行,可以查看日志)
# 7 mycat安装完,需要关注的几个文件
    sever.xml:综合配置数据库的相关信息,端口,内存占用,创建账号,密码
    schema.xml:对数据库表结构的定义
    rule.xml:指定相关算法,来实现不同的分片数据库
    
# 8 id分表规则配置
-shema.xml
			# name指定表名,dataNode指定节点,rule指定分片规则(水平分表的规则)
      <table name="user" primaryKey="id" dataNode="dn1,dn2" rule="auto-sharding-long" autoIncrement="true" fetchStoreNodeByJdbc="true">
      </table>
    
    
   # dataNode="dn1,dn2" 跟这个地方对应
  <dataNode name="dn1" dataHost="localhost1" database="db1" />
	<dataNode name="dn2" dataHost="localhost1" database="db2" />
  
  
  # 在这配置跟上面对应,主机的地址和端口,连接mysql服务端的用户名和密码
  
  	<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0"
			  writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1"  slaveThreshold="100">
		<heartbeat>select user()</heartbeat>
		<!-- can have multi write hosts -->
		<writeHost host="hostM1" url="jdbc:mysql://localhost:3306" user="root"
				   password="123456">
		</writeHost>
		<!-- <writeHost host="hostM2" url="localhost:3316" user="root" password="123456"/> -->
	</dataHost>


	<dataHost name="localhost2" maxCon="1000" minCon="10" balance="0"
			  writeType="0" dbType="mysql" dbDriver="jdbc" switchType="1"  slaveThreshold="100">
		<heartbeat>select user()</heartbeat>
		<!-- can have multi write hosts -->
		<writeHost host="hostM1" url="jdbc:mysql://localhost:3307" user="root"
				   password="123456">
		</writeHost>
		<!-- <writeHost host="hostM2" url="localhost:3316" user="root" password="123456"/> -->
	</dataHost>
  
# 9 配置规则
auto-sharding-long---》rule.xml
	<tableRule name="auto-sharding-long">
		<rule>
			<columns>id</columns>
			<algorithm>rang-long</algorithm>
		</rule>
	</tableRule>
  # rang-long
  	<function name="rang-long"
			  class="io.mycat.route.function.AutoPartitionByLong">
		<property name="mapFile">autopartition-long.txt</property>
	</function>
# autopartition-long.txt
# range start-end ,data node index
# K=1000,M=10000.
0-500M=0        # id号为0---50000000的数据落在 0库上
500M-1000M=1    # id号为50000000---100000000的数据落在 1库上


# 10 启动mycat
# 11 远程连接,需要在3306和3307库上创建出db1数据库
# 12 远程连接到mycat,创建表,插入数据,如果是不通范围的id会落到不通库上



## 同过hash方式实现水平分表
	-只需要修改shema.xml
  
		<table name="article" primaryKey="id" dataNode="dn1,dn2" rule="sharding-by-murmur">
		</table>
  -重启mycat
  -在客户端测试,创建article表。插入数据,会均匀的散落在两个哭上
  
  
  
  # 原来由于我的设计,没有考虑到分表的情况(单数据---》数据量越来越大,要分表了?)
  	-起一个从库,把原来的业务数据同步过来---》操作从库---》通过mycat从库分表--》再练mycat(缺一部分数据---》把这部分数据重放回来)

redis实现分布式锁

# 1 分布式锁: 锁住不同机器上的不通进程
# 2 redis实现:官方提供了

#Redlock

from redlock import Redlock

dlm = Redlock([{"host": "localhost", "port": 6379, "db": 0}, ])

my_lock = dlm.lock("my_resource_name",1000)
# 自己的逻辑---》悲观锁---你的代码
print("xxx")

#你写的业务
# 自己的逻辑---》悲观锁---你的代码
dlm.unlock(my_lock)


分布式id生成方案

# 分布式id:为了保证全局唯一
	-分表,默认自增--》两个库上--》可能id号重复       uuid:有没有重复
# 设计思路:
  low版本的出来:
    -一个库 1,3,5,7,9
    -另一个库2,4,6,8,10
  分布式id生成方案
  	-UUID:不是趋势自增,性能挺高(5台机器生成,一般不会重复)
    -mysql生成:性能低
    -redis生成:很快,自增 ,必须还得有台redis服务器  incrby   16位: '当前时间戳+自增'  
    -雪花算法:python版雪花算法

redis持久化的方式

redis提供两种方式进行持久化,一种是RDB持久化,另外一种是AOF持久化。

RDB持久化(数据文件)

按照间隔时间备份数据快照
# ------------------ RDB持久化 -------------- 
# 1. 原理
RDB持久化是指在指定的时间间隔内将通过save命令将内存中的数据生成生成RDB快照文件RDB文件是经过压
缩的二进制文件,这个文件被保存在硬盘中,redis可以通过这个文件还原数据库当时的状态。

# 2. 过程:
Redis调用fork(),产生一个子进程。子进程把数据写到一个临时的RDB文件。
当子进程写完新的RDB文件后,把旧的RDB文件替换掉

# 3. 优点 RDB文件是一个很简洁的单文件,它保存了某个时间点的Redis数据,很适合用于做备份。你可
以设定一个时间点对RDB文件进行归档,这样就能在需要的时候很轻易的把数据恢复到不同的版本。比起
AOF,在数据量比较大的情况下, RDB的启动速度更快。

# 4. 缺点
RDB容易造成数据的丢失。假设每5分钟保存一次快照,如果Redis因为某些原因不能正常工作,那么从上次
产生快照 到Redis出现问题这段时间的数据就会丢失了。RDB使用fork()产生子进程进行数据的持久化,
如果数据比较大的话可能就会花费点时间,造成Redis停止服务几毫秒。如果数据量很大且CPU性能不是很好
的时候,停止服务的时间甚至会到1秒。

AOF持久化(日志命令)

把所有记录在日志中的命令,重新执行一遍
# ------------------ AOF持久化 -------------------- 
# 1. 原理
AOF持久化以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,生成AOF文件,重启Redis时,AOF里的命令会被重新执行一次,重建数据。

# 2. 过程
Redis调用fork(),产生一个子进程。子进程把新的AOF写到一个临时文件里。主进程持续把新的变动写到
内存里的buffer,同时也会把这些新的变动写到旧的AOF里,这样即使重写失败也能保证数据的安全。当子
进程完成文件的重写后,主进程会获得一个信号,然后把内存里的buffer追加到子进程生成的那个新AOF里

# 3. 优点
比RDB可靠。你可以制定不同的fsync策略:不进行fsync、每秒fsync一次和每次查询进行fsync。默认是每秒fsync一次。这意味着你最多丢失一秒钟的数据。

# 4.缺点:
在相同的数据集下,AOF文件的大小一般会比RDB文件大。日志重写:新文件上会写入能重建当前数据集的最小操作命令的集合。

go-redis实现队列

package main

import (
	"fmt"
	"time"

	"github.com/go-redis/redis"
)

// 声明一个全局的rdb变量
var rdb *redis.Client

// 初始化连接
func initClient() (err error) {
	rdb = redis.NewClient(&redis.Options{
		Addr:     "192.168.0.247:30279",
		Password: "",
		DB:       7,
	})

	_, err = rdb.Ping().Result()
	if err != nil {
		return err
	}
	return nil
}

func push()  {
	for i:=0;i<100;i++ {
		rdb.RPush("list",i)
	}
}

func pull()  {
	for  {
		l:= rdb.BLPop(3*time.Second,"list")
		fmt.Println(l.Val())
	}
}


func main() {
	err := initClient()
	if err != nil {
		fmt.Println(err)
	}
	go push()
	go pull()

	for  {

	}

}

go-redis事务

package main

import (
	"fmt"

	"github.com/go-redis/redis"
)

// 声明一个全局的rdb变量
var rdb *redis.Client

// 初始化连接
func initClient() (err error) {
	rdb = redis.NewClient(&redis.Options{
		Addr:     "ip:port",
		Password: "",
		DB:       7,
	})

	_, err = rdb.Ping().Result()
	if err != nil {
		return err
	}
	return nil
}

func main() {
	err := initClient()
	if err != nil {
		fmt.Println(err)
	}

	pipe:= rdb.TxPipeline()
	defer pipe.Close()
	pipe.RPush("list",0)
	r, err := pipe.Exec()
	if err!=nil {
		//取消提交
		pipe.Discard()
	}
	fmt.Println(r)
}

秒杀设计方案

# 思路一:
	-某个时间段---》卖商品---》别卖超了---》mysql悲观锁实现---》缺陷,性能低
  -100商品---》预热---》100这个数,放到redis中----》incrby--》来一个秒杀请求-1,在redis集合中把用户id放进去,最后100这个数变成了0,---》起个异步任务---》消费集合中的id,生成订单,扣减库存,扣减账户余额,提前充钱了
  -用户真去看订单的时候---》异步任务完成了

# 思路二:
	-用户发了秒杀请求---》前端看到--》您正在排队
  -请求来了---》放到队列里---》(djnago中间件:请求放到队列中,直接返回,告诉用户,您正在排队)

Redis Monitor实时打印出 Redis 服务器接收到的命令

redis 127.0.0.1:6379> MONITOR 
OK
1410855382.370791 [0 127.0.0.1:60581] "info"
1410855404.062722 [0 127.0.0.1:60581] "get" "a"

测试案列

package main

import (
	"fmt"

	"github.com/go-redis/redis"
)

// 声明一个全局的rdb变量
var rdb *redis.Client

// 初始化连接
func initClient() (err error) {
	rdb = redis.NewClient(&redis.Options{
		Addr:     "ip:port",
		Password: "", // no password set
		DB:       7,  // use default DB
	})

	_, err = rdb.Ping().Result()
	if err != nil {
		return err
	}
	return nil
}


func main() {
	err := initClient()
	if err != nil {
		fmt.Println(err)
	}

	go get()

	go test()
	for  {

	}
}

func get()  {
	for  {
		rdb.HVals("test")
	}
}
func test()  {
	for  {
		a:=rdb.Do("MONITOR")
		fmt.Println(a)
	}
}

//////结果///////
&{{[MONITOR] <nil> <nil>} 1644393067.051442 [7 192.168.0.247:28514] "hvals" "test"}
&{{[MONITOR] <nil> <nil>} 1644393067.052393 [7 192.168.0.247:28514] "hvals" "test"}
&{{[MONITOR] <nil> <nil>} 1644393067.053169 [7 192.168.0.247:28514] "hvals" "test"}
&{{[MONITOR] <nil> <nil>} 1644393067.053919 [7 192.168.0.247:28514] "hvals" "test"}

posted @ 2020-11-03 15:35  Jeff的技术栈  阅读(163)  评论(0编辑  收藏  举报
回顶部