GVKun编程网logo

redis06

20

在本文中,我们将为您详细介绍redis06的相关知识,此外,我们还会提供一些关于phpredisHashesredis下载redis集群redis可视化工具、phpredis并发控制redis下载re

在本文中,我们将为您详细介绍redis06的相关知识,此外,我们还会提供一些关于php redis Hashes redis 下载 redis 集群 redis可视化工具、php redis 并发控制 redis 下载 redis 集群 redis可视化工具、Redis00--Redis的基本命令、redis01的有用信息。

本文目录一览:

redis06

redis06

缓存的使用与设计

 


1.受益

加速读写
CPU L1/L2/L3 Cache、浏览器缓存、Ehcache缓存数据库结果
降低后端负载
后端服务器通过前端缓存降低负载:业务端使用Redis降低后端MySQL的负载

 

2.成本

数据不一致:缓存层和数据层有时间窗口不一致问题,和更新策略有关
代码维护成本:多了一层缓存逻辑
运维成本:例如Redis Cluster

 

3.使用场景

降低后端负载
对高消耗的SQL:join结果集/分组统计结果缓存
加速请求响应
利用Redis/Memcache优化IO响应时间
大量写合并为批量写
入计数器先Redis累加再批量写DB

 

缓存的更新策略

 

LRU等算法剔除:例如 maxmemory-policy

 

2.超时剔除:例如expire

3.主动更新:开发控制生命周期

4.两条建议
低一致性数据:最大内存和淘汰策略
高一致性:超时剔除和主动更新结合,最大内存和淘汰策略兜底

 

缓存粒度问题

通用性:全量属性更好
占用空间:部分属性更好
代码维护:表面上全量属性更好

 

 

 

缓存穿透优化

查询一个不存在的数据,由于缓存是不命中时需要从数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询

产生原因
业务代码自身问题
恶意攻击、爬虫
发现问题
业务的响应时间,受到恶意攻击时,普遍请求被打到存储层,必会引起响应时间提高,可通过监控发现

业务本身问题
相关指标:总调用数、缓存层命中数、存储层命中数

解决方法1:缓存空对象(设置过期时间)

当存储层查询不到数据后,往cache层中存储一个null,后期再被查询时,可以通过cache返回null。
缺点
cache层需要存储更多的key
缓存层和数据层数据“短期”不一致

 1 public String getPassThrough(String key) {
 2     String cacheValue = cache.get(key);
 3     if( StringUtils.isEmpty(cacheValue) ) {
 4         String storageValue = storage.get(key);
 5         cache.set(key , storageValue);
 6         if( StringUtils.isEmpty(storageValue) ) {
 7             cache.expire(key , 60 * 5 );
 8         } 
 9         return storageValue;
10     } else {
11         return cacheValue;
12     }
13 }

 

 

解决方法2:布隆过滤器拦截(适合固定的数据)

将所有可能存在的数据哈希到一个足够大的bitmap中,一个不存在的数据会被这个bitmap拦截掉,从而避免了对底层存储系统的查询压力

 

 

 

缓存雪崩优化

 

由于cache服务器承载大量的请求,当cache服务异常脱机,流量直接压向后端组件,造成级联故障。或者缓存集中在一段时间内失效,发生大量的缓存穿透

解决方法1:保证缓存高可用性

做到缓存多节点、多机器、甚至多机房。
Redis Cluster、Redis Sentinel
做二级缓存

解决方法2:依赖隔离组件为后端限流

使用Hystrix做服务降级

解决方法3:提前演练(压力测试)

解决方法4:对不同的key随机设置过期时间

 

 

无底洞问题

 

添加机器时,客户端的性能不但没提升,反而下降
关键点
更多的机器 != 更高的性能
更多的机器 = 数据增长与水平扩展
批量接口需求:一次mget随着机器增多,网络节点访问次数更多。网络节点的时间复杂度由O(1) -> O(node)

优化IO的方法
命令本身优化:减少慢查询命令:keys、hgetall、查询bigKey并进行优化
减少网络通信次数
mget由O(keys),升级为O(node),O(max_slow(node)) , 甚至是O(1)
降低接入成本:例如客户端长连接/连接池、NIO等

 

 

热点Key的重建优化

 

热点Key(访问量比较大) + 较长的重建时间(重建过程中的API或者接口比较费时间)
导致的问题:有大量的线程会去查询数据源并重建缓存,对存储层造成了巨大的压力,响应时间会变得很慢

 

 

1.三个目标

减少重建缓存的次数
数据尽可能一致
减少潜在危险:例如死锁、线程池大量被hang住(悬挂)

 

2.两种解决方案

互斥锁(分布式锁)
第一个线程需要重建时候,对这个Key的重建加入分布式锁,重建完成后进行解锁
这个方法避免了大量的缓存重建与存储层的压力,但是还是会有大量线程的阻塞

jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime)

String get(String key) {
    String SET_IF_NOT_EXIST = "NX";
    String SET_WITH_EXPIRE_TIME = "PX";
    
    String value = jedis.get(key);
    if( null == value ) {
        String lockKey = "lockKey:" + key;
        if( "OK".equals(jedis.set(lockKey , "1" , SET_IF_NOT_EXIST , 
                      SET_WITH_EXPIRE_TIME , 180)) ) {
            value = db.get(key);
            jedis.set(key , value);
            jedis.delete(lockKey);
        } else {
            Thread.sleep(50);
            get(key);
        }
    }
    return value;
}

 

永远不过期

缓存层面:不设置过期时间(不使用expire)
功能层面:为每个value添加逻辑过期时间,单发现超过逻辑过期时间后,会使用单独的线程去重建缓存。
还存在一个数据不一致的情况。可以将逻辑过期时间相对实际过期时间相对减小

 

 

Redis规模化的困扰

发布构建繁琐,私搭乱盖
节点&机器等运维成本
监控报警比较低级

 

 

CacheCloud的主要功能

一键开启Redis(单点、Sentinel、Cluster)
机器、应用、实例监控和报警
客户端:透明使用、性能上报
可视化运维:配置、扩容、Failover、机器/应用/实例上下线
已存在Redis直接移入和数据迁移

 

 

布隆过滤器引出

问题引出:现有50亿个电话号码,有10万个电话号码,要快速准确判断这些电话号码是否已经存在
1. 通过数据库查询:实现快速有点难
2. 数据预先放在内存集合中:50亿 * 8字节 = 40GB(***内存***浪费或不够)
3. hyperloglog:准确有点难

 

 

布隆过滤器原理

需要参数
m个二进制向量(m个二进制位数)
n个预备数据(类似于问题中的50亿个电话号码)
k个hash函数(每个数据,逐个进行hash,将指定向量标识为1)
构建布隆过滤器
将n个数据逐个走一遍hash流程
判断元素是否存在
将元素逐个hash进行执行
如果得到的hash结果再向量中全都是1,则表明存在,反之当前元素不存在

 

 

布隆过滤器误差率

对的数据的返回结果必然是对的,但是错误的数据也可能是对的
直观因素
m / n 的比例:比例越大,误差率越小
hash函数的个数:个数越多,误差率越小


本地布隆过滤器

实现类库:Guava

 1 Funnel<Integer> funnel = Funnels.integerFunnel();
 2 int size = 1000_000;
 3 double errorChance = 0.001;        //错误率
 4 BloomFilter<Integer> filter = BloomFilter.create(funnel , size , errorChance);
 5 for(int i = 0 ; i < size ; i++ ) {
 6     filter.put(i);
 7 }
 8 for(int i = 0 ; i < size ; i++ ) {
 9     if( !filter.mightContain(i) ) {
10         System.out.println("发现不存在的数据 : " + i);
11     }
12 }

 

布隆过滤器的问题

容量受到限制
多个应用存在多个布隆过滤器,构建同步过滤器复杂

 

 

Redis单机布隆过滤器

基于bitmap实现,利用setbit、getbit命令实现
hash函数:
MD5
murmur3_128
murmur3_32
sha1
sha256
sha512
基于Redis单机实现存在的问题
速度慢:与本机比,输在网络
解决方法1:单独部署、与应用同机房甚至同机架部署
解决方法2:使用pipeline
容量限制:Redis最大字符串为512MB、Redis单机容量
解决方法:基于RedisCluster实现

 

Redis Cluster实现布隆过滤器

多个布隆过滤器:二次路由
基于pipeline提高效率

 

 

内存管理

 

Redis内存消耗


内存使用统计

info memory

 

 

 2.内存消耗划分

used_memory的组成部分
自身内存(800K左右)
缓冲内存
客户端缓冲区
复制缓冲区
AOF缓冲区
对象内存
Key对象
Value对象
Lua内存
内存碎片 = used_memory_rss - used_memory(申请内存的会超过使用内存,内存预留与内存暂未释放)

 

3.子进程内存消耗

 

redis在bgsave与bgrewriteaof时候都会使用fork创建出子进程,fork是copy-on-write的,当发生写操作时,就会复制出一份内存
优化方式
去除THP特性:在kernel 2.6.38中新增的特性。这个特性可以加快fork的速度,但是在复制内存页的时候,会比原来的内存页扩大了512倍。例如原来是4K,扩大后为2M。当写入量比较大时,会造成不必要的阻塞与内存的暴增。
overcommit_memory=1 可以保证fork顺利完成

 

 

 

客户端缓冲区

 #查看已连接客户端的基本信息

info clients

 

 

#查看所有Redis-Server的所有客户端的详细信息
client list

 

 

输入缓冲区

各个客户端执行的Redis命令会存储在Redis的输入缓冲区中,由单线程排队执行
- 注意:输入缓冲区最大1GB,超过后会被强制断开,不可动态配置

 

输出缓冲区

1 client-output-buffer-limit ${class} ${hard limit} ${soft limit} ${soft seconds}
2 ## class 客户端类型
3 ##        normal        普通客户端
4 ##        slave        从节点用于复制,伪装成客户端
5 ##        pubsub        发布订阅客户端
6 ## hardLimit 如果客户端使用的输出缓冲区大于hardLimit,客户端会被立即关闭
7 ## softLimit 如果客户端使用的输出缓冲区超过了softLimit并且持续了softSeconds秒,客户端会立即关闭
8 ## 其中hardLimit与softLimit为0时不做任何限制

 

 

1.普通客户端

默认配置:client-output-buffer-limit normal 0 0 0
注意:需要防止大命令或者monitor,这两种情况会导致输出缓冲区暴增

2.slave客户端

默认配置:client-output-buffer-limit slave 256mb 64mb 60
建议调大:可能主从延迟较高,或者从节点数量过多时,主从复制容易发生阻塞,缓冲区会快速打满。最终导致全量复制
注意:在主从网络中,从节点不要超过2个

3.pubsub客户端

默认配置:client-output-buffer-limit pubsub 32mb 8mb 60
阻塞原因:生产速度大于消费速度
注意:需要根据实际情况进行调试

 

 

缓冲内存

 

1.复制缓冲区

此部分内存独享,默认1MB,考虑部分复制,可以设置更大,可以设置为100MB,牺牲部分内存避免全量复制。


2.AOF缓冲区

无论使用always、everysecs还是no的策略,都会进行刷盘,刷盘前的数据存放在AOF缓冲区中。

另外在AOF重写期间,会分配一块AOF重写缓冲区,重写时的写数据会存放在重写缓冲区当中。

为了避免数据不一致的发生,在重写完成后,会将AOF重写缓冲区的内容,同步到AOF缓冲区中。

AOF相关的缓冲区没有容量限制。

 

 

对象内存

Key:不要过长,量大不容忽视,建议控制在39字节之内。(embstr)
Value:尽量控制其内部编码为压缩编码。
内存碎片
在jemalloc中必然存在内存碎片
原因
与jemalloc有关,jemalloc会将内存空间划分为小、大、巨大三个范围;每个范围又划分了许多小的内存块单位;存储数据的时候,会选择大小最合适的内存块进行存储。

redis作者为了更好的性能,在redis中实现了自己的内存分配器来管理内存,不用的内存不会马上返还给OS,从而实现提高性能。
修改cache的值,且修改后的value与原先的value大小差异较大。

 

优化方法

重启redis服务,
redis4.0以上可以设置自动清理 config set activedefrag yes,也可以通过memory purge手动清理,配置监控使用性能最佳。
修改分配器(不推荐,需要对各个分配器十分了解)
避免频繁更新操作

 

内存回收策略

 

1.删除过期键值

惰性删除
1. 访问key
2. expired dict
3. del key
定时删除:每秒运行10次,采样删除

2.maxmemory-policy

Noevition:默认策略,不会删除任何数据,拒绝所有写入操作并返回错误信息。
volatile-lru:根据lru算法删除设置了超时属性的key,直到腾出空间为止。如果没有可删除的key,则将退回到noevition。
allkeys-lru:根据lru算法删除key,不管数据有没有设置超时属性,直到腾出足够空间为止。
allkeys-random:随机删除所有键,直到腾出足够空间为止。
volatile-random:随机删除过期键,直到腾出足够空间为止。
volatile-ttl:根据键值对象的ttl属性,删除最近将要过期的数据。如果没有,回退到noevicition。

 

 

客户端缓冲区优化

 

案例:一次线上事故,主从节点配置的maxmemory都是4GB,发现主节点的使用内存达到了4GB即内存已打满。而从节点只有2GB。


思考方向
考虑Redis的内存自身组成
主从节点之前数据传输不一致(会导致对象内存不一致)
dbsize
查看info replication中的slave_repl_offset
查看缓冲区方面
通过info clients查看最大的缓冲区占用
通过client list查看所有客户端的详细信息

 

问题发现:

存在一个monitor客户端对命令进行监听,由于Redis的QPS极高,monitor客户端无法及时处理,占用缓冲区。
问题预防
运维层面:线上禁用monitor(rename monitor "")
运维层面:适度限制缓冲区大小
开发层面:理解monitor原理,可以短暂寻找热点key
开发层面:使用CacheCloud可以直接监控到相关信息

 

内存优化其他建议

不要忽视key的长度:1个亿的key,每个字节都是节省
序列化和压缩方法:拒绝Java原生序列化,可以采用Protobuf、kryo等

 

不建议使用Redis的场景

数据:大且冷的数据
功能性:关系型查询、消息队列

 

 

 

 

 

php redis Hashes redis 下载 redis 集群 redis可视化工具

php redis Hashes redis 下载 redis 集群 redis可视化工具

php redis 并发控制 redis 下载 redis 集群 redis可视化工具

php redis 并发控制 redis 下载 redis 集群 redis可视化工具

针对并发控制可以使用 memcacheq ,redirs channle 等方式处理

这里我单单的说一下redis 怎么去控制并发

redis控制并发主要采用 redis list api 中的 lPush llen lPop 这三个函数

        lLen - 获得列表的长度 

        lPop - 删除列表的第一个值并返回它 

        lPush - 插入一个值到列表中,如果列表不存在,新建一个列表

立即学习“PHP免费学习笔记(深入)”;

比如我这边现在有个抢购的需求。一个商品只运行抢200个 大概思路如下

redis 命令,redis windows,redis入门指南,redis 安装,redis java,php redis,redis 下载,redis 集群,redis可视化工具

每次查看 redis 消息队列 长度是否已经超过 或 = 200  这种写法有可能会有多抢的情况。

所以我们这边后端的单独起一个程序做队列处理。如果说数量太多那就后面的不进行处理操作。

redis 命令,redis windows,redis入门指南,redis 安装,redis java,php redis,redis 下载,redis 集群,redis可视化工具
当然。这个前端已经进入队列的用户。你不能告诉人家您已经抢到了。应该让他5分钟后再去看看结果。

这样处理的数量不会去超出。当然如果并发太大的话可以专门寻找处理并发架构,

如果要求用户体验友好那就用socket获取后端处理结果告诉用户是否抢到。redis处理还是蛮快的所以不用担心用户等待时间过长。

以上就介绍了php redis 并发控制,包括了redis方面的内容,希望对PHP教程有兴趣的朋友有所帮助。

Redis00--Redis的基本命令

Redis00--Redis的基本命令

前言

这一篇文章我们主要是来整理下Redis的一些常用命令。

基本命令

  1. 启动Redis
 ./src/redis-server redis.conf
  1. 连接Redis数据库
 ./src/redis-cli -h 127.0.0.1 -p 6379

字符串相关的操作命令

String 数据类型主要用在做缓存,计数器,分布式锁,分布式ID等等
3. 设置一个字符串类型的值

 set key value
 例如: set testkey testvalue
  1. 获取字符串的值
 get key
 例如:get testkey

在这里插入图片描述
5. 删除键

del key
例如:del testkey
  1. 不存在就插入(not exists),
    存在的话就不会插入,这是用Redis做分布式锁的基础。
  setnx key value
  例如:127.0.0.1:6379> setnx username zhangsan
(integer) 1
  1. 设置过期时间(expire)
 setex key time value
 例如:
 127.0.0.1:6379> setex username  1 lisi

  1. 递增
incr key
incrby key increment 
例如:127.0.0.1:6379> incr age
  1. 递减
decr key  
decrby key decrement
例如:
127.0.0.1:6379> decr age
(integer) 1
127.0.0.1:6379> decrby age 3
(integer) -2

hash(哈希)

Redis hash 是一个键值对集合,Redis hash是一个String类型的field和value的映射表,hash特别适合存储对象,例如SpringSession中的session信息,存储用户信息,用户主页访问量等等。
6. 设置单个field值

hset key field value
例如:HSET company:1 companyname  alibaba
  1. 设置多个field值
hmset key field1 value1 [field2 value2 field3 value3 ......fieldn valuen]
例如:HMSET user:1 username zhangsna age 12
  1. 返回key中的field域的值
HGET key field
例如:
127.0.0.1:6379> HGET company:1 companyname
"alibaba"
  1. 返回key中的field1,field2,fieldN域的值
hmget key field1 field2 fieldN
例如:
127.0.0.1:6379> HMGET user:1 username age
1) "zhangsna"
2) "12"

  1. 返回key中,所有的域与其值
hgetall key
例如:
127.0.0.1:6379> HGETALL user:1
1) "username"
2) "zhangsna"
3) "age"
4) "12"
  1. 删除键
hdel key field[field ....]
例如:127.0.0.1:6379> hdel company:1 companyname
(integer) 1

list列表

字符串列表,按照插入顺序,添加一个元素到列表的头部(左边)或者尾部(右边),可以用于微博关注人,微博时间轴列表
充当队列的原理
左侧入队列

stringRedisTemplate.opsForList().leftPush(key, value)

右侧出队列

stringRedisTemplate.opsForList().rightPop(key)
  1. 将一个或多个值插入到列表头部
lpush key value1 [value2] 
例如:127.0.0.1:6379> lpush order 111 222
(integer) 2

  1. 获取列表指定范围内的数据
lrange key start stop 
例如:127.0.0.1:6379> lrange order 0 1
1) "222"
2) "111"

  1. 移除列表元素
lrem key count value 
例如:127.0.0.1:6379> lrem order 1 111
(integer) 1
  1. 通过索引设置元素列表的值
lset key index value 
例如:127.0.0.1:6379> lset order 0 123
OK
  1. 移除并获取列表最后一个元素
rpop key
例如:127.0.0.1:6379> rpop order
"123"
  1. 在列表尾部添加一个或者多个元素
rpush key value1 [value2] 
例如:127.0.0.1:6379> rpush student zhangsan lisi wanger
(integer) 3

set 集合

set 集合是String类型的无序集合,集合是通过哈希表实现的。所以添加,删除,查找的复杂度都是O(1)。set 集合一般用于,赞,踩,标签等场景
18. 添加一个元素到集合中(集合中的元素无序并且唯一)

sadd key member [member ...]
例如: 127.0.0.1:6379> sadd myset test
(integer) 1
  1. 查看集合中所有的元素
smembers key
例如:127.0.0.1:6379> smembers myset
1) "test"
  1. 删除结点中指定的元素
srem key member [member ...]
例如:127.0.0.1:6379> srem myset test
(integer) 1

  1. scard: 返回集合元素的数量
scard key
例如:127.0.0.1:6379> scard key
(integer) 0

  1. smove: 将一个集合的元素转移到另一个集合中
smove source destionation member
例如:
127.0.0.1:6379> smembers myset
1) "test1"
127.0.0.1:6379> smembers myset1
(empty list or set)
127.0.0.1:6379> smove myset myset1 test1
(integer) 1
127.0.0.1:6379> smembers myset1
1) "test1"

zset(有序集合)

Redis zset和set一样也是String类型元素的集合,且不允许重复的成员,不同的是每个元素都会关联一个double类型的分数,redis正是通过分数来为集合中的成员进行从小到大的排序的。
23. ZADD: 添加多个元素到有序集合中

ZADD key [NX|XX] [CH] [INCR] score member [score member ...]
例如:127.0.0.1:6379> ZADD city:gdp 95 "beijing" 92 "shanghai" 89 "shengzhen"
(integer) 3

  1. ZINCRBY: 为分数值加上增量
ZINCRBY key increment member
例如:127.0.0.1:6379> zincrby city:gdp 3 "beijing"
"98"
  1. ZCARD:获取有序集合中的元素数量
ZCARD key
例如:127.0.0.1:6379> ZCARD city:gdp
(integer) 3

  1. ZCOUNT: 获取在分数区间内的元素数量
zcount key min max
例如:127.0.0.1:6379>  zcount city:gdp 90 99
(integer) 2

  1. ZREM: 删除有序集合中的多个元素
  ZREM key member [member ..]
  例如:127.0.0.1:6379> zrem city:gdp "beijing"
(integer) 1

排序

  1. sort 排序
sort mylist
例如:
127.0.0.1:6379> lpush mylist 1 2 3 4
(integer) 4
127.0.0.1:6379> lpush mylist 1 2 3 4 12 10 9
(integer) 11
127.0.0.1:6379> sort mylist
 1) "1"
 2) "1"
 3) "2"
 4) "2"
 5) "3"
 6) "3"
 7) "4"
 8) "4"
 9) "9"
10) "10"
11) "12"

  1. 字母排序
sort mylist alpha desc limit 0 2

总结

本文主要介绍了Redis中各种常见的命令,Redis 有五种数据类型,每种数据类型都有不同的操作命令。

redis01

redis01

1、redis

1)cookie 与 session 

session 本质上也是 cookie,cookie 携带 session 返回给服务端

redis 是一个存储数据库

redis 读写快速,使用简单,常用于存储 session

2)安装

菜鸟网站有安装流程,

安装完成后

执行命令 redis-cli

 

在 koa 环境下使用 redis 需要安装两个插件

cnpm i koa-generic-session koa-redis

安装完成后需要在 koa 根目录下的 app.js 下引入

const session=require(''koa-generic-session'')

const Redis=require(koa-redis)

 

接着对 session 进行加密处理:

书写

app.keys=[''keys'',''your keys'']

app.use(session({

key:''mk'',

prefix:''mtpr''// 改变存储的字段名称

store=new Redis()

}))

 

之后可以在中间件中任意使用:

计算并保留访问次数:

自此我们操作 cookie 都可以通过 ctx.session 来完成

 

使用 redis-cli 可以查看我们的 session

keys * 表示当前所有的 key

直接操作 redis 数据库

在路由文件中引入 redis 中间件

const Redis=require(''koa-redis'')

新建 redis 客户端

const Store=new Redis().client

关于redis06的问题就给大家分享到这里,感谢你花时间阅读本站内容,更多关于php redis Hashes redis 下载 redis 集群 redis可视化工具、php redis 并发控制 redis 下载 redis 集群 redis可视化工具、Redis00--Redis的基本命令、redis01等相关知识的信息别忘了在本站进行查找喔。

本文标签: