redis的快速机制与数据类型
想一下 redis 的高并发和快速
单线程模型 - 避免了不必要的上下文切换和竞争条件(锁)
Redis客户端对服务端的每次调用都经历了发送命令,执行命令,返回结果三个过程。其中执行命令阶段,由于Redis是单线程来处理命令的,所有每一条到达服务端的每一条到达服务端的命令都不会立刻执行,所有的命令都会进入一个队列中,然后逐个执行。并且多个客户端发送的命令的执行顺序是不确定的。但是可以确定的是不会有两条命令被同时执行,不会产生并发问题,这就是Redis的单线程基本模型。
redis 核心就是如果我的数据全都在内存里,我单线程的去操作 就是效率最高的,为什么呢,因为多线程的本质就是 CPU 模拟出来多个线程的情况,这种模拟出来的情况就有一个代价,就是上下文的切换,对于一个内存的系统来说,它没有上下文的切换就是效率最高的。redis 用 单个CPU 绑定一块内存的数据,然后针对这块内存的数据进行多次读写的时候,都是在一个CPU上完成的,所以它是单线程处理这个事。在内存的情况下,这个方案就是最佳方案。
为何单核cpu绑定一块内存效率最高?
“我们不能任由操作系统负载均衡,因为我们自己更了解自己的程序,所以我们可以手动地为其分配CPU核,而不会过多地占用CPU”,默认情况下单线程在进行系统调用的时候会随机使用CPU内核,为了优化Redis,我们可以使用工具为单线程绑定固定的CPU内核,减少不必要的性能损耗!
redis作为单进程模型的程序,为了充分利用多核CPU,常常在一台server上会启动多个实例。而为了减少切换的开销,有必要为每个实例指定其所运行的CPU。
Linux 上 taskset 可以将某个进程绑定到一个特定的CPU。你比操作系统更了解自己的程序,为了避免调度器愚蠢的调度你的程序,或是为了在多线程程序中避免缓存失效造成的开销。
非阻塞IO - IO多路复用 - 减少网络IO的时间消耗
绝大部分请求是纯粹的内存操作(非常快速)
redis 的瓶颈一般主要在网络上
redis常见的数据类型
String字符串 - http://redisdoc.com/
Redis能存储二进制安全的字符串,最大长度为512M
redis 127.0.0.1:> SET name "John Doe"
OK
redis 127.0.0.1:> GET name
"John Doe" String类型支持批量的读写操作
redis 127.0.0.1:> MSET age sex "male"
OK
redis 127.0.0.1:> MGET age sex
) ""
) "male" String类型支持对其部分的修改和获取操作
redis 127.0.0.1:> APPEND name " Mr."
(integer)
redis 127.0.0.1:> GET name
"John Doe Mr."
redis 127.0.0.1:> STRLEN name
(integer)
redis 127.0.0.1:> GETRANGE name
"John" String类型也可以用来存储数字,并支持对数字的加减操作
redis 127.0.0.1:> INCR age
(integer)
redis 127.0.0.1:> INCRBY age
(integer)
redis 127.0.0.1:> GET age
""
redis 127.0.0.1:> DECR age
(integer)
redis 127.0.0.1:> DECRBY age
(integer)
redis 127.0.0.1:> GET age
""
Hash哈希
Redis能够存储key对应多个属性的数据
redis 127.0.0.1:> HKEYS student
) "name"
) "age"
) "sex"
redis 127.0.0.1:> HVALS student
) “tom"
) ""
) "Male"
redis 127.0.0.1:> HGETALL student
) "name"
) “tom"
) "age"
) ""
) "sex"
) "Male"
redis 127.0.0.1:> HDEL student sex
(integer)
redis 127.0.0.1:> HGETALL student
) "name"
) “tom"
) "age"
) "" Hash数据结构能够批量修改和获取
redis 127.0.0.1:> HMSET kid name Anna age sex Female
OK
redis 127.0.0.1:> HMGET kid name age sex
) “Anna "
) ""
) "Female"
原生字符串类型:简单直观,每个属性都支持更新操作,但是用户ID为重复存储,如果存在大量这样的数据,内存浪费还是非常可观的。
序列化字符串类型:Key为用户ID,值为所有属性值的组合,使用合理可以提高内存使用效率,但增加了序列化/反序列化的开销,并且在需要修改其中一项信息时,需要把整个对象取回,并且修改操作需要对并发进行保护,引入cas等复杂问题 。
哈希类型:每个用户属性使用一对field-value,但是只用一个键保存。更新数据属性时通过 key(用户ID) + field(属性标签) 就可以操作对应属性数据了,既不需要重复存储数据,也不会带来序列化和并发修改控制的问题。但要控制哈希在ziplist和hashtable两种内部编码的转换,hashtable会消耗更多内存。
hscan --- 渐进式遍历,解决hgetall阻塞问题,hscan过程中键有变化,会导致新增键不能遍历到,或者重复遍历。
List列表 - 有序,1个list最多存储2^32 -1 个元素
Redis能够将数据存储成一个链表,并能对这个链表进行丰富的操作
redis 127.0.0.1:> LPUSH students "John Doe"
(integer)
redis 127.0.0.1:> LPUSH students "Captain Kirk"
(integer)
redis 127.0.0.1:> LPUSH students "Sheldon Cooper"
(integer)
redis 127.0.0.1:> LLEN students
(integer)
redis 127.0.0.1:> LRANGE students
) "Sheldon Cooper"
) "Captain Kirk"
) "John Doe"
redis 127.0.0.1:> LPOP students
"Sheldon Cooper"
redis 127.0.0.1:> LLEN students
(integer) Redis也支持很多修改操作
redis 127.0.0.1:> LINSERT students BEFORE "Captain Kirk" "Dexter Morgan"
(integer)
redis 127.0.0.1:> LRANGE students
) "Dexter Morgan"
) "Captain Kirk"
) "John Doe"
redis 127.0.0.1:> LPUSH students "Peter Parker"
(integer)
redis 127.0.0.1:> LRANGE students
) "Peter Parker"
) "Dexter Morgan"
) "Captain Kirk"
) "John Doe"
redis 127.0.0.1:> LTRIM students
OK
redis 127.0.0.1:> LLEN students
(integer)
业务中有先后顺序的所有列表都可以用List很好的表示(单向队列,双向队列,循环队列,各种队列)
lpush+rpop -- quenue(先进先出)
lpush+lpop -- stack
lpush+ltrim -- Capped Collection(有限集合)
lpush+brpop -- Message Queue (消息队列)
先进先出的队列+阻塞读操作,可以很方便实现 “生产者,消费者”这类问题,通常用于解耦应用程序的不同模块
Set集合
Redis能够将一系列不重复的值存储成一个集合
redis 127.0.0.1:6379> SADD sql oracle
(integer) 1
redis 127.0.0.1:6379> SADD sql mysql
(integer) 1
redis 127.0.0.1:6379> SADD nosql redis
(integer) 1
redis 127.0.0.1:6379> SADD nosql hbase
(integer) 1
redis 127.0.0.1:6379> SADD nosql neo4j
(integer) 1
redis 127.0.0.1:6379> SADD nosql MongoDB
(integer) 1
redis 127.0.0.1:6379> SMEMBERS sql
1) “oracle"
2) “mysql“
redis 127.0.0.1:6379> SMEMBERS nosql
1) "redis"
2) "hbase"
3) "neo4j"
4) “MongoDB” Sets结构也支持相应的修改操作
redis 127.0.0.1:6379> SREM nosql MongoDB
(integer) 1
redis 127.0.0.1:6379> SMEMBERS nosql
1) "redis"
2) "hbase“
3) "neo4j”
Sets还支持对集合的并等操作
redis 127.0.0.1:6379> SUNION sql nosql
1) "oracle"
2) "mysql"
3) "redis"
4) "hbase"
5) "neo4j“
Sets的随机操作
redis 127.0.0.1:6379> srandmember nosql
1) "hbase"
redis 127.0.0.1:6379> srandmember nosql
1) "redis"
srem --- 删除指定元素, spop ---- 随机删除1个元素 (抽奖)
srandmember --- 随机返回count个元素,不会删除
Sorted Set排序集 - 为每个成员分配1个分值,可根据分值排序
redis 127.0.0.1:> ZADD salary tom
(integer)
redis 127.0.0.1:> ZADD salary bob
(integer)
redis 127.0.0.1:> ZADD salary jack
(integer)
redis 127.0.0.1:> ZRANGE salary - withscores
) “bob"
) “"
) “tom"
) “"
) “jack"
) ““
redis 127.0.0.1:> ZCOUNT salary
(integer)
redis 127.0.0.1:> ZCOUNT salary
(integer)
redis 127.0.0.1:> ZRANK salary tom
(integer)
redis 127.0.0.1:> ZREVRANGE salary -
) “jack"
) “tom"
) “bob"
ZRANGE salary 0 -1 withscores ----- 从低排到高, withscores 同时返回分数
ZREVRANGE ----- 从高排到低 , 下标从0开始
ZCOUNT ---- 返回指定分数区间内的成员个数,闭区间
GEO地理位置
)增加a和b的坐标
127.0.0.1:> GEOADD test 13.361389 38.115556 a 15.087269 37.502669 b
(integer) )坐标200km内的元素
127.0.0.1:> GEORADIUS test km WITHDIST
) ) "a"
) "190.4424"
) ) "b"
) "56.4413"
127.0.0.1:> GEORADIUS test km WITHCOORD COUNT
) ) "b"
) ) "15.08726745843887329"
) "37.50266842333162032" )a和b之间的距离
127.0.0.1:> GEODIST test a b
" 166274.1516 " )增加坐标c
127.0.0.1:> GEOADD test 13.583333 37.316667 "c"
(integer) )获取c 100kM内的元素
127.0.0.1:> GEORADIUSBYMEMBER test c km
) "c"
) "a“ )获取a,b,c的坐标
127.0.0.1:> GEOPOS test a b c
) ) "13.36138933897018433"
) "38.11555639549629859"
) ) "15.08726745843887329"
) "37.50266842333162032"
) ) "13.5833314061164856"
) "37.31666804993816555"
geoadd key名 经度 纬度 成员,geoadd key可以用于更新已存在成员的位置,但返回结果为0
georadius key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count]
withcoord:返回结果中包含经纬度
withdist : 返回结果中包含离中心节点位置的距离
withhash: 返回结果中包含geohash
Publish/Subscribe及使用场景
订阅信息管道
.用一个客户端订阅管道
redis 127.0.0.1:> SUBSCRIBE channelone
Reading messages... (press Ctrl-C to quit)
) "subscribe"
) "channelone"
) (integer) .另一个客户端往这个管道推送信息
redis 127.0.0.1:> PUBLISH channelone hello
(integer)
redis 127.0.0.1:> PUBLISH channelone world
(integer) .然后第一个客户端就能获取到推送的信息
) "message"
) "channelone"
) "hello"
) "message"
) "channelone"
) "world" 按一定模式批量订阅
.用下面的命令订阅所有channel开头的信息通道
redis 127.0.0.1:> PSUBSCRIBE channel*
Reading messages... (press Ctrl-C to quit)
) "psubscribe"
) "channel*"
) (integer) .在另一个客户端对两个推送信息
redis 127.0.0.1:> PUBLISH channelone hello
(integer)
redis 127.0.0.1:> PUBLISH channeltwo world
(integer) .然后在第一个客户端就能收到推送的信息
) "pmessage"
) "channel*"
) "channelone"
) "hello"
) "pmessage"
) "channel*"
) "channeltwo"
) "world"
添加stream ,对比pub/sub和stream的区别
pub/sub 消息无法持久化,客户端断开期间消息无法获取
实例重启后,需要重新订阅
Redis事务及使用场景
.通过MULTI和EXEC,将几个命令组合起来执行
redis 127.0.0.1:> SET num
OK
redis 127.0.0.1:> MULTI
OK
redis 127.0.0.1:> INCR num
QUEUED
redis 127.0.0.1:> INCR num
QUEUED
redis 127.0.0.1:> INCR num
QUEUED
redis 127.0.0.1:> EXEC
) (integer)
) (integer)
) (integer)
redis 127.0.0.1:> GET num
"" .将EXEC替换为DICARD命令来中断执行中的命令序列
redis 127.0.0.1:> SET num
OK
redis 127.0.0.1:> MULTI
OK
redis 127.0.0.1:> INCR num
QUEUED
redis 127.0.0.1:> INCR num
QUEUED
redis 127.0.0.1:> INCR num
QUEUED
redis 127.0.0.1:> DICARD
) (integer)
) (integer)
) (integer)
redis 127.0.0.1:> GET cnt
""
事务不支持事务回滚,无法实现命令之间的逻辑关系;
错误命令处理机制:(1)语法错误,整个事务不执行
(2)命令敲错(语法正确),执行成功,回滚需要应用修复
Redis模块化
Redis4.0提供了模块化的功能,只需要在配置文件中增加了loadmodule /path/to/my_module.so参数,指定Redis在启动时加载某个模块化功能,就可以为用户提供更多的可能性。参考:https://redis.io/modules
Redis复制原理
Redis提供的高可用方案
Redis提供的分片算法
Redis迁移
redis的快速机制与数据类型的更多相关文章
- Linux07 /redis的配置、五大数据类型、发布订阅、持久化、主从复制、哨兵配置、集群搭建
Linux07 /redis的配置.五大数据类型.发布订阅.持久化.主从复制.哨兵配置.集群搭建 目录 Linux07 /redis的配置.五大数据类型.发布订阅.持久化.主从复制.哨兵配置.集群搭建 ...
- 详解 Redis 内存管理机制和实现
Redis是一个基于内存的键值数据库,其内存管理是非常重要的.本文内存管理的内容包括:过期键的懒性删除和过期删除以及内存溢出控制策略. 最大内存限制 Redis使用 maxmemory 参数限制最大可 ...
- Redis内存回收机制
为什么需要内存回收? 原因有如下两点: 在 Redis 中,Set 指令可以指定 Key 的过期时间,当过期时间到达以后,Key 就失效了. Redis 是基于内存操作的,所有的数据都是保存在内存中, ...
- 《闲扯Redis一》五种数据类型之String型
一.前言 Redis 提供了5种数据类型:String(字符串).Hash(哈希).List(列表).Set(集合).Zset(有序集合),理解每种数据类型的特点对于redis的开发和运维非常重要. ...
- Redis的持久化机制你学会了吗
大家都知道Redis经常被使用在缓存的场景中,那有没有想过这么一个问题,一旦服务器宕机,内存中的数据全部丢失,我们该如何进行恢复呢?如果直接从后端数据库恢复,不仅会给数据库带来巨大的压力,还会使上层应 ...
- Redis 发布/订阅机制原理分析
Redis 通过 PUBLISH. SUBSCRIBE 和 PSUBSCRIBE 等命令实现发布和订阅功能. 这些命令被广泛用于构建即时通信应用,比如网络聊天室(chatroom)和实时广播.实时 ...
- Redis学习笔记(二)Redis支持的5种数据类型的总结之String和Hash
引言 在Redis学习笔记(一)中我们已经会安装并且简单使用Redis了,接下来我们一起来学习下Redis支持的5大数据类型. 简介 Redis是REmote DIctionary Server(远程 ...
- Redis的删除机制、持久化 主从
转: Redis的删除机制.持久化 主从 Redis的使用分两点: 性能如下图所示,我们在碰到需要执行耗时特别久,且结果不频繁变动的SQL,就特别适合将运行结果放入缓存.这样,后面的请求就去缓存中读取 ...
- Redis内存淘汰机制
转自:https://my.oschina.net/andylucc/blog/741965 摘要 Redis是一款优秀的.开源的内存数据库,我在阅读Redis源码实现的过程中,时时刻刻能感受到Red ...
随机推荐
- A Bite Of React(1)
react: component and views : produce html abd add them on a page( in the dom) <import React from ...
- 44-python基础-python3-字符串-常用字符串方法(二)-isalpha()-isalnum()-isdigit()-isspace()-istitle()
3-isX 字符串方法 序号 方法 条件 返回结果1 返回结果2 1 isalpha() 如果字符串只包含字母,并且非空; True False 2 isalnum() 如果字符串只包含字母和数字 ...
- 区间节点的lca
题目hdu5266 分析:多节点的LCA就是dfs序中最大最小两个节点的LCA.所以只要每次维持给出节点的dfs序的最大最小,然后就是两点的LCA 代码: rmq的st+lca的倍增 #include ...
- 【转】在配置静态IP的时候遇到 :bringing up interface eth0 : error unknown connection
首先这是动态ip配置成功的结果 接下来切换到root用户来配置静态的 按照静态ip的配置方法配置好文件后(具体过程这里就不多加说明) 然后保存退出 当我们重启网卡的时候问题来了(因为本人有点强迫症,多 ...
- ELK-7.3安装部署
原文 ELK-7.3安装部署 前沿 1.什么是ELK? ELK是由Elasticsearch.Logstash.Kibana 三个开源软件的组成的一个组合体 不懂自行查阅 https://www.el ...
- JavaScript 事件——“模拟事件”的注意要点
DOM中的事件模拟 三个步骤: 首先通过document.createEvent()方法创建event对象,接收一个参数,即表示要创建的事件类型的字符串: UIEvents(DOM3中的UIEvent ...
- 如何判断一个List集合中是否有空值
list.Any(v => string.IsNullOrWhiteSpace(v))
- linux随笔-03
必须掌握的Linux命令 系统状态检测命令 1.ifconfig命令 ifconfig命令用于获取网卡配置与网络状态等信息,格式为“ifconfig [网络设备] [参数]”. 使用ifconfig命 ...
- 转载:java集合类数据结构分析
数组是 最常用的数据结构.数组的特点是长度固定,可以用下标索引,并且所有的元素的类型都是一致的.数组常用的场景有把:从数据库里读取雇员的信息存储为 EmployeeDetail[],把一个字符串转换并 ...
- jQuery实现网页放大镜功能 转载
京东等电商网站中可以对商品进行放大观察,本文要实现的就是模仿这个放大镜功能,大致效果如下图所示: 简要说明实现思路: 1.原图窗口与放大窗口插入的是同一个图片,不过原图窗口的图片要适当缩小,放大窗口图 ...