Redis是NoSQL中比较常典型的一个非关系型数据库,在日常工作中也是最为常见的。Redis是一个由C语言编写的开源的、遵守BSD协议、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
https://db-engines.com/en/ranking
一、安装及启动Redis
由于我们日常中最多使用redis的环境是在linux中,所以这里主要来看linux下的安装方法。
1、下载并安装Redis
我们可以使用wget下载,也可以将redis的包下载下来并且导入到linux中
$ wget http://download.redis.io/releases/redis-2.8.17.tar.gz
$ yum install gcc tcl -y
$ tar xzf redis-2.8.8.tar.gz
$ cd redis-4.0.8
$ make
$ mkdir /usr/local/redis
$ make install PREFIX=/usr/local/redis
2、启动redis
./redis-server
默认启动redis使用的是默认配置,端口号为6379,密码为空。如果需要后台启动的话,可以使用nohup来启动。
nohup redis-server &
当然,如果需要指定redis的配置文件,那我们可以在启动命令中指定好配置文件就可以。
nohup redis-server /usr/local/redis/redis.conf &
3、停止redis
redis-cli shutdown
4、redis配置
# Protected mode is a layer of security protection, in order to avoid that
# Redis instances left open on the internet are accessed and exploited.
#
# When protected mode is on and if:
#
# 1) The server is not binding explicitly to a set of addresses using the
# "bind" directive.
# 2) No password is configured.
#
# The server only accepts connections from clients connecting from the
# IPv4 and IPv6 loopback addresses 127.0.0.1 and ::1, and from Unix domain
# sockets.
#
# By default protected mode is enabled. You should disable it only if
# you are sure you want clients from other hosts to connect to Redis
# even if no authentication is configured, nor a specific set of interfaces
# are explicitly listed using the "bind" directive.
protected-mode yes
# Accept connections on the specified port, default is 6379 (IANA #815344).
# If port 0 is specified Redis will not listen on a TCP socket.
port 6379
# Unix socket.
#
# Specify the path for the Unix socket that will be used to listen for
# incoming connections. There is no default, so Redis will not listen
# on a unix socket when not specified.
#
# unixsocket /tmp/redis.sock
# unixsocketperm 700
# Close the connection after a client is idle for N seconds (0 to disable)
timeout 0
# TCP keepalive.
#
# If non-zero, use SO_KEEPALIVE to send TCP ACKs to clients in absence
# of communication. This is useful for two reasons:
#
# 1) Detect dead peers.
# 2) Take the connection alive from the point of view of network
# equipment in the middle.
#
# On Linux, the specified value (in seconds) is the period used to send ACKs.
# Note that to close the connection the double of the time is needed.
# On other kernels the period depends on the kernel configuration.
#
# A reasonable value for this option is 300 seconds, which is the new
# Redis default starting with Redis 3.2.1.
tcp-keepalive 300
# By default Redis does not run as a daemon. Use 'yes' if you need it.
# Redis默认不是以守护进程的方式运行,可以通过该配置项修改,使用yes启用守护进程
# Note that Redis will write a pid file in /var/run/redis.pid when daemonized.
# 启用守护进程后,Redis会把pid写到一个pidfile中,在/var/run/redis.pid
daemonize yes
# 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
################################ SNAPSHOTTING ################################
#
# Save the DB on disk:
#
# save <seconds> <changes>
#
# Will save the DB if both the given number of seconds and the given
# number of write operations against the DB occurred.
#
# In the example below the behaviour will be to save:
# after 900 sec (15 min) if at least 1 key changed
# after 300 sec (5 min) if at least 10 keys changed
# after 60 sec if at least 10000 keys changed
#
# Note: you can disable saving completely by commenting out all "save" lines.
#
# It is also possible to remove all the previously configured save
# points by adding a save directive with a single empty string argument
# like in the following example:
#
# save ""
save 900 1
save 300 10
save 60 10000
# Compress string objects using LZF when dump .rdb databases?
# For default that's set to 'yes' as it's almost always a win.
# If you want to save some CPU in the saving child set it to 'no' but
# the dataset will likely be bigger if you have compressible values or keys.
rdbcompression yes
# The filename where to dump the DB
dbfilename dump.rdb
# The working directory.
#
# The DB will be written inside this directory, with the filename specified
# above using the 'dbfilename' configuration directive.
#
# The Append Only File will also be created inside this directory.
#
# Note that you must specify a directory here, not a file name.
dir ./
5、连接redis
远程连接redis,可以使用redis自带的工具redis-cli,具体使用方法如下:
redis-cli -h 127.0.0.1 -p 6379 -n 0
-h <hostname> Server hostname (default: 127.0.0.1).
-p <port> Server port (default: 6379).
-a <password> Password to use when connecting to the server.
--help 显示帮助信息
切换数据库:
select 0
select 10
6、redis常用命令
Redis 是一个高性能的key-value数据库,和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set –有序集合)和hash(哈希类型)。不过既然redis是一个数据库,那么也就逃脱不开增删改查的操作,接下来把每种数据类型常用的增删改查命令列举一次。
如果对某个命令不知道该如何使用的时候可以使用–help来查询如:
help set
DEL key [key ...]
summary: Delete a key
since: 1.0.0
group: generic
KEYS pattern
summary: Find all keys matching the given pattern
since: 1.0.0
group: generic
RENAME key newkey
summary: Rename a key
since: 1.0.0
group: generic
MOVE key db
summary: Move a key to another database
since: 1.0.0
group: generic
EXPIRE key seconds
summary: Set a key's time to live in seconds
since: 1.0.0
group: generic
EXISTS key [key ...]
summary: Determine if a key exists
since: 1.0.0
group: generic
(1)String(字符串)
redis中最简单的数据类型,可以存储文字、数字、浮点数还可以进行二进制的存储,value存储最大数据量为512M。
APPEND
APPEND key value
summary: Append a value to a key
since: 2.0.0
group: string
在一个key的值后面追加上value内容
GET
GET key
summary: Get the value of a key
since: 1.0.0
group: string
获取key的值
GETRANGE
GETRANGE key start end
summary: Get a substring of the string stored at a key
since: 2.4.0
group: string
获取key值的切片 从start开始到end结束
GETSET
GETSET key value
summary: Set the string value of a key and return its old value
since: 1.0.0
group: string
将value作为key的值写入,并将key的旧值返回
INCR
INCR key
summary: Increment the integer value of a key by one
since: 1.0.0
group: string
给key的int值加1,如果这个key没有存在,则会先初始化一个0,然后再加1
INCRBY
INCRBY key increment
summary: Increment the integer value of a key by the given amount
since: 1.0.0
group: string
将 key所储存的值加上增量 increment,如果key的值不是int类型,则报错
MGET
MGET key [key ...]
summary: Get the values of all the given keys
since: 1.0.0
group: string
同时获取多个key
MSET
MSET key value [key value ...]
summary: Set multiple keys to multiple values
since: 1.0.1
group: string
同时写入多个key
MSETNX
MSETNX key value [key value ...]
summary: Set multiple keys to multiple values, only if none of the keys exist
since: 1.0.1
group: string
只有在key不存在的时候才可以同时写入多个key值
PSETEX
PSETEX key milliseconds value
summary: Set the value and expiration in milliseconds of a key
since: 2.6.0
group: string
写入一个值,但是只有设置的毫秒的有效期,超过后会被删除
SET
SET key value [EX seconds] [PX milliseconds] [NX|XX]
summary: Set the string value of a key
since: 1.0.0
group: string
写入一个值
SETEX
SETEX key seconds value
summary: Set the value and expiration of a key
since: 2.0.0
group: string
写入一个值,并且有设置的有效期
SETNX
SETNX key value
summary: Set the value of a key, only if the key does not exist
since: 1.0.0
group: string
将 key 的值设为value,当且仅当key不存在
SETRANGE
SETRANGE key offset value
summary: Overwrite part of a string at key starting at the specified offset
since: 2.2.0
group: string
用value参数覆写(overwrite)给定key所储存的字符串值,从偏移量offset开始。
STRLEN
STRLEN key
summary: Get the length of the value stored in a key
since: 2.2.0
group: string
返回key所储存的字符串值的长度。
(2)Hash(哈希)
hash 是一个string类型的field和value的映射表,hash特别适合用于存储对象。Redis 中每个 hash 可以存储 232 – 1 键值对(40多亿)。
HDEL
HDEL key field [field ...]
summary: Delete one or more hash fields
since: 2.0.0
group: hash
删除哈希表key中的一个或多个指定域,不存在的域将被忽略。
HEXISTS
HEXISTS key field
summary: Determine if a hash field exists
since: 2.0.0
group: hash
判断哈希表key中的field是否存在
HGET
HGET key field
summary: Get the value of a hash field
since: 2.0.0
group: hash
获取哈希表key中的field
HGETALL
HGETALL key
summary: Get all the fields and values in a hash
since: 2.0.0
group: hash
获取哈希表key中的所有域和值
HINCRBY
HINCRBY key field increment
summary: Increment the integer value of a hash field by the given number
since: 2.0.0
group: hash
为哈希表key中的域field的值加上增量increment。
HKEYS
HKEYS key
summary: Get all the fields in a hash
since: 2.0.0
group: hash
返回哈希表key中的所有域。
HLEN
HLEN key
summary: Get the number of fields in a hash
since: 2.0.0
group: hash
返回哈希表key中域的数量。
HMGET
HMGET key field [field ...]
summary: Get the values of all the given hash fields
since: 2.0.0
group: hash
返回哈希表key中,一个或多个给定域的值。
HMSET
HMSET key field value [field value ...]
summary: Set multiple hash fields to multiple values
since: 2.0.0
group: hash
同时将多个field-value(域-值)对设置到哈希表key中。
HSET
HSET key field value
summary: Set the string value of a hash field
since: 2.0.0
group: hash
将哈希表key中的域field的值设为value
HSETNX
HSETNX key field value
summary: Set the value of a hash field, only if the field does not exist
since: 2.0.0
group: hash
将哈希表key中的域field的值设置为value,当且仅当域field不存在。
HVALS
HVALS key
summary: Get all the values in a hash
since: 2.0.0
group: hash
返回哈希表key中所有的域
7、监控redis
图形化监控工具:TreeSoft
命令行监控:
- 吞吐量
- Redis提供的INFO命令不仅能够查看实时的吞吐量(ops/sec),还能看到一些有用的运行时信息。下面用grep过滤出一些比较重要的实时信息,比如已连接的和在阻塞的客户端、已用内存、拒绝连接、实时的tps和数据流量等:
[root@liml redis]# /usr/local/redis/redis-cli -h 127.0.0.1 -p 6380 -a 123456 info |
grep -e "connected_clients" -e "blocked_clients" -e "used_memory_human" -e "used_memory_peak_human" -e "rejected_connections" -e "evicted_keys" -e "instantaneous" connected_clients:3 #连接数 blocked_clients:0 #阻塞连接数 used_memory_human:3.37M # redis占用内存 used_memory_peak_human:3.37M #redis占用内存峰值 instantaneous_ops_per_sec:192 #每秒处理请求数 instantaneous_input_kbps:11.82 #每秒读字节数 instantaneous_output_kbps:0.75 #每秒写字节数 rejected_connections:0 #拒绝连接数 evicted_keys:0 #运行以来删除的key数量
- 吞吐量
- 延迟
- 监控redis的延迟可以使用redis提供的ping命令来不断的ping服务器,并且记录服务器响应ping的时间。
[root@liml ~]# /usr/local/redis/redis-cli -h 127.0.0.1 -p 6380 -a 123456 --latency min: 0, max: 1, avg: 0.08 (284 samples)
[root@liml ~]# /usr/local/redis/redis-cli -h 127.0.0.1 -p 6380 -a 123456
127.0.0.1:6380> monitor 1522663856.563254 [0 127.0.0.1:34881] "PING" 1522663856.573585 [0 127.0.0.1:34881] "PING" 1522663856.583894 [0 127.0.0.1:34881] "PING" 1522663856.686623 [0 127.0.0.1:34881] "PING" 1522663856.696851 [0 127.0.0.1:34881] "PING" 1522663856.707109 [0 127.0.0.1:34881] "PING"- 延迟
- 持续实时监控
- 持续监控redis使用的是linux自带的watch命令和我们前面监控命令结合到一起就可以变成持续的实时监控工具了。
先将前面的命令保存到一个shell脚本中,
vi testredis.sh #!/bin/bash /usr/local/redis/redis-cli -h 127.0.0.1 -p 6380 -a 123456 info | grep -e "connected_clients" -e "blocked_clients" -e "used_memory_human" -e "used_memory_peak_human" -e "rejected_connections" -e "evicted_keys" -e "instantaneous"
#保存后并给予执行的权限 chmod 755 testredis.sh
使用watch命令实时监控
watch -n 1 -d "/usr/local/redis/testredis.sh"
- 持续实时监控
- 慢操作日志
- SORT、LREM、SUNION等操作在大对象上会非常耗时,使用时要注意参照官方API上每个命令的算法复杂度。和主流数据库提供的慢SQL日志一样,Redis也提供了记录慢操作的日志。注意这部分日志只会计算纯粹的操作耗时。
- 慢操作日志
8、压力测试redis
redis-benchmark
默认情况下面,基准测试使用单一的 key。在一个基于内存的数据库里, 单一 key 测试和真实情况下面不会有巨大变化。当然,使用一个大的 key 范围空间, 可以模拟现实情况下面的缓存不命中情况。
这时候我们可以使用 -r 命令。比如,假设我们想设置 10 万随机 key 连续 SET 100 万次,我们可以使用下列的命令:
./redis-benchmark -p 6380 -a 123456 -t set -n 1000 -r 10
====== set -n 1 -r 1000 ======
100000 requests completed in 1.24 seconds
50 parallel clients
3 bytes payload
keep alive: 1
99.88% <= 1 milliseconds
99.89% <= 2 milliseconds
99.90% <= 3 milliseconds
99.95% <= 5 milliseconds
100.00% <= 5 milliseconds
80450.52 requests per second
有几个因素直接决定 Redis 的性能。它们能够改变基准测试的结果, 所以我们必须注意到它们。一般情况下,Redis 默认参数已经可以提供足够的性能, 不需要调优。
- 网络带宽和延迟通常是最大短板。建议在基准测试之前使用 ping 来检查服务端到客户端的延迟。根据带宽,可以计算出最大吞吐量。 比如将 4 KB 的字符串塞入 Redis,吞吐量是 100000 q/s,那么实际需要 3.2 Gbits/s 的带宽,所以需要 10 GBits/s 网络连接, 1 Gbits/s 是不够的。 在很多线上服务中,Redis 吞吐会先被网络带宽限制住,而不是 CPU。 为了达到高吞吐量突破 TCP/IP 限制,最后采用 10 Gbits/s 的网卡, 或者多个 1 Gbits/s 网卡。
- CPU 是另外一个重要的影响因素,由于是单线程模型,Redis 更喜欢大缓存快速 CPU, 而不是多核。这种场景下面,比较推荐 Intel CPU。AMD CPU 可能只有 Intel CPU 的一半性能(通过对 Nehalem EP/Westmere EP/Sandy 平台的对比)。 当其他条件相当时候,CPU 就成了 redis-benchmark 的限制因素。
- 在小对象存取时候,内存速度和带宽看上去不是很重要,但是对大对象(> 10 KB), 它就变得重要起来。不过通常情况下面,倒不至于为了优化 Redis 而购买更高性能的内存模块。
- Redis 在 VM 上会变慢。虚拟化对普通操作会有额外的消耗,Redis 对系统调用和网络终端不会有太多的 overhead。建议把 Redis 运行在物理机器上, 特别是当你很在意延迟时候。在最先进的虚拟化设备(VMWare)上面,redis-benchmark 的测试结果比物理机器上慢了一倍,很多 CPU 时间被消费在系统调用和中断上面。