Redis小结

一. Redis简介  

  Redis是一个速度非常快的高性能的key-value存储系统。redis的出现,很大程度补偿了memcached这类key/value存储的不足。Redis支持存储五种value数据类型,包括string(字符串)、list(链表)、set(集合)、hash(哈希类型)和zset(sorted set --有序集合)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。为了保证效率,数据都是缓存在内存中。redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文 件,并且在此基础上实现了master-slave(主从)同步。另外,Redis数据存在内存里面,速度非常快。

二. Redis的优点

  1. 速度快,因为数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1)
  2. 支持丰富数据类型,支持string,list,set,sorted set,hash
  3. 支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行
  4. 丰富的特性:可用于缓存,消息,按key设置过期时间,过期后将会自动删除

三. Redis与其他一些数据库和缓存服务器的特性与功能的对比如下:


名称


类型


数据存储选项


查询类型


附加功能


Redis


使用内存存储(in-memory)的非关系数据库


字符串、列表、集合、散列表、有序集合


每种数据类型都有自己的专属命令,另外还有批量操作(bulk operation)和不完全(partial)的事务支持


发布与订阅,主从复制(master/slave replication),持久化,脚本(存储过程,stored procedure)


memcached


使用内存存储的键值缓存


键值之间的映射


创建命令、读取命令、更新命令、删除命令以及其他几个命令


为提升性能而设的多线程服务器


MySQL


关系数据库


每个数据库可以包含多个表,每个表可以包含多个行;可以处理多个表的视图(view);支持空间(spatial)和第三方扩展


SELECTINSERTUPDATEDELETE、函数、存储过程


支持ACID性质(需要使用InnoDB),主从复制和主主复制 (master/master replication)


PostgreSQL


关系数据库


每个数据库可以包含多个表,每个表可以包含多个行;可以处理多个表的视图;支持空间和第三方扩展;支持可定制类型


SELECTINSERTUPDATEDELETE、内置函数、自定义的存储过程


支持ACID性质,主从复制,由第三方支持的多主复制(multi-master replication)


MongoDB


使用硬盘存储(on-disk)的非关系文档存储


每个数据库可以包含多个表,每个表可以包含多个无schema(schema-less)的BSON文档


创建命令、读取命令、更新命令、删除命令、条件查询命令等


支持map-reduce操作,主从复制,分片,空间索引(spatial index)

四. Redis的持久化方式

  在使用类似Redis这样的内存数据库时,一个首先要考虑的问题就是“当服务器被关闭时,服务器存储的数据将何去何从呢?”

  Redis拥有两种不同形式的持久化方法,它们都可以用小而紧凑的格式将存储在内存中的数据写入硬盘:

  第一种持久化方法为RDB,即时间点转储(point-in-time dump)。有一份数据,就把这一份数据整体保存一份,每隔一定的时间就保存一下数据,保存的是最终的结果。转储操作既可以在“指定时间段内有指定数量的写操作执行”这一条件被满足时执行,又可以通过调用两条转储到硬盘(dump-to-disk)命令中的任何一条来执行;

  第二种持久化方法是AOP,将所有修改了数据库的命令都写入一个只追加(append-only)文件里面,保存的是命令操作。用户可以根据数据的重要程度,将只追加写入设置为从不同步(sync)、每秒同步一次或者每写入一个命令就同步一次。

五. Redis的主从同步

  Redis实现了主从复制特性:执行复制的从服务器会连接上主服务器,接收主服务器发送的整个数据库的初始副本(copy);之后主服务器执行的写命令,都会被发送给所有连接着的从服务器去执行,从而实时地更新从服务器的数据集。因为从服务器包含的数据会不断地进行更新,所以客户端可以向任意一个从服务器发送读请求,以此来避免对主服务器进行集中式的访问。

六. Redis的value的数据类型

1. String(字符串)

string是redis最基本的类型,一个key对应一个value。
string类型是二进制安全的。意思是redis的string可以包含任何数据。比如jpg图片或者序列化的对象 。
string类型是Redis最基本的数据类型,一个键最大能存储512MB。

1.1 常用命令

除了get、set、incr、decr mget等操作外,Redis还提供了下面一些操作:

  • 获取字符串长度
  • 往字符串append内容
  • 设置和获取字符串的某一段内容
  • 设置及获取字符串的某一位(bit)
  • 批量设置一系列字符串的内容
1.2 应用场景

  String是最常用的一种数据类型,普通的key/value存储都可以归为此类,value其实不仅是String, 也可以是数字:比如想知道什么时候封锁一个IP地址(访问超过几次)。INCRBY命令让这些变得很容易,通过原子递增保持计数。

1.3 实现方式

  m,decr等操作时会转成数值型进行计算,此时redisObject的encoding字段为int。

1.4 实例
 1 // get,set
 2 jedis.set("hello", "world");
 3 print(1, jedis.get("hello"));
 4 jedis.rename("hello", "newhello");
 5 print(1, jedis.get("newhello"));
 6 jedis.setex("hello2", 15, "world");
 7 // 数值操作
 8 jedis.set("pv", "100");
 9 jedis.incr("pv");
10 jedis.decrBy("pv", 5);
11 print(2, jedis.get("pv"));
12 print(3, jedis.keys("*"));

2. List(列表)

  Redis 列表是简单的字符串列表,按照插入顺序排序。可以添加一个元素到列表的头部(左边)或者尾部(右边)。列表最多可存储 2^32 - 1 元素 (4294967295, 每个列表可存储40多亿)。

2.1 常用命令

  lpush,rpush,lpop,rpop,lrange,BLPOP(阻塞版)等。

2.2 应用场景

  Redis list的应用场景非常多,也是Redis最重要的数据结构之一。

  我们可以轻松地实现最新消息排行榜等功能(比如新浪微博的 TimeLine )。

  Lists的另一个应用就是消息队列,可以利用List的PUSH操作,将任务存在Lists中,然后工作线程再用POP操作将任务取出进行执行。

2.3 实现方式

  Redis list的实现为一个双向链表,即可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销,Redis内部的很多实现,包括发送缓冲队列等也都是用的这个数据结构。

2.4 实例
 1 // 列表操作, 最近来访, 粉丝列表,消息队列
 2 String listName = "list";
 3 jedis.del(listName);
 4 for (int i = 0; i < 10; ++i) {
 5     jedis.lpush(listName, "a" + String.valueOf(i));
 6 }
 7 print(4, jedis.lrange(listName, 0, 12)); // 最近来访10个id
 8 print(5, jedis.llen(listName));
 9 print(6, jedis.lpop(listName));
10 print(7, jedis.llen(listName));
11 print(8, jedis.lrange(listName, 2, 6)); // 最近来访10个id
12 print(9, jedis.lindex(listName, 3));
13 print(10, jedis.linsert(listName, BinaryClient.LIST_POSITION.AFTER, "a4", "xx"));
14 print(10, jedis.linsert(listName, BinaryClient.LIST_POSITION.BEFORE, "a4", "bb"));
15 print(11, jedis.lrange(listName, 0, 12));

3.Set(集合)

  Redis的Set是string类型的无序集合。集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。集合中最大的成员数为 2^32 - 1 (4294967295, 每个集合可存储40多亿个成员)。

3.1 常用命令

  sadd,srem,spop,sdiff ,smembers,sunion 等。

3.2 应用场景

  Redis set对外提供的功能与list类似是一个列表的功能,特殊之处在于set是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的。

  1. 共同好友、二度好友
  2. 利用唯一性,可以统计访问网站的所有独立 IP
  3. 好友推荐的时候,根据 tag 求交集,大于某个 threshold 就可以推荐

  在微博应用中,可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存在一个集合。因为 Redis 非常人性化的为集合提供了求交集、并集、差集等操作,那么就可以非常方便的实现如共同关注、共同喜好、二度好友等功能,对上面的所有集合操作,你还可以使用不同的命令选择将结果返回给客户端还是存集到一个新的集合中。

3.3 实现方式

  set 的内部实现是一个 value永远为null的HashMap,实际就是通过计算hash的方式来快速排重的,这也是set能提供判断一个成员是否在集合内的原因。

3.4 实例
 1 String likeKey1 = "newsLike1";
 2 String likeKey2 = "newsLike2";
 3 for (int i = 0; i < 10; ++i) {
 4     jedis.sadd(likeKey1, String.valueOf(i));
 5     jedis.sadd(likeKey2, String.valueOf(i * 2));
 6 }
 7 print(20, jedis.smembers(likeKey1));
 8 print(21, jedis.smembers(likeKey2));
 9 print(22, jedis.sunion(likeKey1, likeKey2));
10 print(23, jedis.sdiff(likeKey1, likeKey2));
11 print(24, jedis.sinter(likeKey1, likeKey2));
12 print(25, jedis.sismember(likeKey1, "12"));
13 print(26, jedis.sismember(likeKey2, "12"));
14 jedis.srem(likeKey1, "5");
15 print(27, jedis.smembers(likeKey1));
16 // 从1移动到2
17 jedis.smove(likeKey2, likeKey1, "14");
18 print(28, jedis.smembers(likeKey1));
19 print(29, jedis.scard(likeKey1));

4.Hash(哈希)

  Redis hash 是一个键值对集合。它是一个string类型的field和value的映射表,hash特别适合用于存储对象。集合中最大的成员数为 2^32 - 1 (4294967295, 每个集合可存储40多亿个成员)。

4.1 常用命令

  hget,hset,hgetall 等。

4.2 应用场景

  存储、读取、修改用户属性。

  Redis的Hash实际是内部存储的Value为一个HashMap, 并提供了直接存取这个Map成员的接口, 如:hmset user:001 name "李三" age 18 birthday "20010101" ,也就是说,Key仍然是用户ID,value是一个Map,这个Map的key是成员的属性名,value是属性值, 这样对数据的修改和存取都可以直接通过其内部Map的Key(Redis里称内部Map的key为field), 也就是通过 key(用户ID) + field(属性标签) 操作对应属性数据了,既不需要重复存储数据,也不会带来序列化和并发修改控制的问题。Redis 的 Hash 结构可以像在数据库中 Update 一个属性一样只修改某一项属性值。

4.3 实现方式

  Redis Hash对应Value内部实际就是一个HashMap,实际这里会有2种不同实现,这个Hash的成员比较少时Redis为了节省内存会采用类似一维数组的方式来紧凑存储,而不会采用真正的HashMap结构,对应的value redisObject的encoding为zipmap,当成员数量增大时会自动转成真正的HashMap,此时encoding为ht。

4.4 实例
 1 // hash, 可变字段
 2 String userKey = "userxx";
 3 jedis.hset(userKey, "name", "jim");
 4 jedis.hset(userKey, "age", "12");
 5 jedis.hset(userKey, "phone", "18666666666");
 6 print(12, jedis.hget(userKey, "name"));
 7 print(13, jedis.hgetAll(userKey));
 8 jedis.hdel(userKey, "phone");
 9 print(14, jedis.hgetAll(userKey));
10 print(15, jedis.hexists(userKey, "email"));
11 print(16, jedis.hexists(userKey, "age"));
12 print(17, jedis.hkeys(userKey));
13 print(18, jedis.hvals(userKey));
14 jedis.hsetnx(userKey, "school", "zju");//这个方法是先判断有没有这个字段,没有的话才进行设置
15 jedis.hsetnx(userKey, "name", "yxy");
16 print(19, jedis.hgetAll(userKey));

5.zset(sorted set:有序集合)

  Redis zset 和 set 一tring类型元素的集合,且不允许重复的成员。不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。zset的成员是唯一的,但分数(score)却可以重复。

5.1 常用命令 

  zadd,zrange,zrem,zcard等

5.2 使用场景 
  1. 带有权重的元素,比如一个游戏的用户得分排行榜
  2. 比较复杂的数据结构,一般用到的场景不算太多

  以某个条件为权重,比如按顶的次数排序。ZREVRANGE命令可以用来按照得分来获取前100名的用户,ZRANK可以用来获取用户排名,非常直接而且操作容易。

  Redis sorted set的使用场景与set类似,区别是set不是自动有序的,而sorted set可以通过用户额外提供一个优先级(score)的参数来为成员排序,并且是插入有序的,即自动排序。比如:twitter 的public timeline可以以发表时间作为score来存储,这样获取时就是自动按时间排好序的。比如:全班同学成绩的SortedSets,value可以是同学的学号,而score就可以是其考试得分,这样数据插入集合的,就已经进行了天然的排序。

  另外还可以用Sorted Sets来做带权重的队列,比如普通消息的score为1,重要消息的score为2,然后工作线程可以选择按score的倒序来获取工作任务。让重要的任务优先执行。

5.3 实现方式

  Redis sorted set的内部使用HashMap和跳跃表(SkipList)来保证数据的存储和有序,HashMap里放的是成员到score的映射,而跳跃表里存放的是所有的成员,排序依据是HashMap里存的score,使用跳跃表的结构可以获得比较高的查找效率,并且在实现上比较简单。

5.4 实例
 1 // 排序集合,有限队列,排行榜
 2 String rankKey = "rankKey";
 3 jedis.zadd(rankKey, 15, "Jim");
 4 jedis.zadd(rankKey, 60, "Ben");
 5 jedis.zadd(rankKey, 90, "Lee");
 6 jedis.zadd(rankKey, 75, "Lucy");
 7 jedis.zadd(rankKey, 80, "Mei");
 8 print(30, jedis.zcard(rankKey));
 9 print(31, jedis.zcount(rankKey, 61, 100));
10 // 改错卷了
11 print(32, jedis.zscore(rankKey, "Lucy"));
12 jedis.zincrby(rankKey, 2, "Lucy");
13 print(33, jedis.zscore(rankKey, "Lucy"));
14 jedis.zincrby(rankKey, 2, "Luc");
15 print(34, jedis.zscore(rankKey, "Luc"));
16 print(35, jedis.zcount(rankKey, 0, 100));
17 // 1-4 名 Luc
18 print(36, jedis.zrange(rankKey, 0, 10));
19 print(36, jedis.zrange(rankKey, 1, 3));
20 print(36, jedis.zrevrange(rankKey, 1, 3));
21 for (Tuple tuple : jedis.zrangeByScoreWithScores(rankKey, "60", "100")) {
22     print(37, tuple.getElement() + ":" + String.valueOf(tuple.getScore()));
23 }
24 print(38, jedis.zrank(rankKey, "Ben"));
25 print(39, jedis.zrevrank(rankKey, "Ben"));
26 String setKey = "zset";
27 jedis.zadd(setKey, 1, "a");
28 jedis.zadd(setKey, 1, "b");
29 jedis.zadd(setKey, 1, "c");
30 jedis.zadd(setKey, 1, "d");
31 jedis.zadd(setKey, 1, "e");
32 print(40, jedis.zlexcount(setKey, "-", "+"));
33 print(41, jedis.zlexcount(setKey, "(b", "[d"));
34 print(42, jedis.zlexcount(setKey, "[b", "[d"));
35 jedis.zrem(setKey, "b");
36 print(43, jedis.zrange(setKey, 0, 10));
37 jedis.zremrangeByLex(setKey, "(c", "+");
38 print(44, jedis.zrange(setKey, 0, 2));

参考:http://www.epubit.com.cn/article/200

http://www.jb51.net/article/54774.htm

http://blog.csdn.net/gaogaoshan/article/details/41039581/

时间: 2024-10-14 14:38:04

Redis小结的相关文章

Memcache和Redis复习总结

Memcache Memcache是一个高性能的分布式的内存对象缓存系统,主要是用来缓存从MySQL数据库中查询的数据,减少对mysql数据库的压力. Memcache的工作流程: 当用户发生一个动态请求的时候,先去Memcache服务器里面查询缓存数据,当首次查询的时候,Memcache里面肯定是没有数据的,这个时候需要php程序去MySQL数据库里面获取数据,将获取先缓存一份到Memcache服务器里面,在把数据返回给用户.当第二次发生相同的动态的请求的时候,这个时候由于上一次上Memcac

15 数据模型特殊属性

数据模型特殊属性 Rowkey.Column(列族和列).Version 组合在一起称为 HBase 中的一个单元格.有可能会有很多单元格的 行和列 是相同的,要区分不同的单元格可以使用版本.     如果有多个版本的写操作同时发起,HBase 都会保存 可以发起包含版本的写操作 Delete 内部删除标记三种不同类型. Delete                     : 删除列指定的版本. Delete Column     :删除列的所有版本. Delete Family       

使用 Docker 在 Linux 上托管 ASP.NET Core 应用程序

说在前面 在阅读本文之前,您必须对 Docker 的中涉及的基本概念以及常见命令有一定了解,本文侧重实战,不会对相关概念详述. 同时请确保您本地开发机器已完成如下安装: Docker 18.06 或更高版本的 Docker 客户端 .NET Core SDK 2.2 或更高版本 Visual Studio Code 代码编辑器,以及 C# 语法插件 1.17.1 或更高版本 注:本文实验环境是 Ubuntu 18.04 LTS.如果您的机器是 Window,也可以把 Docker 装在虚拟机或服

redis的小结

redis使用场景: 1.在主页中显示最新的项目列表. 2.删除和过滤 3.排行榜及相关问题. 4.按照用户投票和时间排序. 5.过期项目处理. 6.计数. 7.特定时间内的特定项目. 8.实时分析正在发生的情况,用于数据统计与防止垃圾邮件等. 9.Pub/Sub. 10.队列. 11.缓存. 12.关注者列表. 13.共同关注. ............... 1.redis包含如下结构(引自官方): Binary-safe strings. Lists: collections of str

redis开发小结

随着缓存在web服务中用的越来越广泛,redis可以说成为了目前最流行的NoSQL数据库!redis与memcached最大的不同在于redis支持更多的数据类型,包括string.hash.list.set.sorted list等,所以redis的发展非常迅速,很多公司已将memcached替换为redis.我也做了一些redis的开发,现做一些小结. 1. redis常用配置 daemonize no     //Redis默认不是以守护进程的方式运行,可以通过该配置项修改,使用yes启用

Redis初学及与Spring集成小结

Redis初学及与Spring集成小结 1.redis是干什么的? redis是一种key-value内存数据库.在技术日新月异的发展环境下,客户的访问需求也在逐渐增长,物理数据库的压力也越来越大,由此redis也应运而生. redis常用的方式是将redis作为缓存数据库,减小物理数据库的访问压力: 2.redis常用数据结构: a.strings: set key value;设置key-value值 get key;获取key的value值 redis...method(redis中的一些

redis学习小结一

Redis知识点小结一 概念: 内存数据库,用于做缓存.可做分布式锁,提供多种数据类型支持不同业务场景.支持事务.持久化.LUA脚本.LRU驱动事件. 高性能和高并发 高性能:第一次访问数据库中的数据会比较慢,因为是从磁盘上读取.将用户第一次访问的数据放入缓存,第二次或以后的多次访问直接查缓存,没有再去磁盘,提高查询效率,缩短查询时间.如果数据库中的数据改变,那么就同步改变缓存中的数据. 高并发:直接操作缓存能够承受的请求远远超过直接访问数据的请求.可以考虑将部分数据库中的数据移到缓存中,从而实

Redis部分数据结构方法小结

package com.practice.util; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import redis.clients.jedis.Jedis; import redi

Redis系列-存储篇sorted set主要操作函数小结

redis支持有序集合,即sorted set.sorted set在set的基础上,增加了排序属性,是set的升级版.这里简要谈谈sorted set的常用函数: 1)insert a)  zadd 语法:zadd key score member [[score member] [score member] ...] 解释:增加一个或多个member[根据score排序]到有序集key中,如果member已经存在,只更新score.返回增加member个数,不包含已经存在的member [p