Redis泛泛而谈(详细3W字)

Posted JAVA炭烧

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis泛泛而谈(详细3W字)相关的知识,希望对你有一定的参考价值。

本文适合于刚接触redis的,文章内容比较基础,大佬请绕道。

一、NoSQL入门和概述

Ⅰ-入门概述

1.为什么用NoSQL

1)单机MySQL的美好年代

在90年代,一个网站的访问量一般都不大,用单个数据库完全可 以轻松应付。

在那个时候,更多的都是静态网页,动态交互类型的网站不多。

DAL dal是数据访问层的英文缩写,即为数据访问层(Data Access Layer)

上述架构下,我们来看看数据存储的瓶颈是什么?

  1. 数据量的总大小一个机器放不下时
  2. 数据的索引(B+ Tree)一个机器的内存放不下时
  3. 访问量(读写混合)一个实例不能承受

如果满足了上述1or3个,进化…

2)Memcached(缓存)+MySQL+垂直拆分

后来,随着访问量的上升,几乎大部分使用mysql架构的网站在数据库上都开始出现了性能问题,web程序不再仅仅专注在功能上,同时也在追求性能。程序员们开始大量的使用缓存技术来缓解数据库的压力,优化数据库的结构和索引。开始比较流行的是通过文件缓存来缓解数据库压力,但是当访问量继续增大的时候,多台web机器通过文件缓存不能共享,大量的小文件缓存也带了了比较高的IO压力。在这个时候,Memcached就自然的成为一个非常时尚的技术产品。MySQL前面挡了一层Cache

3)Mysql主从读写分离

由于数据库的写入压力增加,Memcached 只能缓解数据库的读取压力。读写集中在一个数据库上让数据库不堪重负,大部分网站开始使用主从复制技术来达到读写分离,以提高读写性能和读库的可扩展性。Mysql的master-slave模 式成为这个时候的网站标配了。

4)分表分库+水平拆分+mysql集群

在Memcached的高速缓存,MySQL的主从复制, 读写分离的基础之上,这时MySQL主库的写压力开始出现瓶颈,而数据量的持续猛增,由于MyISAM使用表锁,在高并发下会出现严重的锁问题,大量的高并发MySQL应用开始使用InnoDB引擎代替MyISAM。

同时,开始流行使用分表分库来缓解写压力和数据增长的扩展问题。这个时候,分表分库成了一个热门技术,是面试的热门问题也是业界讨论的热门技术问题。也就在这个时候,MySQL推出了还不太稳定的表分区,这也给技术实力一般的公司带来了希望。虽然MySQL推出了MySQL Cluster集群,但性能也不能很好满足互联网的要求,只是在高可靠性上提供了非常大的保证。

5)MySQL的扩展性瓶颈

MySQL数据库也经常存储一些大文本字段,导致数据库表非常的大,在做数据库恢复的时候就导致非常的慢,不容易快速恢复数据库。比如1000万4KB大小的文本就接近40GB的大小, 如果能把这些数据从MySQL省去,MySQL将变得非常的小。关系数据库很强大,但是它并不能很好的应付所有的应用场景。MySQL的扩展性差(需要复杂的技术来实现),大数据下IO压力大,表结构更改困难,正是当前使用MySOL的开发人员面临的问题。

6)今天是什么样子? ?

7)为什么用NoSQL

今天我们可以通过第三方平台( 如: Google,Facebook等) 可以很容易的访问和抓取数据。用户的个人信息,社交网络,地理位置,用户生成的数据和用户操作日志已经成倍的增加。我们如果要对这些用户数据进行挖掘,那SQL数据库已经不适合这些应用了,NoSQL数据库的发展也却能很好的处理这些大的数据。

2.是什么

NoSQL(NoSQL = Not Only SQL),意即“不仅仅是SQL”,泛指非关系型的数据库。随着互联网web2.0网站的兴起,传统的关系数据库在应付web2.0网站,特别是超大规模和高并发的SNS类型的web2.0纯动态网站已经显得力不从心,暴露了很多难以克服的问题,而非关系型的数据库则由于其本身的特点得到了非常迅速的发展。NoSQL 数据库的产生就是为了解决大规模数据集合多重数据种类带来的挑战,尤其是大数据应用难题,包括超大规模数据的存储。

(例如谷歌或Facebook每天为他们的用户收集万亿比特的数据)。这些类型的数据存储不需要固定的模式,无需多余操作就可以横向扩展。

3.能干嘛

易扩展

NoSQL数据库种类繁多,但是一个共同的特点都是去掉关系数据库的关系型特性。数据之间无关系,这样就非常容易扩展。也无形之间,在架构的层面上带来了可扩展的能力。(关系型数据库如MySQL的字段就不方便随时扩展)

大数据量高性能

NoSQL数据库都具有非常高的读写性能,尤其在大数据量下,同样表现优秀。
这得益于它的无关系性,数据库的结构简单。

一般MySQL使用Query Cache,每次表的更新Cache就失效,是一种大粒度的Cache,在针对web2.0的交互频繁的应用,Cache性能不高。

而NoSQL的Cache是记录级的,是一种细粒度的Cache,所以NoSQL在这个层面上来说就要性能高很多了。

多样灵活的数据模型

NoSQL无需事先为要存储的数据建立字段,随时可以存储自定义的数据格式。

而在关系数据库里,增删字段是一件非常麻烦的事情。如果是非常大数据量的表,增加字段简直就是一个噩梦。

传统RDBMS VS NOSQL

RDBMS

  • 高度组织化结构化数据
  • 结构化查询语言(SQL)
  • 数据和关系都存储在单独的表中
  • 数据操纵语言,数据定义语言
  • 严格的一致性

NoSQL

  • 代表着不仅仅是SQL
  • 没有声明性查询语言
  • 没有预定义的模式
  • 键-值对存储,列存储,文档存储,图形数据库
  • 最终一致性,而非ACID属性
  • 非结构化和不可预知的数据:
  • CAP定理
  • 高性能,高可用性和可伸缩性

4.有哪些NoSQL

  • Redis
  • Memcached
  • MongDB

5.怎么玩

  • KV
  • Cache
  • Persistence

Ⅱ-3V + 3高

大数据时代的3V:

  • 海量Volume
  • 多样Variety
  • 实时Velocity

互联网需求的3高:

  • 高并发
  • 高可括
  • 高性能

Ⅲ-当下NoSQL应用场景简介

1.Alibaba中文站商品信息如何存放

看看阿里巴巴中文网站首页以女装/女包包为例

架构发展历程:

演变过程

2. 第5代

3.第5代架构使命

和我们相关的,多数据源类型的存储问题

2.商品信息的存储方案

下面介绍电商系统中的各种信息数据需要哪些东西去存储:

1.商品基本信息

  • 名称、价格,出厂日期,生产厂商等存储关系型数据库
  • 关系型数据库,mysql/oracle目前淘宝在去O化(也即拿掉Oracle),注意,淘宝内部用的Mysql是里面的大牛自己改造过的

为什么去IOE(在IT建设过程中,去除IBM小型机、Oracle数据库及EMC存储设备) 简而意之,可不用穿脚链跳舞。

2.商品描述、详情、评价信息(多文字类)

  • 多文字信息描述类,IO读写性能变差
  • 文档数据库MongDB(文档类使用存储)

3.商品的图片

  • 商品图片展现类
  • 分布式的文件系统中

淘宝自家TFS
Google的GFS
Hadoop的HDFS

4.商品的关键字

  • 搜索引擎,淘宝自家
  • ISearch

5.商品的波段性的热点高频信息(如,情人节的巧克力)

  • 内存数据库
  • Tair(美团)、Redis、Memcache

6.商品的交易、价格计算、积分累计

  • 外部系统,外部第3方支付接口
  • 支付宝、微信

3.总结大型互联网应用

(大数据、高并发、多样数据类型)的难点和解决方案)

  • 难点

1.数据类型多样性

2.数据源多样性和变化重构(redis,MySQL,mongodb等等太多了,能不能抽象一个类似接口的模式)

3.数据源改造而数据服务平台不需要大面积重构

  • 解决方法

1.EAI

2.UDSL 统一数据平台服务层

3.是什么 :

Ⅳ-NoSQL数据模型简介

以一个电商客户、订单、订购、地址模型来对比关系型数据库和非关系型数据库:

  • 传统关系型数据库如何设计

ER图(1:1、1:N、N:N)主外键等

  • NOSQL如何设计

BSON ()是一种类json的一种二进制形式的存储格式,简称Binary JSON,它和JSON一样,支持内嵌的文档对象和数组对象

{
 "customer":{
   "id":1136,
   "name":"Z3",
   "billingAddress":[{"city":"beijing"}],
   "orders":[
    {
      "id":17,
      "customerId":1136,
      "orderItems":[{"productId":27,"price":77.5,"productName":"thinking in java"}],
      "shippingAddress":[{"city":"beijing"}]
      "orderPayment":[{"ccinfo":"111-222-333","txnid":"asdfadcd334","billingAddress":{"city":"beijing"}}],
      }
    ]
  }
}
  • 两者对比,问题和难点

问题和难点

1.为什么用聚合模型(NoSQL)来处理

  • 高并发的操作是不太建议用关联查询的,互联网公司用冗余数据来避免关联查询

  • 分布式事务是支持不了太多的并发的

聚合模型

  • KV
  • BSON
  • 列族

顾名思义,是按列存储数据的。最大的特点是方便存储结构化和半结构化数据,方便做数据压缩,对针对某一 列或者某几列的查询有非常大的IO优势。

  • 图形

Ⅴ-NoSQL数据库的四大分类

  1. KV

新浪:BerkeleyDB + Redis
美团:Redis + tair
阿里、百度:memcache + Redis

2.文档型数据库(bson格式比较多)

  • CouchDB
  • MongoDB

MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。
MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。

3.列存储数据库

Cassandra、HBase
分布式文件系统

4.图关系数据库

它不是放图形的、放的是关系比如:朋友圈社交网络、广告推荐系统
社交网络、推荐系统。专注于构建关系图谱
Neo4j、InfoGrid

NoSQL的四个维度四者对比

Ⅵ-分布式数据库CAP原理

1.传统的ACID分别是什么

  • A (Atomicity) 原子性
  • C (Consistency) 一致性
  • I (Isolation) 独立性
  • D (Durability) 持久性

关系型数据库遵循ACID规则,事务在英文中是transaction,和现实世界中的交易很类似,它有如下四个特性:

1、A (Atomicity) 原子性 原子性很容易理解,也就是说事务里的所有操作要么全部做完,要么都不做,事务成功的条件是事务里的所有操作都成功,只要有一个操作失败,整个事务就失败,需要回滚。比如银行转账,从A账户转100元至B账户,分为两个步骤:1)从A账户取100元;2)存入100元至B账户。这两步要么一起完成,要么一起不完成,如果只完成第一步,第二步失败,钱会莫名其妙少了100元。

2、C (Consistency) 一致性 一致性也比较容易理解,也就是说数据库要一直处于一致的状态,事务的运行不会改变数据库原本的一致性约束。

3、I (Isolation) 独立性 所谓的独立性是指并发的事务之间不会互相影响,如果一个事务要访问的数据正在被另外一个事务修改,只要另外一个事务未提交,它所访问的数据就不受未提交事务的影响。比如现有有个交易是从A账户转100元至B账户,在这个交易还未完成的情况下,如果此时B查询自己的账户,是看不到新增加的100元的

4、D (Durability) 持久性 持久性是指一旦事务提交后,它所做的修改将会永久的保存在数据库上,即使出现宕机也不会丢失。

2.CAP

  • C:Consistency(强一致性)
  • A:Availability(可用性)
  • P:Partition tolerance(分区容错性)

CAP理论就是说在分布式存储系统中,最多只能实现上面的两点。

而由于当前的网络硬件肯定会出现延迟丢包等问题,所以分区容错性是我们必须需要实现的。所以我们只能在一致性和可用性之间进行权衡,没有NoSQL系统能同时保证这三点。

C:强一致性 A:高可用性 P:分布式容忍性

  • CA 传统Oracle数据库
  • AP 大多数网站架构的选择
  • CP Redis、Mongodb

注意:分布式架构的时候必须做出取舍。

一致性和可用性之间取一个平衡。多余大多数web应用,其实并不需要强一致性。因此牺牲C换取P,这是目前分布式数据库产品的方向。

一致性C与可用性A的决择

对于web2.0网站来说,关系数据库的很多主要特性却往往无用武之地

数据库事务一致性需求

很多web实时系统并不要求严格的数据库事务,对读一致性的要求很低, 有些场合对写一致性要求并不高。允许实现最终一致性。

数据库的写实时性和读实时性需求

对关系数据库来说,插入一条数据之后立刻查询,是肯定可以读出来这条数据的,但是对于很多web应用来说,并不要求这么高的实时性,比方说在微博发一条消息之后,过几秒乃至十几秒之后,我的订阅者才看到这条动态是完全可以接受的。

对复杂的SQL查询,特别是多表关联查询的需求

任何大数据量的web系统,都非常忌讳多个大表的关联查询,以及复杂的数据分析类型的报表查询,特别是SNS类型的网站,从需求以及产品设计角 度,就避免了这种情况的产生。往往更多的只是单表的主键查询,以及单表的简单条件分页查询,SQL的功能被极大的弱化了。

3.经典CAP图

CAP理论的核心是:一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性这三个需求,最多只能同时较好的满足两个。

因此,根据 CAP 原理将 NoSQL 数据库分成了满足 CA 原则、满足 CP 原则和满足 AP 原则三 大类:

  • CA - 单点集群,满足一致性,可用性的系统,通常在可扩展性上不太强大。
  • CP - 满足一致性,分区容忍必的系统,通常性能不是特别高。
  • AP - 满足可用性,分区容忍性的系统,通常可能对一致性要求低一些

4.BASE

BASE就是为了解决关系数据库强一致性引起的问题而引起的可用性降低而提出的解决方案。

BASE其实是下面三个术语的缩写:

  • 基本可用(Basically Available)
  • 软状态(Soft state)
  • 最终一致(Eventually consistent)

它的思想是通过让系统放松对某一时刻数据一致性的要求来换取系统整体伸缩性和性能上改观。为什么这么说呢,缘由就在于大型系统往往由于地域分布和极高性能的要求,不可能采用分布式事务来完成这些指标,要想获得这些指标,我们必须采用另外一种方式来完成,这里BASE就是解决这个问题的办法

5.分布式+集群简介

分布式系统(distributed system)

由多台计算机和通信的软件组件通过计算机网络连接(本地网络或广域网)组成。分布式系统是建立在网络之上的软件系统。正是因为软件的特性,所以分布式系统具有高度的内聚性和透明性。因此,网络和分布式系统之间的区别更多的在于高层软件(特别是操作系统),而不是硬件。分布式系统可以应用在在不同的平台上如:PC、工作站、局域网和广域网上等。

简单来讲:

  1. 分布式:不同的多台服务器上面部署不同的服务模块(工程),他们之间通过RPC/RMI之间通信和调用,对外提供服务和组内协作。
  2. 集群:不同的多台服务器上面部署相同的服务模块,通过分布式调度软件进行统一的调度,对外提供服务和访问。

二、Redis入门介绍

Ⅰ-入门概述

是什么

Redis:REmote DIctionary Server(远程字典服务器)是完全开源免费的,用C语言编写的,遵守BSD协议,是一个高性能的(key/value)分布式内存数据库,基于内存运行 并支持持久化的NoSQL数据库,是当前最热门的NoSql数据库之一,也被人们称为数据结构服务器。

Redis 与其他 key - value 缓存产品有以下三个特点:

  • Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用
  • Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储
  • Redis支持数据的备份,即master-slave模式的数据备份

能干嘛

  • 内存存储和持久化:redis支持异步将内存中的数据写到硬盘上,同时不影响继续服务
  • 取最新N个数据的操作,如:可以将最新的10条评论的ID放在Redis的List集合里面
  • 模拟类似于HttpSession这种需要设定过期时间的功能
  • 发布、订阅消息系统
  • 定时器、计数器

去哪下

  • Redis官网
  • Redis中文网

怎么玩

  • 数据类型、基本操作和配置
  • 持久化和复制,RDB/AOF
  • 事务的控制
  • 复制(主从关系)

Ⅱ-Redis的安装

略(见服务器配置)

Ⅲ-HelloWorld

在前面make install后指定安装目录后:

# -p是指定端口  -a是输入密码 (前面在redis.conf中设置了密码,如果未设置可省略)
[root@localhost bin]# redis-cli -p 6379 -a coderxz
-bash: redis-cli: 未找到命令
[root@localhost bin]# ./redis-cli -p 6379 -a coderxz
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> set k1 hello
OK
127.0.0.1:6379> get k1
"hello"
127.0.0.1:6379>

Ⅳ-启动后杂项基础知识

redis-benchmark 可测试redis在机器运行的效能

[root@localhost bin]# ./redis-benchmark
====== PING_INLINE ======
  100000 requests completed in 0.59 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

99.96% <= 4 milliseconds
99.99% <= 5 milliseconds
100.00% <= 5 milliseconds
168634.06 requests per second

====== PING_BULK ======
  100000 requests completed in 0.63 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

99.85% <= 1 milliseconds
99.92% <= 2 milliseconds
99.95% <= 4 milliseconds
99.98% <= 5 milliseconds
100.00% <= 5 milliseconds
158227.84 requests per second #每秒钟15W

====== SET ======
  100000 requests completed in 0.57 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

100.00% <= 0 milliseconds
175746.92 requests per second

====== GET ======
  100000 requests completed in 0.57 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

100.00% <= 0 milliseconds
175131.36 requests per second
。。。。。。略
  • 单进程

单进程模型来处理客户端的请求。对读写等事件的响应 是通过对epoll函数的包装来做到的。Redis的实际处理速度完全依靠主进程的执行效率

Epoll是Linux内核为处理大批量文件描述符而作了改进的epoll,是Linux下多路复用IO接口select/poll的增强版本, 它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率。

默认16个数据库,类似数组下表从零开始,初始默认使用零号库,可在配置文件配置

设置数据库的数量,默认数据库为0,可以使用SELECT < dbid >命令在连接上指定数据库iddatabases 16

127.0.0.1:6379> select 2
OK
127.0.0.1:6379[2]>
  • select 命令切换数据库
  • dbsize 查看当前数据库的key的数量 keys *查看所有的key
  • flushdb:清空当前库
  • flushall;通杀全部库
  • 统一密码管理,16个库都是同样密码,要么都OK要么一个也连接不上
  • Redis索引都是从零开始
  • 为什么默认端口是6379 (有个窍门,Redis端口号6379是电话键盘上的MERZ)

三、Redis常用数据类型

Ⅰ-Redis的五大数据类型

  • String(字符串)

string是redis最基本的类型,你可以理解成与Memcached一模一样的类型,一个key对应一个value。
string类型是二进制安全的。意思是redis的string可以包含任何数据。比如jpg图片或者序列化的对象 。
string类型是Redis最基本的数据类型,一个redis中字符串value最多可以是512M

  • Hash(哈希,类似java里的Map)

Redis hash 是一个键值对集合。 Redis
hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。
类似Java里面的Map<String,Object>

  • List(列表)

Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素导列表的头部(左边)或者尾部(右边)
它的底层实际是个链表

  • Set(集合)

Redis的Set是string类型的无序集合。它是通过HashTable实现实现的

  • Zset(sorted set:有序集合)

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

  • 哪里去获得redis常见数据类型操作命令

Redis 命令参考
Redis 官网命令参考

Ⅱ-Key关键字

常用的

案例

  • keys
  • exists key的名字,判断某个key是否存在
  • move key db —>当前库就没有了,被移除了
  • expire key 秒钟:为给定的key设置过期时间
  • ttl key 查看还有多少秒过期,-1表示永不过期,-2表示已过期
  • type key 查看你的key是什么类型

Ⅲ-String

单值单value

常用

案例

  • set/get/del/append/strlen(末尾添加、求长度)
  • Incr/decr/incrby/decrby(+1、-1、+n、-n),一定要是数字才能进行加减)
  • getrange/setrange (返回/设置从start-end之间的内容 注意下表从0开始计数)
  • setex(set with expire)( 创建keyValue的时候并设置过期时间,动态设置)
  • setnx(set if not exist)( 只有在 key 不存在时设置 key 的值。)
  • mset/mget/msetnx( 同时设置/获取一个或多个 key-value 对。)
  • getset(先get再set)

Ⅳ-List

单值多value

常用

案例

  • lpush/rpush/lrange (lrange key 0 -1 表示获取所有的元素)
# 左边的LPUSH 正着进反着出;右边RPUSH怎么进就怎么出
127.0.0.1:6379> LPUSH list01 1 2 3 4 5
(integer) 5
127.0.0.1:6379> keys *
1) "k3"
2) "list01"
3) "k2"
4) "k1"
127.0.0.1:6379> LRANGE list01 0 -1
1) "5"
2) "4"
3) "3"
4) "2"
5) "1"
127.0.0.1:6379> RPUSH list02 1 2 3 4 5
(integer) 5
127.0.0.1:6379> LRANGE list02 0 -1
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"

  • lpop/rpop
  • lindex,按照索引下标获得元素(从上到下)
127.0.0.1:6379> LPOP list01
"5"
127.0.0.1:6379> LPOP list02
"1"
127.0.0.1:6379> lindex list01 0 #上面list01中最上面的5已经出了
"4"
127.0.0.1:6379> lindex list02 0 #上面list02中最上面的1已经出了
"2"
127.0.0.1:6379>
  • llen
  • lrem key 删N个value (rem->remove 有可能有多个key的value是相同的,删除N个值为value)
  • ltrim key 开始index 结束index,截取指定范围的值后再赋值给key
  • rpoplpush 源列表 目的列表
  • lset key index value 修改指定下班下的值
  • linsert key before/after 值1 值2

    性能总结:
  • 它是一个字符串链表,left、right都可以插入添加;
  • 如果键不存在,创建新的链表;
  • 如果键已存在,新增内容;
  • 如果值全移除,对应的键也就消失了。
  • 链表的操作无论是头和尾效率都极高,但假如是对中间元素进行操作,效率就很惨淡了。

Ⅴ-Set

单值多value

常用

案例

  1. sadd/smembers/sismember
  2. scard,获取集合里面的元素个数
  3. srem key value 删除集合中元素
  4. srandmember key 某个整数(随机出几个数)
  5. spop key 随机出栈
  6. smove key1 key2 在key1里某个值 作用是将key1里的某个值赋给key2
  7. 数学集合类

差集:sdiff
交集:sinter
并集:sunion

127.0.0.1:6379> SMEMBERS set01
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
127.0.0.1:6379> SMEMBERS set02
1) "2"
2) "1"
3) "c"
4) "e"
5) "a"
6) "b"
7) "d"
8) "f"
9) "5"
127.0.0.1:6379> sdiff set01 set02
1) "3"
2) "4"
127.0.0.1:6379> SINTER set01 set02
1) "1"
2) "2"
3) "5"
127.0.0.1:6379> SUNION set01 set02
 1) "1"
 2) "3"
 3) "a"
 4) "f"
 5) "d"
 6) "b"
 7) "2"
 8) "c"
 9) "e"
10) "4"
11) "5"
127.0.0.1:6379>

Ⅵ-Hash

KV模式不变,但V是一个键值对 (类比于key-(HashMap)Value)

常用
案例

  • hset/hget/hmset/hmget/hgetall/hdel(几乎天天用的)
127.0.0.1:6379> hset user id 11  #这里key是user value是 id 11
(integer) 1
127.0.0.1:6379> hget user id
"11"
127.0.0.1:6379> hset user name z3
(integer) 1
127.0.0.1:6379> hget user name
"z3"
127.0.0.1:6379> hmset customer id 11 name lisi age 26 #一次性添加多个
OK
127.0.0.1:6379> hmget customer id name age #一次性获取多个,被获取之后的数据依旧存在
1) "11"
2) "lisi"
3) "26"
127.0.0.1:6379> HGETALL customer  #获取所有的value(这里的value就已经包括了key-value)
1) "id"
2) "11"
3) "name"
4) "lisi"
5) "age"
6) "26"
  • hlen
  • hexists key 在key里面的某个值的key
127.0.0.1:6379> hdel user name
(integer) 1
127.0.0.1:6379> hlen user
(integer) 1
127.0.0.1:6379> hlen customer
(integer) 3
127.0.0.1:6379> HEXISTS user id
(integer) 1
127.0.0.1:6379> HEXISTS user email
  • hkeys/hvals
127.0.0.1:6379> hkeys customer
1) "id"
2) "name"
3) "age"
127.0.0.1:6379> hvals customer
1) "11"
2) "lisi"
3) "26"
  • hincrby/hincrbyfloat
  • hsetnx
127.0.0.1:6379> HINCRBY customer age 3
(integer) 29
127.0.0.1:6379> HINCRBY customer age 3 #添加 key对应的key-value中的value的值
(integer) 32
127.0.0.1:6379> hset customer score 91.5
(integer) 1
127.0.0.1:6379> HINCRBYFLOAT customer score 0.6 #添加 key对应的key-value中的value的值
"92.1"
127.0.0.1:6379> HSETNX customer age 22
(integer) 0
127.0.0.1:6379> HSETNX customer email abc@qq.com
(integer) 1

Ⅶ-ZSet

在set基础上,加一个score值。 之前set是k1 v1 v2 v3, 现在zset是k1 score1 v1 score2 v2 (score1 v1就是一个键值对)

常用

案例

  • zadd/zrange

Withscores

  • zrangebyscore key 开始score 结束score

1.withscores
2.( 不包含
3.Limit 作用是返回限制

limit 开始下标步 多少步

  • zrem key 某score下对应的value值,作用是删除元素
  • zcard/zcount key score区间/zrank key values值,作用是获得下标值/zscore key对应值,获得分数
  • zrevrank key values值,作用是逆序获得下标值
  • zrevrange
  • zrevrangebyscore key 结束score 开始score
127.0.0.1:6379> ZCARD zset01  #统计个数
(integer) 4
127.0.0.1:6379> zcount zset01 60 80 #统计[60,80]之间的个数
(integer) 3
127.0.0.1:6379> ZRANK zset01 v4 #获取对应的下标
(integer) 3
127.0.0.1:6379> zscore zset01 v4 #返回分数
"90"
127.0.0.1:6379> ZREVRANK zset01 v4 #作用是逆序获得下标值
(integer) 0
127.0.0.1:6379> ZREVRANGE zset01 0 -1#分数从高到低
1) "v4"
2) "v3"
3) "v2"
4) "v1"
127.0.0.1:6379> ZRANGE zset01 0 -1 #分数从低到高
1) "v1"
2) "v2"
3) "v3"
4) "v4"
127.0.0.1:6379> ZREVRANGEBYSCORE zset01 90 60 #分数从高到低的截取区间[90,60]
1) "v4"
2) "v3"
3) "v2"
4) "v1"
127.0.0.1:6379> zadd zset01 60 coderxz
(integer) 1
127.0.0.1:6379> ZRANGE zset01 0 -1 withscores #存在score相同的好像也可以
 1) "coderxz"
 2) "60"
 3) "v1"
 4) "60"
 5) "v2"
 6) "70"
 7) "v3"
 8) "80"
 9) "v4"
10) "90"

四、配置文件介绍

Redis 的配置文件位于 Redis 安装目录下,文件名为 redis.conf(Windows 名为 redis.windows.conf)。

你可以通过 CONFIG 命令查看或设置配置项。

语法

Redis CONFIG 命令格式如下:

redis 127.0.0.1:6379> CONFIG GET CONFIG_SETTING_NAME

实例

redis 127.0.0.1:6379> CONFIG GET loglevel1) "loglevel"2) "notice"

参数说明
redis.conf 配置项说明如下:

--------------redis.conf中GENERAL的部分配置:--------------------

  • daemonize no

Redis 默认不是以守护进程的方式运行,可以通过该配置项修改,使用 yes 启用守护进程(Windows 不支持守护线程的配置为 no )

  • pidfile /var/run/redis.pid

当 Redis 以守护进程方式运行时,Redis 默认会把 pid 写入 /var/run/redis.pid 文件,可以通过 pidfile 指定

  • port 6379

指定 Redis 监听端口,默认端口为 6379,作者在自己的一篇博文中解释了为什么选用 6379 作为默认端口,因为 6379 在手机按键上 MERZ 对应的号码,而 MERZ 取自意大利歌女 Alessia Merz 的名字

  • bind 127.0.0.1

绑定的主机地址

  • timeout 300

当客户端闲置多长秒后关闭连接,如果指定为 0 ,表示关闭该功能

  • loglevel notice

指定日志记录级别,Redis 总共支持四个级别:debug、verbose、notice、warning,默认为 notice

  • logfile stdout

日志记录方式,默认为标准输出,如果配置 Redis 为守护进程方式运行,而这里又配置为日志记录方式为标准输出,则日志将会发送给 /dev/null

  • databases 16

设置数据库的数量,默认数据库为0,可以使用SELECT 命令在连接上指定数据库id

-------------redis.conf的SNAPSHOTTING快照配置------------------------

  • save < seconds> < changes>

Redis 默认配置文件中提供了三个条件(以下三者出其一就会触发):

save 900 1 900秒以内有1次修改

save 300 10

save 60 10000

分别表示 900 秒(15 分钟)内有 1 个更改,300 秒(5 分钟)内有 10 个更改以及 60 秒内有 10000 个更改。

指定在多长时间内,有多少次更新操作,就将数据同步到数据文件,可以多个条件配合

  • rdbcompression yes

指定存储至本地数据库时是否压缩数据,默认为 yes,Redis 采用 LZF 压缩,如果为了节省 CPU 时间,可以关闭该选项,但会导致数据库文件变的巨大

  • dbfilename dump.rdb

指定本地数据库文件名,默认值为 dump.rdb

  • dir ./

指定本地数据库存放目录

  • slaveof < masterip> < masterport>

设置当本机为 slave 服务时,设置 master 服务的 IP 地址及端口,在 Redis 启动时,它会自动从 master 进行数据同步

  • masterauth < master-password>

当 master 服务设置了密码保护时,slav 服务连接 master 的密码

-----------------redis.conf的SECURITY部分配置------------------------

  • requirepass foobared

设置 Redis 连接密码,如果配置了连接密码,客户端在连接 Redis 时需要通过 AUTH 命令提供密码,默认关闭

-----------------redis.conf中LIMITS的部分配置------------------

- maxclients 128

设置同一时间最大客户端连接数,默认无限制,Redis 可以同时打开的客户端连接数为 Redis 进程可以打开的最大文件描述符数,如果设置 maxclients 0,表示不作限制。当客户端连接数到达限制时,Redis 会关闭新的连接并向客户端返回 max number of clients reached 错误信息

- maxmemory < bytes>

指定 Redis 最大内存限制,Redis 在启动时会把数据加载到内存中,达到最大内存后,Redis 会先尝试清除已到期或即将到期的 Key,当此方法处理 后,仍然到达最大内存设置,将无法再进行写入操作,但仍然可以进行读取操作。Redis 新的 vm 机制,会把 Key 存放内存,Value 会存放在 swap 区

  • Maxmemory-policy noeviction(默认) 缓存清除策略,生产环境上肯定得改

(1)volatile-lru:使用LRU算法移除key,只对设置了过期时间的键 (最近最少使用)
(2)allkeys-lru:使用LRU算法移除key
(3)volatile-random:在过期集合中移除随机的key,只对设置了过期时间的键
(4)allkeys-random:移除随机的key
(5)volatile-ttl:移除那些TTL值最小的key,即那些最近要过期的key
(6)noeviction:不进行移除。针对写操作,只是返回错误信息

--------------redis.conf中 APPEND ONLY MODE的部分配置-----------

  • appendonly no

AOF启动,指定是否在每次更新操作后进行日志记录,Redis 在默认情况下是异步的把数据写入磁盘,如果不开启,可能会在断电时导致一段时间内的数据丢失。因为 redis 本身同步数据文件是按上面 save 条件来同步的,所以有的数据会在一段时间内只存在于内存中。默认为 no

  • appendfilename appendonly.aof

指定更新日志文件名,默认为 appendonly.aof

  • appendfsync everysec

指定更新日志条件,共有 3 个可选值:

no:表示等操作系统进行数据缓存同步到磁盘(快)

always:表示每次更新操作后手动调用 fsync() 将数据写到磁盘(慢,安全)

everysec:表示每秒同步一次(折中,默认值)

  • vm-enabled no

指定是否启用虚拟内存机制,默认值为 no,简单的介绍一下,VM 机制将数据分页存放,由 Redis 将访问量较少的页即冷数据 swap 到磁盘上,访问多的页面由磁盘自动换出到内存中(在后面的文章我会仔细分析 Redis 的 VM 机制)

- vm-swap-file /tmp/redis.swap

虚拟内存文件路径,默认值为 /tmp/redis.swap,不可多个 Redis 实例共享

  • vm-max-memory 0

将所有大于 vm-max-memory 的数据存入虚拟内存,无论 vm-max-memory 设置多小,所有索引数据都是内存存储的(Redis 的索引数据 就是 keys),也就是说,当 vm-max-memory 设置为 0 的时候,其实是所有 value 都存在于磁盘。默认值为 0

  • vm-page-size 32

Redis swap 文件分成了很多的 page,一个对象可以保存在多个 page 上面,但一个 page 上不能被多个对象共享,vm-page-size 是要根据存储的 数据大小来设定的,作者建议如果存储很多小对象,page 大小最好设置为 32 或者 64bytes;如果存储很大大对象,则可以使用更大的 page,如果不确定,就使用默认值

  • vm-pages 134217728

设置 swap 文件中的 page 数量,由于页表(一种表示页面空闲或使用的 bitmap)是在放在内存中的,,在磁盘上每 8 个 pages 将消耗 1byte 的内存。

  • vm-max-threads 4

设置访问swap文件的线程数,最好不要超过机器的核数,如果设置为0,那么所有对swap文件的操作都是串行的,可能会造成比较长时间的延迟。默认值为4

  • glueoutputbuf yes

设置在向客户端应答时,是否把较小的包合并为一个包发送,默认为开启

hash-max-zipmap-entries 64

hash-max-zipmap-value 512

指定在超过一定的数量或者最大的元素超过某一临界值时,采用一种特殊的哈希算法

  • activerehashing yes

指定是否激活重置哈希,默认为开启(后面在介绍 Redis 的哈希算法时具体介绍)

  • include /path/to/local.conf

指定包含其它的配置文件,可以在同一主机上多个Redis实例之间使用同一份配置文件,而同时各个实例又拥有自己的特定配置文件

五、Redis的持久化

Ⅰ-持久化之RDB

RDB(Redis DataBase)

1.是什么

  • 在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的Snapshot快照,它恢复时是将快照文件直接读到内存里
  • Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到
    一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。
    整个过程中,主进程是不进行任何IO操作的(类似于垃圾回收中的STW),这就确保了极高的性能。如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失。
  • rdb 保存的是dump.rdb文件
  • 相关配置在配置文件的位置 - 在redis.conf搜寻### SNAPSHOTTING ###

2.如何触发RDB快照

  • 配置文件中默认的快照配置redis.conf中 dbfilename dump.rdb 也就是说它只会这个文件

冷拷贝后重新使用
可以cp dump.rdb dump_new.rdb 主机和备份机是不同的

  • 立即进行备份命令save或者是bgsave

Save:save时只管保存,其它不管,全部阻塞
BGSAVE:Redis会在后台异步进行快照操作,
快照同时还可以响应客户端请求。可以通过lastsave 命令获取最后一次成功执行快照的时间

  • 执行FLUSHALL命令,也会产生dump.rdb文件,但里面是空的,无意义

3.如何恢复

  • 将备份文件 (dump.rdb) 移动到 redis 安装目录并启动服务即可 (redis重新启动的时候会自动读取dump.rdb去恢复)
  • CONFIG GET dir获取目录

4.优势与劣势

优势

适合大规模的数据恢复
对数据完整性和一致性要求不高

劣势

在一定间隔时间做一次备份,所以如果redis意外down掉的话,就会丢失最后一次快照后的所有修改(因为保存一次有时间间隔)
Fork的时候,内存中的数据被克隆了一份,大致2倍的膨胀性需要考虑

5.如何停止
动态所有停止RDB保存规则的方法:redis-cli config set save

6.小结

  • RDB是一个非常紧凑的文件
  • RDB在保存RDB文件时父进程唯一需要做的就是fork出一个子进程,接下来的工作全部由子进程来做,父进程不需要再做其他I0操作,所以RDB持久化方式可以最大化redis的性能。
  • 与AOF相比,在恢复大的数据集的时候,RDB方式会更快一一些。
  • 数据丢失风险大。
  • RDB需要经常fork子进程来保存数据集到硬盘上,当数据集比较大的时候fork的过程是非常耗时的,可能会导致Redis在一些毫秒级不能回应客户端请求。

Ⅱ-持久化之AOF

AOF(Append Only File)

在Redis重启的时候;AOF和dump同时存在的时候,先找谁?

先找AOF文件,如果AOF有问题,Redis是启动不了的。

1.是什么
以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来(读操作不记录), 只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis 重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作

2.AOF配置
相关配置在配置文件的位置 - 在redis.conf搜寻### APPEND ONLY MODE ###
aof保存的是appendonly.aof文件(在配置文件可修改文件名)

3.AOF启动/修复/恢复

- 正常恢复

启动:设置Yes

修改默认的appendonly no,改为yes
将有数据的aof文件复制一份保存到对应目录(config get dir)

恢复:重启redis然后重新加载 (注意:如果之前最后的命令有FLASHALL,得先手动删除,不然FLASHALL也会被再次执行一次,那就又没得了)

- 异常恢复(如果aof文件有问题怎么办?因为先找的是aof)

启动:设置Yes

修改默认的appendonly no,改为yes
备份被写坏的AOF文件

修复

Redis-check-aof --fix appendonly.aof 会把不符合语法的都删掉,自动修复aof文件

(比如网络通信会丢包文件有损失)Redis-check-dump–fix文件是一样的

恢复:重启redis然后重新加载

4.rewrite

  • 是什么:

AOF采用文件追加方式,文件会越来越大。为避免出现此种情况,新增了重写机制, 当AOF文件的大小超过所设定的阈值时,Redis就会启动AOF文件的内容压缩, 只保留可以恢复数据的最小指令集。可以使用命令bgrewriteaof

  • 重写原理

AOF文件持续增长而过大时,会fork出一条新进程来将文件重写(也是先写临时文件最后再rename), 遍历新进程的内存中数据,每条记录有一条的Set语句。重写aof文件的操作,并没有读取旧的aof文件, 而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,这点和快照有点类似

  • 触发机制

Redis会记录上次重写时的AOF大小,默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发 (在redis.conf中的auto-aof-rewrite-min-size 64mb配置)

5.优势与劣势

优势

每修改同步:appendfsync always 同步持久化 每次发生数据变更会被立即记录到磁盘 性能较差但数据 完整性比较好
每秒同步:appendfsync everysec 异步操作,每秒记录 如果一秒内宕机,有数据丢失
不同步:appendfsync no 从不同步

劣势

相同数据集的数据而言aof文件要远大于rdb文件,恢复速度慢于rdb
Aof运行效率要慢于rdb,每秒同步策略效率较好,不同步效率和rdb相同

6.小结

  • AOF文件时一个只进行追加的日志文件
  • Redis可以在AOF文件体积变得过大时,自动地在后台对AOF进行重写
  • AOF文件有序地保存了对数据库执行的所有写入操作,这些写入操作以Redis协议的格式保存,因此AOF文件的内容非常容易被人读懂,对文件进行分析也很轻松
  • 对于相同的数据集来说,AOF文件的体积通常要大于RDB文件的体积
  • 根据所使用的fsync 策略,AOF的速度可能会慢于RDB

Ⅲ-总结

1.官网建议

  • RDB持久化方式能够在指定的时间间隔能对你的数据进行快照存储
  • AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以redis协议追加保存每次写的操作到文件末尾.
  • Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大
  • 我只是做缓存:如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化方式.

2.同时开启两种

  • 在这种情况下,当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整.
  • RDB的数据不实时,同时使用两者时服务器重启也只会找AOF文件。那要不要只使用AOF呢?作者建议不要,因为RDB更适合用于备份数据库(AOF在不断变化不好备份),快速重启,而且不会有AOF可能潜在的bug,留着作为一个万一的手段。

3.性能建议

因为RDB文件只用作后备用途,建议只在Slave上持久化RDB文件,而且只要15分钟备份一次就够了,只保留save 900 1这条规则。

如果Enalbe AOF,好处是在最恶劣情况下也只会丢失不超过两秒数据,启动脚本较简单只load自己的AOF文件就可以了。代价一是带来了持续的IO,二是AOF rewrite的最后将rewrite过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的。只要硬盘许可,应该尽量减少AOF rewrite的频率,AOF重写的基础大小默认值64M太小了,可以设到5G以上。默认超过原大小100%大小时重写可以改到适当的数值。

如果不Enable AOF ,仅靠Master-Slave Replication 实现高可用性也可以。能省掉一大笔IO也减少了rewrite时带来的系统波动。代价是如果Master/Slave同时倒掉,会丢失十几分钟的数据,启动脚本也要比较两个Master/Slave中的RDB文件,载入较新的那个。新浪微博就选用了这种架构

六、Redis事务

事务官方文档

1.是什么

可以一次执行多个命令,本质是一组命令的集合。一个事务中的所有命令都会序列化,按顺序地串行化执行而不会被其它命令插入,不许加塞。

2.能干嘛

一个队列中,一次性、顺序性、排他性的执行一系列命令。

3.怎么玩

1)常用命令

2)正常执行
MULTI & EXEC

3)放弃事务
MULTI & discard

4)全体连坐
MULTI & 执行的redis质量有错误 & exec 类似于语法错误 类似Java编译异常

5)冤头债主
类似于语义执行的有问题 这个没有直接报错 类似Java运行异常

没有强一致性,把对的放行,语义执行错误的就执行失败。

以上是关于Redis泛泛而谈(详细3W字)的主要内容,如果未能解决你的问题,请参考以下文章

3w字深度好文|Redis面试全攻略,读完这个就可以和面试官大战几个回合了

指针的这些知识你知道吗?C语言超硬核指针进阶版3w+字详解+指针笔试题画图+文字详细讲解

熬夜肝出 3w 字测试开发学习路线

3W+字长文深度总结|程序员面试题精华版集合(内附思维导图)!

7000字 Redis 超详细总结笔记总 | 收藏必备!

3W字详解Hadoop知识点(建议收藏)