redis背景

  • 概述
  • Windows安装
  • Linux安装
  • 基础知识说明
  • 五大数据类型
  • Redis键(key)
  • 字符串String


概述

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能干嘛

内存存储和持久化:redis支持异步将内存中的数据写到硬盘上,同时不影响继续服务
取最新N个数据的操作,如:可以将最新的10条评论的ID放在Redis的List集合里面
发布、订阅消息系统
地图信息分析
定时器、计数器

特性

数据类型、基本操作和配置
持久化和复制,RDB、AOF
事务的控制

常用网站

https://redis.io/官网
http://www.redis.cn 中文网

Windows安装

下载地址:https://github.com/dmajkic/redis/downloads ( 素材提供 )

解压到自己电脑的环境目录即可

![在这里插入图片描述](

Redis daemonize在容器内需要启动吗_redis

双击 redis-server.exe 启动即可

Redis daemonize在容器内需要启动吗_数据库_02


通过客户端去访问 redis-cli

# 测试基本的set设值
127.0.0.1:6379> set name zhangsan
OK
# 取出存储的值
127.0.0.1:6379> get name
"zhangsan"
127.0.0.1:6379>

重要提示

根据官网的介绍,推荐使用linux部署。http://www.redis.cn/topics/introduction

Redis daemonize在容器内需要启动吗_数据_03

Linux安装

下载地址 https://download.redis.io/releases/redis-6.0.6.tar.gz

Redis daemonize在容器内需要启动吗_数据_04

安装步骤

Redis daemonize在容器内需要启动吗_缓存_05

启动

修改daemonize 属性为yes ,默认为no

Redis daemonize在容器内需要启动吗_缓存_06

  • A、redis.conf配置文件中daemonize守护线程,默认是NO。
  • B、daemonize是用来指定redis是否要用守护线程的方式启动。

daemonize 设置yes或者no区别

  • daemonize:yes
    redis采用的是单进程多线程的模式。当redis.conf中选项daemonize设置成yes时,代表开启
    守护进程模式。在该模式下,redis会在后台运行,并将进程pid号写入至redis.conf选项
    pidfile设置的文件中,此时redis将一直运行,除非手动kill该进程
  • daemonize:no
    当daemonize选项设置成no时,当前界面将进入redis的命令行界面,exit强制退出或者关闭
    连接工具(putty,xshell等)都会导致redis进程退出。

启动测试一下!

# 【shell】启动redis服务 
[root@192 bin]# cd /usr/local/bin 
[root@192 bin]# redis-server /opt/redis-5.0.7/redis.conf 
# redis客户端连接===> 观察地址的变化,如果连接ok,是直接连上的,redis默认端口号 6379
[root@192 bin]# redis-cli -p 6379 
127.0.0.1:6379> ping PONG 
127.0.0.1:6379> set k1 helloworld OK
127.0.0.1:6379> get k1 "helloworld" 
# 【shell】ps显示系统当前进程信息 
[root@192 myredis]# ps -ef|grep redis 
root 16005 1 0 04:45 ? 00:00:00 redis-server 
127.0.0.1:6379 
root 16031 15692 0 04:47 pts/0 00:00:00 redis-cli -p 6379 
root 16107 16076 0 04:51 pts/2 00:00:00 grep --color=auto redis
# 【redis】关闭连接 
127.0.0.1:6379> shutdown 
not connected> exit
# 【shell】ps显示系统当前进程信息
[root@192 myredis]# ps -ef|grep redis 
root 16140 16076 0 04:53 pts/2 00:00:00 grep --color=auto redis

基础知识说明

redis压力测试工具-----Redis-benchmark

Redis-benchmark是官方自带的Redis性能测试工具,可以有效的测试Redis服务的性能。

Redis daemonize在容器内需要启动吗_Redis_07

redis 性能测试工具可选参数如下所示:

序号

选项

描述

描述

1

-h

指定服务器主机名

127.0.0.1

2

-p

指定服务器端口

6379

3

-s

指定服务器 socket

4

-c

指定并发连接数

50

5

-n

指定请求数

10000

6

-d

以字节的形式指定 SET/GET 值的数据大小

2

7

-k

1=keep alive 0=reconnect

1

8

-r

SET/GET/INCR 使用随机 key, SADD 使用随机值

9

-P

通过管道传输 请求

1

10

-q

强制退出 redis。仅显示 query/sec 值

11

–csv

以 CSV 格式输出

12

-l

生成循环,永久执行测试

13

-t

仅运行以逗号分隔的测试命令列表。

14

-I

Idle 模式。仅打开 N 个 idle 连接并等待

# 测试一:100个并发连接,100000个请求,检测host为localhost 端口为6379的redis服务器性能
redis-benchmark -h localhost -p 6379 -c 100 -n 100000
# 测试出来的所有命令只举例一个!
====== SET ======
100000 requests completed in 1.88 seconds # 对集合写入测试
100 parallel clients # 每次请求有100个并发客户端
3 bytes payload # 每次写入3个字节的数据,有效载荷
keep alive: 1 # 保持一个连接,一台服务器来处理这些请求

17.05% <= 1 milliseconds
97.35% <= 2 milliseconds
99.97% <= 3 milliseconds
100.00% <= 3 milliseconds # 所有请求在 3 毫秒内完成
53248.14 requests per second # 每秒处理 53248.14 次请求

基本数据库常识

1、默认16个数据库,类似数组下标从零开始,初始默认使用零号库

查看 redis.conf ,里面有默认的配置
databases 16

# Set the number of databases. The default database is DB 0, you can select
# a different one on a per-connection basis using SELECT <dbid> where
# dbid is a number between 0 and 'databases'-1
databases 16

2、Select命令切换数据库

127.0.0.1:6379> Select 1
OK
127.0.0.1:6379[1]>

3、Dbsize查看当前数据库的key的数量

127.0.0.1:6379[1]> dbsize
(integer) 0

4、Flushdb:清空当前库
5、Flushall:清空全部的库

为什么redis是单线程

我们首先要明白,Redis很快!官方表示,因为Redis是基于内存的操作,CPU不是Redis的瓶颈,Redis
的瓶颈最有可能是机器内存的大小或者网络带宽。既然单线程容易实现,而且CPU不会成为瓶颈,那就
顺理成章地采用单线程的方案了!

Redis采用的是基于内存的采用的是单进程单线程模型的 KV 数据库,由C语言编写,官方提供的数据是
可以达到100000+的QPS(每秒内查询次数)。这个数据不比采用单进程多线程的同样基于内存的 KV
数据库 Memcached 差!

Redis为什么这么快?

1)以前一直有个误区,以为:高性能服务器 一定是多线程来实现的
原因很简单因为误区二导致的:多线程 一定比 单线程 效率高,其实不然!
在说这个事前希望大家都能对 CPU 、 内存 、 硬盘的速度都有了解了!
2)redis 核心就是 如果我的数据全都在内存里,我单线程的去操作 就是效率最高的,为什么呢,因为
多线程的本质就是 CPU 模拟出来多个线程的情况,这种模拟出来的情况就有一个代价,就是上下文的切
换,对于一个内存的系统来说,它没有上下文的切换就是效率最高的。redis 用 单个CPU 绑定一块内存
的数据,然后针对这块内存的数据进行多次读写的时候,都是在一个CPU上完成的,所以它是单线程处
理这个事。在内存的情况下,这个方案就是最佳方案。
因为一次CPU上下文的切换大概在 1500ns 左右。从内存中读取 1MB 的连续数据,耗时大约为 250us,
假设1MB的数据由多个线程读取了1000次,那么就有1000次时间上下文的切换,那么就有1500ns *
1000 = 1500us ,我单线程的读完1MB数据才250us ,你光时间上下文的切换就用了1500us了,我还不
算你每次读一点数据 的时间。

五大数据类型

官方文档

Redis daemonize在容器内需要启动吗_Redis_08

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键(key)

127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> set name zhangsan
OK
127.0.0.1:6379> get name
"zhangsan"
127.0.0.1:6379> keys *
1) "name"
# exists key 判断key是否存在,1表示存在,0表示不存在
127.0.0.1:6379> exists name
(integer) 1
127.0.0.1:6379> exists name1
(integer) 0

127.0.0.1:6379> set name zhangsan
OK
127.0.0.1:6379> set age 18
OK
127.0.0.1:6379> keys *
1) "age"
2) "name"
# 移动Move 命令用于将当前 Redis 数据库的 KEY 移动到给定的数据库 db 当中。
# 如果当前数据库(源数据库)和给定数据库(目标数据库)有相同名字的给定 KEY ,或者 KEY 不存在于当前数据库,那么 MOVE 没有任何效果。
127.0.0.1:6379> move name 1
(integer) 1
127.0.0.1:6379> keys *
1) "age"
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> keys *
1) "name"
# 目标数据库中存在,move没有任何效果
127.0.0.1:6379> move name 1
(integer) 0


# expire key 秒钟:为给定 key 设置生存时间,当 key 过期时(生存时间为 0 ),它会被自动删 除。
# ttl key 查看还有多少秒过期,-1 表示永不过期,-2 表示已过期
127.0.0.1:6379> set name zhangsan
OK
127.0.0.1:6379> expire name 20
(integer) 1
127.0.0.1:6379> ttl name
(integer) 17
127.0.0.1:6379> ttl name
(integer) 15
127.0.0.1:6379> ttl name
(integer) 12
127.0.0.1:6379> ttl name
(integer) 10
127.0.0.1:6379> ttl name
(integer) 8
127.0.0.1:6379> ttl name
(integer) -2
127.0.0.1:6379>

# type key 查看你的key是什么类型
127.0.0.1:6379> set age 18
OK
127.0.0.1:6379> type age
string

字符串String

常用命令说明

# =================================================== 
# set(设置值)、get(获取值)、del(删除值)、append(追加值)、strlen(字符串长度) 
# ===================================================
127.0.0.1:6379> set name zhangsan  # 设置值
OK
127.0.0.1:6379> get name # 获取值
"zhangsan"
127.0.0.1:6379> del name # 删除值
(integer) 1
127.0.0.1:6379> keys * # 查看列表是否存在
(empty list or set)
127.0.0.1:6379> exists name # 通过exists查看是否存在
(integer) 0
127.0.0.1:6379> append name hello #对不存在的 key 进行 APPEND ,等同于 SET
(integer) 5
127.0.0.1:6379> append name Word  # 对已存在的字符串进行 APPEND
(integer) 9
127.0.0.1:6379> get name # 查看最终值
"helloWord"
127.0.0.1:6379> strlen name # 获取字符串长度
(integer) 9
127.0.0.1:6379>


# =================================================== 
# incr、decr 一定要是数字才能进行加减,+1 和 -1。 
# incrby、decrby 命令将 key 中储存的数字加上指定的增量值。 
# ===================================================
127.0.0.1:6379> set views 0   #设置初始值,值为数字类型
OK
127.0.0.1:6379> incr views    #incr累加1
(integer) 1
127.0.0.1:6379> incr views   #incr累加1
(integer) 2
127.0.0.1:6379> decr views    #decr累减1
(integer) 1
127.0.0.1:6379> decr views    # decr累减1
(integer) 0
127.0.0.1:6379> incrby views 10   #指定添加多少值
(integer) 10
127.0.0.1:6379> decrby views 5    #指定减少多少值
(integer) 5
127.0.0.1:6379> get views     #查看最终值
"5"
127.0.0.1:6379>

# =================================================== 
# range [范围] 
# getrange 获取指定区间范围内的值,类似between...and的关系,从零到负一表示全部 
# ===================================================
127.0.0.1:6379> set name helloword
OK
127.0.0.1:6379> get name
"helloword"
127.0.0.1:6379> getrange name 0 1
"he"
127.0.0.1:6379> getrange name 0 -1
"helloword"
127.0.0.1:6379>

# =================================================== 
# setrange 设置指定区间范围内的值,格式是setrange key值 开始替换的索引位置值[offset] 具体值 
# ===================================================
127.0.0.1:6379> get name #查看name值
"helloword"
127.0.0.1:6379> setrange name 0 H  #替换索引位置为0的字符为H
(integer) 9
127.0.0.1:6379> get name #查看
"Helloword"
127.0.0.1:6379> setrange name 0 HELLOWORD #从索引为0开始替换,HELLOWORD
(integer) 9
127.0.0.1:6379> GET name
"HELLOWORD"
127.0.0.1:6379>

# =================================================== 
# setex(set with expire)键秒值  设置key的过期时间  setex key 过期时间 value
# setnx(set if not exist)  判断key是否存在并且设置值 1为成功,0为失败。失败表示有key存在了。
# ===================================================
127.0.0.1:6379> setex name 10 xiaowang  #设置name:xiaowang过期时间为10
OK
127.0.0.1:6379> get name  #查看设置值
"xiaowang"
127.0.0.1:6379> ttl name # 查看剩余过期时间
(integer) 7
127.0.0.1:6379> setnx age 18  #不存在age字段时设置
(integer) 1
127.0.0.1:6379> setnx age 19  #存在age字段时设置 
(integer) 0
127.0.0.1:6379> get age
"18"


# =================================================== 
# mset Mset 命令用于同时设置一个或多个 key-value 对。 
# mget Mget 命令返回所有(一个或多个)给定 key 的值。 
# 如果给定的 key 里面,有某个 key 不存在,那么这个 key 返回特殊值 nil 。 
# msetnx 当所有 key 都成功设置,返回 1 。 
# 如果所有给定 key 都设置失败(至少有一个 key 已经存在),那么返回 0 。原子操作
# ===================================================
127.0.0.1:6379> mset k1 v1 k2 v2  #批量添加
OK
127.0.0.1:6379> keys *  #查看
1) "k2"
2) "k1" 
127.0.0.1:6379> mget k1 k2  #批量获取
1) "v1"
2) "v2"
# msetnx如果所有给定 key 都设置失败(至少有一个 key 已经存在),那么返回 0 。原子操作
127.0.0.1:6379> msetnx k1 v1 k2 v2 k3 v3 #再次批量条件 具有原子性
(integer) 0
127.0.0.1:6379> mget k1 k2 k3
1) "v1"
2) "v2"
3) (nil)
# 获取k3为nul


# =================================================== 
# getset(先get再set) 
# ===================================================
127.0.0.1:6379> getset name zhangsan # 获取旧值设置新值,没有旧值返回为null
(nil)
127.0.0.1:6379> getset name lisi #获取旧值设置新值,有旧值返回zhangsan
"zhangsan"
127.0.0.1:6379> get name  #查看新值
"lisi"
127.0.0.1:6379>

String数据结构是简单的key-value类型,value其实不仅可以是String,也可以是数字。
常规key-value缓存应用:
常规计数:微博数,粉丝数等。