redis学习整理笔记
文章目录
一、NoSql入门概述
1、入门概述
- 为什么要用NoSql?
- 单机MySql的年代
- Memcached(缓存)+MySql+垂直拆分
- MySql主从读写分离
- 由于数据库的写入压力增加,,,,
- 分表分库+水平拆分+mysql集群
- MySql的扩展性瓶颈
- 今天是什么样子
- 为什么用NoSql
- 是什么
- 能干嘛
2、3V+3高
-
3V:Volume(海量)、Variety(多样)、Velocity(时)
-
3高:高并发、高可扩、高性能
3、当下的NoSql经典应用
4、NoSql数据模型简介
- 聚合模型
- KV键值
- Bson
- 列数
- 图形
5、NoSql数据库的四大分类
- KV键值
- 新浪:BerkeleyDB+redis
- 美团:redis+tair
- 阿里、百度:memcache+redis
- 文档性数据库(Bson格式比较多)
- CouchDb
- MongDb
- 列存储数据库
- Cassandra\HBase
- 分布式文件系统
- 图关系数据库
- 它不是放图形的,放的是关系。比如:朋友圈社交网络、广告推荐系统等。
- 专注于构建关系图谱
- Neo4j\InfoGrid
- 四者对比
6、在分布式数据库中CAP原理 CAP+BASE
- 传统的ACID:A(Atomicity)原子性、C()一致性、I()独立性、D()持久性
- CAP:C(Consistency)强一致性、A(Avaliability)可用性、P(Partition tolerance)区分可容错性
- CAP的3进2
- 经典的CAP图
- BASE
- 分布式+集群简介
二、redis入门介绍
1、入门概述
- 是什么
- 能干吗
- 去哪下
- 怎么用
2、下载与安装
(Linux版本,因为ubuntu出错,make不了,也就是安装不了,所以就用window试试手)
- 下载
- 安装
三、redis的数据类型
1、redis的五大数据类型:
- String(字符串)
- Hash(哈希,类似于java里面的map)
- List(列表)
- Set(集合)
- Zset(sorted set:有序集合)
String(字符串)
- String是redis最基本的类型,你可以理解成与Memcached一摸一样的类型,一个key对应一个value
- String类型是二进制安全的,意思是redis的String可以包含任何数据,比如jpg图片或者序列化的对象
- String类型是redis最基本的数据类型,一个redis中字符串value最多可以是512M
Hash(哈希,类似于java里面的map)
List(列表)
Set(集合)
Zset(sorted set:有序集合)
2、redis的常见数据类型操作命令
常用:http://redisdoc.com/
redis键(key)
-
set/get/del/append/strlen:
-
**keys ***
- 返回所有的key
-
set (set key value)
- 设置,也就是添加数据进redis数据库
- key后面一定要跟value,否则或报错
- 如果要添加value为空的值,则value设置为null,这时类型为none
-
get(get key)
- 获取key的value
-
del(del key)
- 删除key
-
append(append key value)
- 在原数据尾端再添加值
-
strlen
- 获取长度
-
-
incr/decr/incrby/decrby
-
前提:一定是数字才能加减**
-
incr(incr key)
- 递增1
-
decr(decr key)
- 递减1
-
incrby(incrby key value)
- 递增value
- value必须为数字,不然报错
-
decrby(decrby key value)
- 递增value
- value必须为数字,不然报错
-
-
setrange/getrange
-
setrange(setrange key index value)
- 从下标index开始,后面的值替换为value
-
getange(getange key index1 index2)
- 对value值,取从下标index1到index2
- 取所有的值:getange key 0 -1
-
-
setex/setnx
- setex(setex key second value)
- 设置规定时间内失去效用,会自动删除(以秒为单位)
- setnx(setnx key value)
- 如果key不存在则插入,存在则插入不了,不会修改值
- setex(setex key second value)
-
mset/mget/msetnx
- mset(mset key1 value1 key2 value2 key3 value3 …)
- 一次性插入多个值
- mget(mget key1 value1 key2 value2 key3 value3 …)
- 一次性获取多个值
- msetnx(msetnx key1 value1 key2 value2 key3 value3 …)
- 一次性的进行setnx操作,当key不存在才会插入值
- 必须保证所有key值在源数据都没有,否则全部都插入不了
- mset(mset key1 value1 key2 value2 key3 value3 …)
redis列表(List)
性能总结
- 它是一个字符串链表,left、right都可以插入添加
- 如果健不存在,创建新的链表
- 如果建已存在,新增内容
- 如果健全移除,对应的健也消失了
- 链表的操作无论是头和尾效率都极高,但如果是对中间元素进行操作,效率就很惨淡了
-
lpush/rpush/lrange:从左边放值/从右边放值/查看列表数值
- lpush(lpush key value)
- rpush(rpush key value)
- lrange(lrange key index1 index2)
- index1(开始下标)index2(结束下标)
- 取全部值:lrange key 0 -1
-
lpop/rpop:从左边弹出值/从右边弹出值
- lpop(lpop key)
- rpop(rpop key)
-
lindex:按照索引下标获得元素(从上到下),并不是弹出值
- lindex(lindex key index)
-
llen:获取列表长度
-
lrem :按顺序删除n个值
-
lrem(lrem key n value)
-
按顺序删除值
-
如果没有所需要删除的值,不会报错
-
如果删除的个数大于列表所拥有的个数,也不会报错
-
-
-
ltrim :截取指定范围的值后再重新赋值给原有列表
- ltrim(ltrim key index1 index2)
-
rpoplpush:对list1进行rpop操作,然后把值对list2进行lpush操作,相当于把list1的出栈值压入list2
- rpoplpush(rpoplpush list01 list02)
-
lset:修改特定下标的值
- lset(lset key index value)
-
linsert key before/after:插入一个value2值,放在value1之前/后
- linsert(linsert key before value1 value2)
- value1的值必须是列表key的值
- 如果value1不是列表key的值,报错,无法插入
- linsert(linsert key after value1 value2)
- value1的值必须是列表key的值
- 如果value1不是列表key的值,报错,无法插入
- linsert(linsert key before value1 value2)
redis集合(Set)
-
sadd/smembers/sismember
- sadd(sadd key value1 value2 value2…)
- 添加集合,重复的值只会添加一次
- smembers(smembers key)
- 读取出集合里面所有的值
- sismember(sismember key value)
- 判断集合是否有value值
- sadd(sadd key value1 value2 value2…)
-
scard
- scard(scard key value)
- 判定set的个数
- scard(scard key value)
-
srem
- srem(srem key value)
- 删除集合里面的value值
- srem(srem key value)
-
srandmember
- srandmember(srandmember key n)
- 随机从集合获取n个值,n不写时默认是1
- srandmember(srandmember key n)
-
spop
- spop(spop key)
- 随机弹出集合的一个值
- spop(spop key)
-
smove
- smove(smove key1 key2 value)
- 将set1中的value值传给set2
- smove(smove key1 key2 value)
-
差集:sdiff
- sdiff(sdiff key1 key2)
- 求集合1和集合2的差集
- sdiff(sdiff key1 key2)
-
交集:sinter
- sinter(sinter key1 key2)
- 求集合1和集合2的交集
- sinter(sinter key1 key2)
-
并集:sunion
- sunion(sunion key1 key2)
- 求集合1和集合2的并集
- sunion(sunion key1 key2)
redis哈希(Hash)
-
hset/hget/hmset/hmget/hgetall/hdel
-
hset(hset name(key) key value)
- hset user id 5
- 设置hash
-
hget(hget name(key) key value)
- hget user id
- 获取user的id
-
hmset(hmset name key1 value1 key2 value2…)
- 一次性设置hash对象的其他属性
-
hmget(hmget name key1 key2…)
- 一次性获取所需的key所对应的value值
-
hdel
- hdel name
- 删除hash对象
- hdel nane key
- 删除hash的key属性
- hdel name
-
-
hlen
- hlen(hlen name)
- 获取hash对象的属性长度
- hlen(hlen name)
-
hexists
- hexists(hexists name key)
- 判断hash对象是否有key属性
- hexists(hexists name key)
-
hkeys/hvals
- hkeys(hkeys name)
- 获取hash对象的所有属性(key)
- hvals(hvals name)
- 获取hash对象的所有value值
- hkeys(hkeys name)
-
hincrby/hincrbyfloat
- hincrby(hincrby name key n)
- key属性所对应的value依次增加n
- key对应的value必须是数字
- hincrbyfloat(hincrby name key n)
- key属性所对应的value依次增加浮点值n
- key对应的value必须是数字
- hincrby(hincrby name key n)
redis有序集合(Zset)
在set的基础上,增加一个score值。
之前的set是 k1 v1 v2 v3
现在Zset是 k1 score1 v1 score2 v2
- zadd/zrange
- zadd(zadd key score1 value1 score2 value2 score3 value3…)
- 添加有序集合
- zrange(zrange key index1 index2)
- 取index1到index2的值
- 取全部的值:zrange key 0 -1
- zrange(zrange key index1 index2 withscores)
- 取index1到index2的值,并且scores也取出来
- 取全部的值:zrange key 0 -1
- zadd(zadd key score1 value1 score2 value2 score3 value3…)
- zrangebyscore
- zrangebyscore(zrangebyscore key score1 score2)
- 根据score来取value,并且score在score1和score2之间,score1必须小于score2
- zrangebyscore(zrangebyscore key score1 score2)
- zrem
- zrem(zrem key value)
- 删除value的值,并且相应的score也删除
- zrem(zrem key value)
- zcard/zcount/zrank/zscore
- zcard(zcard key)
- 查找长度
- zcount(zcount key score1 score2)
- 查找score在1和2之间的个数
- zrank(zrank key value)
- 查找value在有序集合的下标
- zscore(zscore key value)
- 查找value在有序集合的score
- zcard(zcard key)
- zrevrank
- zrevrank(zrevrank key value)
- 通过逆序获取下标
- zrevrank(zrevrank key value)
- zrevrange
- zrevrange(zrevrange key index1 index2)
- 逆序取index1到index2的值
- 逆序取全部的值:zrange key 0 -1
- zrevrange(zrevrange key index1 index2)
- zrevrangebyscore
- zrevrangebyscore(zrevrangebyscore key score1 score2)
- 逆序根据score来取value,并且score在score1和score2之间,score1必须大于score2
- zrevrangebyscore(zrevrangebyscore key score1 score2)
四、解析配置文件:redis.conf
1、它在哪
2、Units单位
# Redis configuration file example
# Note on units: when memory size is needed, it is possible to specify
# it in the usual form of 1k 5GB 4M and so forth:
#
# 1k => 1000 bytes
# 1kb => 1024 bytes
# 1m => 1000000 bytes
# 1mb => 1024*1024 bytes
# 1g => 1000000000 bytes
# 1gb => 1024*1024*1024 bytes
#
# units are case insensitive so 1GB 1Gb 1gB are all the same.
- 配置大小单位,开头定义了一些基本的数量单位,只支持bytes,不支持bit
- 对大小写不敏感
3、INCLUDES包含
# Include one or more other config files here. This is useful if you
# have a standard template that goes to all Redis servers but also need
# to customize a few per-server settings. Include files can include
# other files, so use this wisely.
#
# Notice option "include" won't be rewritten by command "CONFIG REWRITE"
# from admin or Redis Sentinel. Since Redis always uses the last processed
# line as value of a configuration directive, you'd better put includes
# at the beginning of this file to avoid overwriting config change at runtime.
#
# If instead you are interested in using includes to override configuration
# options, it is better to use include as the last line.
#
# include .\path\to\local.conf
# include c:\path\to\other.conf
和我们的struts2配置文件类似,可以通过includes包含,redis.conf可以作为总阀,包含其他
4、GENERAL通用
-
daemonize
# By default Redis does not run as a daemon. Use 'yes' if you need it. # Note that Redis will write a pid file in /var/run/redis.pid when daemonized. daemonize no
默认是no,使用时要设置为yes
-
pidfile:进程管道pid
# Creating a pid file is best effort: if Redis is not able to create it # nothing bad happens, the server will start and run normally. pidfile /var/run/redis_6379.pid
-
port:默认端口号
# 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
-
tcp-backlog
#In high requests-per-second environments you need an high backlog in order # to avoid slow clients connections issues. Note that the Linux kernel # will silently truncate it to the value of /proc/sys/net/core/somaxconn so # make sure to raise both the value of somaxconn and tcp_max_syn_backlog # in order to get the desired effect.
tcp-backlog
设置tcp的backlog,backlog其实是一个连接队列,backlog队列总和=未完成三次握手队列+已经完成三次队列+已经完成三次队列。
在高并发环境下你需要一个高backlog值来避免慢客户端连接问题。注意linux内核会将这个值减少到/proc/sys/net/core/somaxconn的值,所以需要确认增大somaxconn和tcp_max_syn_backlog这两个值来达到想要的效果
-
timeout:设置时间限制
# Close the connection after a client is idle for N seconds (0 to disable) timeout 0
-
bind:绑定的ip和端口
# By default, if no "bind" configuration directive is specified, Redis listens # for connections from all the network interfaces available on the server. # It is possible to listen to just one or multiple selected interfaces using # the "bind" configuration directive, followed by one or more IP addresses. # # Examples: # # bind 192.168.1.100 10.0.0.1 # bind 127.0.0.1 ::1
-
tcp-keepalive:查看是否存活(如网络是否连通)
# 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
单位为秒,如果设置为0,则不会进行keepalive检测,建议设置成60
-
loglevel:日志级别
# Specify the server verbosity level. # This can be one of: # debug (a lot of information, useful for development/testing) # verbose (many rarely useful info, but not a mess like the debug level) # notice (moderately verbose, what you want in production probably) # warning (only very important / critical messages are logged) loglevel notice
-
logfile:日志名字
# Specify the log file name. Also the empty string can be used to force # Redis to log on the standard output. Note that if you use standard # output for logging but daemonize, logs will be sent to /dev/null logfile ""
-
syslog-enabled:是否把日志输出到syslog中
# To enable logging to the system logger, just set 'syslog-enabled' to yes, # and optionally update the other syslog parameters to suit your needs. # syslog-enabled no
-
syslog-ident:指定syslog里的日志标识
# Specify the syslog identity. # syslog-ident redis
-
syslog-facility:指定syslog设备,值可以是USER或LOCAL0-LOCAL7
# Specify the syslog facility. Must be USER or between LOCAL0-LOCAL7. # syslog-facility local0
-
databases
# 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
5、SNAPSHOTTING快照
-
save
-
save 秒数
# 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. save 900 1 save 300 10 save 60 10000
RDB是整个内存的压缩过得snapshot,RDB的数据结构,可以配置复合的快照触发条件
默认:15分钟改了1次
或5分钟改了10次
1分钟改了1万次
-
禁用
# 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 ""
如果想禁用RDB持久化策略,只要不设置任何save指令,或者给save传入一个空字符串参数也可以
-
-
stop-writes-on-bgsave-error:如果后台save操作出错,前台停止写
# By default Redis will stop accepting writes if RDB snapshots are enabled # (at least one save point) and the latest background save failed. # This will make the user aware (in a hard way) that data is not persisting # on disk properly, otherwise chances are that no one will notice and some # disaster will happen. # # If the background saving process will start working again Redis will # automatically allow writes again. # # However if you have setup your proper monitoring of the Redis server # and persistence, you may want to disable this feature so that Redis will # continue to work as usual even if there are problems with disk, # permissions, and so forth. stop-writes-on-bgsave-error yes
如果设置成no,表示不在乎数据不一致或者有其他手段发现和控制
-
rdbcompression
# 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
- 是否启用LZF压缩算法,默认启用压缩
- rdbcompression:对于存储到磁盘中的快照,可以设置是否进行压缩存储。如果是的话,redis会采用LZF压缩算法进行压缩。如果你不想消耗CPU来进行压缩的话,可以设置为关闭此功能
-
rdbchecksum
# Since version 5 of RDB a CRC64 checksum is placed at the end of the file. # This makes the format more resistant to corruption but there is a performance # hit to pay (around 10%) when saving and loading RDB files, so you can disable it # for maximum performances. # # RDB files created with checksum disabled have a checksum of zero that will # tell the loading code to skip the check. rdbchecksum yes
rdbchecksum:在存储快照后,还可以让redis使用CRC64算法来进行数据校验,但是这样做会增大大约10%的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能。
-
dbfilename:备份的文件名
# The filename where to dump the DB dbfilename dump.rdb
-
dir:备份的目录
6、REOLICATION复制
7、SECURITY安全
默认功能关闭,需要使用的话自己设置
# Require clients to issue AUTH <PASSWORD> before processing any other
# commands. This might be useful in environments in which you do not trust
# others with access to the host running redis-server.
#
# This should stay commented out for backward compatibility and because most
# people do not need auth (e.g. they run their own servers).
#
# Warning: since Redis is pretty fast an outside user can try up to
# 150k passwords per second against a good box. This means that you should
# use a very strong password otherwise it will be very easy to break.
#
# requirepass foobared
# Command renaming.
#
# It is possible to change the name of dangerous commands in a shared
# environment. For instance the CONFIG command may be renamed into something
# hard to guess so that it will still be available for internal-use tools
# but not available for general clients.
#
# Example:
#
# rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52
#
# It is also possible to completely kill a command by renaming it into
# an empty string:
#
# rename-command CONFIG ""
#
# Please note that changing the name of commands that are logged into the
# AOF file or transmitted to replicas may cause problems.
8、LIMITS限制
-
maxclients
-
maxmemory
-
maxmemory-policy
# volatile-lru -> Evict using approximated LRU among the keys with an expire set. # allkeys-lru -> Evict any key using approximated LRU. # volatile-lfu -> Evict using approximated LFU among the keys with an expire set. # allkeys-lfu -> Evict any key using approximated LFU. # volatile-random -> Remove a random key among the ones with an expire set. # allkeys-random -> Remove a random key, any key. # volatile-ttl -> Remove the key with the nearest expire time (minor TTL) # noeviction -> Don't evict anything, just return an error on write operations.
- volatile-lru:使用LRU(最近最少使用)算法移除key,只对设置了过期时间的健
- allkeys-lru:使用LRU算法移除key
- volatile-random:在过期集合中移除随机的key,只对设置了过期时间的健
- allkeys-random:随机移除key
- volatile-ttl:移除那些TTL值最小的key,和那些最近过期的key
- noeviction:不进行移除,针对写操作,只是返回错误信息
-
maxmemory-samples
- 设置样本数量,LRU算法和并非是精确的算法,而是估算值,所以你可以设置样本的大小,redis默认会检查这么多个key并选择其中LRU的那个
9、APPEND ONLY MODE追加
- appendonly:是否需要使用aof,默认为no,使用时设置问yes
- appendfilename:配置文件名称(操作日志文件)
- appendfsync
- appendfsync always:同步持久化,每次发生数据变更会被立即记录到磁盘,性能较差但数据完整性比较好
- appendfsync everysec:出厂默认推荐,异步操作,每秒记录,如果一秒内死机,有数据丢失,只丢失1秒内操作的数据
- appendfsync no
- no-appendfsync-on-rewrite:重写时是否可以运用appendfsync,用默认no即可,保证数据安全性
- auto-aof-rewrite-percentage:设置重写的基准值
- auto-aof-rewrite-min-size:设置重写的基准值
10、常用配置redis.conf介绍
- daemonize no
- redis默认不是以守护进程方式运作,可以通过配置项修改,使用yes启用守护进程
- pidfile /var/run/redis_6379.pid
- 当redis以守护进程方式运行时,redis默认会把pid写入/var/run/redis_6379.pid文件,可以通过pidfile指定
- port 6379
- 指定redis监听端口,默认端口为6379,作者在自己的一篇文中解释了为什么选用6379作为默认端口,因为6379在手机按键上MERZ对应的号码,而MERZ取自意大利女歌手Alessia Merz
- bind 127.0.0.1
- 绑定的主机地址
- timeout 300
- 当客户端闲置多长时间后关闭连接,如果指定为0,表示关闭该功能
- loglevel notice
- 指定日志记录级别。redis总共支持四个级别debug、verbosenotice、warning,默认为notice
- logfile stdout
- 日志记录方式,默认为标准输出,如果配置redis为守护进程方式进行,而这里又配置为日志记录方式为标准输出,则日志将会发送给/dev/null
- databases 16
- 设置数据库数量,默认数据库是0,可以使用select命令在连接上指定数据库id
- save
- 指定多长时间内,有多少次更新操作,就将数据同步到数据文件,可以多个条件配合
- redis默认配置文件中提供了三个条件
- save 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
- 设置当本地slav服务时,设置master服务的ip地址及端口,在redis启动时,它会自动从master进行数据同步
- masterauth
- 当master设置了密码服务时,slav服务连接master的密码
- requirepass foobared
- 设置redis连接密码,如果配置了连接密码,客户端在连接redis时需要通过AUTH命令提供密码,默认关闭
- maxclients 128
- 设置同一时间最大客户端连接数,默认无限制。redis可以同时打开的客户端连接数为redis进程可以打开的最大文件描述符数,如果设置maxclients 0,表示不做限制。当客户端连接数到达限制时,redis会默认关闭新的连接并向客户端返回max number of clients reached 错误信息
- maxmemory
- 指定redis最大内存限制,redis启动时会把数据加载到内存中,达到最大内存后,redis会先尝试清除已到期或即将到期的key,当此方法处理后,仍然到达最大内存设置,将无法再进行写入操作,但仍可能进行读取操作。redis新的vim机制,会把key存放到内存中,value存放在swap区
- appendonly no
- 指定是否每次更新操作后进行日志记录。redis在默认情况下是异步的把数据写入磁盘,如果不开启,可能会在断电时导致一段时间的数据丢失。因为redis本身同步数据文件是按照上面save条件来同步的,所以有的数据会在一段时间内只存在内存中。默认为no
- appendfilename appendonly.aof
- 指定更新日志文件名,默认为appendonly.aof
- appendfsncy everysec
- 指定更新日志条件,有三个可选值
- no:表示等操作系统进行数据缓存同步到硬盘(快)
- always:表示每次更行操作后手动调用fsync()将数据写入到硬盘(慢,安全)
- everysec:表示每秒同步一次(折中,默认值)
- 指定更新日志条件,有三个可选值
- vm-enable
- 指定是否启用虚拟内存机制,默认值为no,简单的介绍一下,vm机制将数据分页存放,有redis将访问量较少的页即冷数据swap到磁盘上,访问多的页面由磁盘自动换出到内存中
- vm-swap-file/temp/redis.swap
- 虚拟文件内存路径,默认为/temp/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上不能被多个page共享,vm-page-size时要根据存储的数据大小来设定的,作者建议如果存储很多对象,page大小最好设置为32或者64bytes,如果存储很大的对象,则可以使用更大的page,如果不确定,就使用默认值
- vm-pages 134217728
- 设置swap文件中的page数量,由于页表(一种表示页面空闲或使用的bitmap)是放在内存中的,在磁盘上每8个pages将消耗1byte的内容
- vm-max-threads 4
- 设置访问swap的线程数,最好不要超过机器的核数,如果设置为0,那么所有对文件的操作都是串行的,可能会造成比较长时间的延迟。默认值是4
- glueoutputbuf yes
- 设置向客户端应答时,是否把较小的包合并成一个包发送,默认是开启
- hash-max-zipmap-entries 64 /hash-max-zipmap-value 512
- 指定在超过一定数量或者最大的元素超过某一临界值时,采用一种特殊的哈希算法
- activerehashing yes
- 指定是否激活重置哈希,默认开启
- include/path/to/local.conf
- 指定包含其他的配置文件,可以在同一台主机上多个redis实例之间使用同一份配置文件。而同时各个实例又拥有自己的特定文件
五、redis的持久化(重要)
1、总体介绍
-
Redis 提供了不同级别的持久化方式:
- RDB持久化方式能够在指定的时间间隔能对你的数据进行快照存储.
- AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以redis协议追加保存每次写的操作到文件末尾.Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大.
- 如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化方式.
- 你也可以同时开启两种持久化方式, 在这种情况下, 当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整.
- 最重要的事情是了解RDB和AOF持久化方式的不同,让我们以RDB持久化方式开始:
2、RDB(Redis DataBase) 重要
- 官网介绍
- 是什么
- 在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的snapshot快照,它恢复时是将快照文件直接读到内存里
- redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,带持久化过程都结束了,在用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能。
- 如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失。
- Fork
- Fork的作用是复制一个与当前进程一样的进程。新进程的所有数据(变量、环境变量、程序计数器等)数值都是和原进程一致,但是是一个全新的进程,并作为原进程的子进程。
- RDB保存的是demp.rdb文件
- 配置的位置:(上面,SNAPSHOTTING快照)
- 如何触发RDB快照
- 配置文件中默认的快照配置:一般是冷拷贝后重新使用
- 命令save或者bgsave:
- save:save时只会保存,其他不管,全部阻塞
- bgsave:redis会在后台异步进行快照操作,快照同时还可以响应客户端请求。可以通过lastsave命令获取最后一次成功执行快照的时间
- 执行flushall命令,也会产生dump.rdb文件,单里面是空的,无意义
- 如何恢复:
- 将备份文件(dump.rdb)移动到redis安装目录并启动服务即可
- config get dir 获取目录
- 优势
- 适合大规模的数据恢复
- 对数据完整性和一致性要求不高
- 劣势
- 在一定间隔时间做一次备份,所以如果redis意外down掉的话,就会丢失最后一次快照后的所有修改
- fork的时候,内存中的数据被克隆了一份,大致2倍的膨胀性需要考虑
- 如何停止
- 动态所有停止RDB保存规则的方法:redis-cll config set save “”
- RDB总结
- RDB是一个非常紧凑的文件
- RDB在保存RDB文件时父进程唯一需要做的就是fork出一个子进程,接下来的工作全部由子进程来做,父进程不需要再做其他IO操作,所以RDB持久化方式可以最大化redis的性能
- 于AOF相比,再恢复大的数据集的时候,RDB方式会更快一些
- 数据丢失风险大
- RDB需要经常fork子进程来保存数据集到硬盘上,当数据集比较大的时候,fork的过程是非常耗时的,可能导致redis在一些毫秒级不能响应客户端请求
3、AOF(Append Only File) 重要
- 官网介绍
- 是什么
- 以日志的形式来记录每个写操作,将redis执行过的所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作
- AOF保存的是appendonly.aof文件
- 配置位置
- AOF启动/修复/恢复
- 正常恢复
- 启动:修改默认的appendonly no ,修改成yes(将有数据的aof文件复制一份保存到对应目录(config get dir))
- 恢复:重启reids然后重新加载
- 异常恢复
- 启动:设置yes(备份被写坏的aof文件)
- 修复:redis-check-aof–fix进行修复
- 恢复:重启reids然后重新加载
- 正常恢复
- rewriite
- 是什么:AOF采用文件追加方式,文件会越来越大,为避免出现这种情况,新增了重写机制。当AOF文件的大小超过所设定的阈值时,redis就会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集们可以使用bgrewriteaof
- 原理:AOF文件持续增长而过大时,会fork出一条新进程来将文件重写(也是先写临时文件最后再rename),遍历新进程的内存中数据,每条记录有一条set语句。重写aof文件的操作,并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令重写了一个新的aof文件,这点和快照有点类似
- 触发机制:redis会记录上次重写的aof大小,默认配置时当aof文件大小是上次rewrite后大小的一倍且文件大于64M时触发
- 优势
- 每秒同步:appendfsync always 同步持久化,每次发生数据变更会被立即记录到磁盘,性能较差但数据完整性比较好
- 每修改秒同步:appendfsync everysec 出厂默认推荐,异步操作,每秒记录,如果一秒内死机,有数据丢失,只丢失1秒内操作的数据
- 不同步:appendfsync no 从不同步
- 劣势
- 相同数据集的数据而言,aof文件要远大于rdb文件,恢复速度慢于rdb
- aof运行效率要慢于rdb,每秒同步策略效率较好,不同步效率和rdb相同
- AOF总结
- aof文件时一个只进行追加的日志文件
- redis 可以在aof文件体积变得过大时自动的在后台对aof进行重写
- aof文件有序地保存了对数据库执行得所有写操作,这些写入操作以redis协议的格式保存,因此aof文件的内容非常容易被人读懂,对文件进行分析也很轻松
- 对于相同的数据集来说,AOF文件的体积通常要大于RDB文件的体积
- 根据所使用的fsync策略,aof的速度可能会慢于rdb
4、总结
-
官网建议
一般来说, 如果想达到足以媲美 PostgreSQL 的数据安全性, 你应该同时使用两种持久化功能。 如果你非常关心你的数据, 但仍然可以承受数分钟以内的数据丢失, 那么你可以只使用 RDB 持久化。 有很多用户都只使用 AOF 持久化, 但我们并不推荐这种方式: 因为定时生成 RDB 快照(snapshot)非常便于进行数据库备份, 并且 RDB 恢复数据集的速度也要比 AOF 恢复的速度要快, 除此之外, 使用 RDB 还可以避免之前提到的 AOF 程序的 bug 。 Note: 因为以上提到的种种原因, 未来我们可能会将 AOF 和 RDB 整合成单个持久化模型。 (这是一个长期计划。) 接下来的几个小节将介绍 RDB 和 AOF 的更多细节。
-
RDB持久化方式能够在指定的时间间隔能对你的数据进行快照存储
-
AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以redis协议追加保存每次写的操作到文件末尾,redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大
-
只做缓存:如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化方式
-
同时开启两种持久化方式
- 在这种情况下,当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下,AOF文件保存的数据集要比RDB文件保存的数据集要完整
- RDB的数据不实时,同时使用两者时服务器重启也只会找AOF文件,那要不要只使用AOF呢?作者建议不要,因为RDB更适合用于备份数据库(AOF在不断变化不好备份),快速重启,而且不会有AOF可能潜在的bug,留着作为一个万一的手段
-
性能建议
- 因为RDB 文件只用作后备用途, 建议只在Slave上持久化RDB 文件, 而且只要15 分钟备份一次就够了, 只保留save 900 1 这条规
- 如果Enable AOF , 好处是在最恶劣情况下也只会丢失不超过两秒数据, 启动脚本较简单只load 自己的AOF 文件就可以了。代价一是带来了持续的IO,二是AOF rewrite 的最后将rewrite 过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的,只要硬盘许可,应该尽量减少AOF rewrite 的频率, AOF 重写的基础大小默认值64M 太小了, 可以设到5G 以上。默认超过原大小100%大小时重写可以改到适当的数值
- 如果不EnabIe AOF , 仅靠Master-Slave Replication 实现高可用性也可以, 能省掉一大笔IO 也减少了rewrite 时带来的系统波动。代价是如果Master/Save 同时倒掉, 会丢夫十几分钟的数据, 启动脚本也要比较两个Master,/Save 中的RDB 文件,载入较新的那个.新浪微博就选用了这种架构
六、redis的事务
1、是什么
-
可以一次执行多个命令,本质是一组命令的集合。一个事务中的所有命令都会序列化,按顺序的串行化执行而不会被其他命令插入,不许加塞
-
MULTI 、 EXEC 、 DISCARD 和 WATCH 是 Redis 事务相关的命令。事务可以一次执行多个命令, 并且带有以下两个重要的保证:
- 事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
- 事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。
EXEC 命令负责触发并执行事务中的所有命令:
- 如果客户端在使用 MULTI 开启了一个事务之后,却因为断线而没有成功执行 EXEC ,那么事务中的所有命令都不会被执行。
- 另一方面,如果客户端成功在开启事务之后执行 EXEC ,那么事务中的所有命令都会被执行。
当使用 AOF 方式做持久化的时候, Redis 会使用单个 write(2) 命令将事务写入到磁盘中。
然而,如果 Redis 服务器因为某些原因被管理员杀死,或者遇上某种硬件故障,那么可能只有部分事务命令会被成功写入到磁盘中。
如果 Redis 在重新启动时发现 AOF 文件出了这样的问题,那么它会退出,并汇报一个错误。
使用
redis-check-aof
程序可以修复这一问题:它会移除 AOF 文件中不完整事务的信息,确保服务器可以顺利启动。从 2.2 版本开始,Redis 还可以通过乐观锁(optimistic lock)实现 CAS (check-and-set)操作,具体信息请参考文档的后半部分。
2、能干嘛
-
一个队列中,一次性、顺序性、排他性的执行一系列命令
-
MULTI 命令用于开启一个事务,它总是返回 OK 。 MULTI 执行之后, 客户端可以继续向服务器发送任意多条命令, 这些命令不会立即被执行, 而是被放到一个队列中, 当 EXEC命令被调用时, 所有队列中的命令才会被执行。 另一方面, 通过调用 DISCARD , 客户端可以清空事务队列, 并放弃执行事务。 以下是一个事务例子, 它原子地增加了 foo 和 bar 两个键的值:
3、怎么玩
-
常用命令
序号 命令及描述 1 DISCARD :取消事务,放弃执行事务块内的所有命令 2 EXEC: 执行所有事务块内的命令 3 MULTI:标记一个事务块的开始 4 UNWATCH:取消WATCH命令对所有key的监视 5 WATCH key[key …]:监视一个(或多个)key,如果在事务执行之前这个(或这些)key被其他命令所改动,那么事务将被打断 -
case1:正常执行
-
case2:放弃事务
-
case1:全体连坐
-
case1:冤头债主
-
case1:watch监控
-
悲观锁/乐观锁/CAS(check and set)
-
悲观锁
定义:悲观锁,顾名思义,很悲观。每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block知道他拿到锁。传统的关系型数据库用到很多这种机制,比如行锁、表锁等,读锁、写锁等,都是在做操作之前先上锁
-
乐观锁
定义:乐观锁,顾名思义,很乐观。每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量
策略:提交版本必须大于记录当前版本才能执行更新
-
CAS
-
-
初始化信用卡可用余额和欠款
-
无加塞篡改,先监控再开启mtlti,保证两笔金额变动在同一个事务内
-
有加塞篡改
-
unwatch
-
一旦执行了exec之前加的监控锁都会被取消掉了
-
总结
- watch指令,类似于乐观锁,事务提交时,如果key的值已被别的客户端改变,比如某个list已被别的客户端push/pop过了,整个事务队列将不会被执行
- 通过watch命令在事务执行之前监控了多个keys,倘若再watch之后有任何key的值发生了变化,exec命令执行的事物都将被放弃,同时返回Nullmulyi-bulk应答通知调用者事务执行失败
-
4、3个阶段
- 开启:以multi开始一个事务
- 入队:将多个命令入队到事务中,接到这些命令并不会立即执行,而是放到等待执行的事物队列里面
- 执行:有exec命令触发执行
5、3个特性
- 单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行、事务在执行的过程中,不会被其他客户端发来的命令请求所打断
- 没有隔离级别的概念:队列中的命令在没有提交之前都不会实际的执行,应为事务提交之前任何指令都不会被实际执行,也就不存在“事务内的查询要看到事务里的更新,在事务外查询不能看到”这个让人万分头痛的问题
- 不保证原子性:redis同一个事物中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚
七、redis的发布订阅
1、是什么
-
进程间的一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息
2、命令
序号 | 命令及描述 |
---|---|
1 | PSUBSCRIBE patten[patten…] 订阅一个或多个符合给定模式的频道 |
2 | PUBSUB subcommomand[argument[argument…]] 查看订阅预发布系统状态 |
3 | PUBLISH channel message 将消息发送到指定的频道 |
4 | PUNSUBSCRIBE [patten[patten…]] 退订所有给定的频道 |
5 | SUBSCRIBE channel [channel…] 订阅给定的一个或多个频道的消息 |
6 | UNSUBSCRIBE [channel [channel…]] 退订给定的频道 |
3、案列
先订阅发布后才能收到消息
1.可以一次性订阅多个 SUBSCRIBE c1 c2 c3
2.消息发布,PUBLISH c2 hello-redis
3.订阅多个,通配符*,PSUBSCRIBE new*
4.收取消息,PUBLISH new1 redis
八、redis的复制(master/slave)
1、是什么
-
在 Redis 复制的基础上,使用和配置主从复制非常简单,能使得从 Redis 服务器(下文称 slave)能精确得复制主 Redis 服务器(下文称 master)的内容。每次当 slave 和 master 之间的连接断开时, slave 会自动重连到 master 上,并且无论这期间 master 发生了什么, slave 都将尝试让自身成为 master 的精确副本。 这个系统的运行依靠三个主要的机制: 当一个 master 实例和一个 slave 实例连接正常时, master 会发送一连串的命令流来保持对 slave 的更新,以便于将自身数据集的改变复制给 slave , :包括客户端的写入、key 的过期或被逐出等等。 当 master 和 slave 之间的连接断开之后,因为网络问题、或者是主从意识到连接超时, slave 重新连接上 master 并会尝试进行部分重同步:这意味着它会尝试只获取在断开连接期间内丢失的命令流。 当无法进行部分重同步时, slave 会请求进行全量重同步。这会涉及到一个更复杂的过程,例如 master 需要创建所有数据的快照,将之发送给 slave ,之后在数据集更改时持续发送命令流到 slave 。 Redis使用默认的异步复制,其特点是低延迟和高性能,是绝大多数 Redis 用例的自然复制模式。但是,从 Redis 服务器会异步地确认其从主 Redis 服务器周期接收到的数据量。
-
也就是所说的主从复制,主机数据更新后根据配置和策略,自动同步到备机的master/slaver机制,master以写为主,slaver以读为主
2、能干嘛
- 读写分离
- 容灾复制
3、怎么玩
- 配从(库)不配主(库)
- 从库配置:slaveof主库IP主库端口(slaveof 127.0.0.1 7369)
- 每次与master断开以后,都需要重新连接,除非你配置进redis.conf文件
- info replication:查看是主库(master)还是从库(slaver)
- 修改配置文件细节操作
- 拷贝多个redis.conf文件
- 开启daemonize yes
- pid 文件名字
- 指定端口
- log 文件名字
- dump.rdb 名字
- 常用3招
- 一主二仆:就是一台主库,两台从库。从库自动复制主库所有内容
- 两个从库使用命令:slaveof 主库IP 主库端口
- 薪火相传:一个主库,剩下都是从库,一个连主库,另一个连从库
- 一个从库使用命令:slaveof 主库IP 主库端口
- 另一个使用命令:slaveof 从库IP 从库端口
- 反客为主:就是主库死机了,从库变成了主库
- 从库使用命令:slaveof no one
- 另一个从库使用命令:slaveof 新主库IP 端口
- 一主二仆:就是一台主库,两台从库。从库自动复制主库所有内容
4、复制原理
- slave启动成功连接到master后会发送一个sync命令
- master接到命令启动后台的存盘进程,同时收集所有接收到的用于修改数据的命令,在后台进程执行完毕之后,master将传送整个数据文件到slave,已完成一次完全命令同步
- 全量复制:而slave服务在接收到数据库文件数据之后,将其存盘并加载到内存中
- 增量复制:master继续将新的所有收集到的命令依次传给slave,完成同步
- 只要是重新连接master,一次完全同步(全量复制)将被自动执行
5、哨兵模式
- 定义:反客为主的自动版,能够后台监控主机是否故障,如果故障了根据投票自动将从库转为主库
- 使用步骤
- 主库(6379),从库(6380和6381)
- 新建sentinel.conf文件(名字不能错)
- 设置,填写配置
- sentinel monitor 被监控数据库的名字(主库,名字自己起) 127.0.0.1 6379 1
- 1 表示主机挂掉之后,slave投票出结果让谁替换成主机,得票数多的成为主机
- 启动
- 一组sentinrl能同时监控多个master
- 主库挂掉之后,再次重启会变成从库
6、复制的缺点
- 由于所有的写操作都是在主库(master)上操作,然后同步到从库(slave)上,所以从主库复制到从库上会有一定的延迟,当系统很繁忙的时候,延迟问题会更加严重,从库数量的增加也会是这个问题更加的严重
九、redis的java客户端jedis
-
需要使用maven导包
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.7.1</version><!--版本号可根据实际情况填写--> </dependency>
-
Jedis常用操作
-
测试连通性
Jedis jedis = new Jedis("127.0.0.1",6379); System.out.println(jedis.ping()); System.out.println(jedis.get("k1"));
-
5+1(一个key 五个数据类型)
-
事务提交
-
日常
Jedis jedis = new Jedis("127.0.0.1",6379); Transaction transaction = jedis.multi(); transaction.set("k3","v3"); transaction.set("k4","v4"); transaction.set("k5","v5"); //提交事务 transaction.exec(); //放弃事务 // transaction.discard(); System.out.println(jedis.get("k3"));
-
加锁
private boolean transMethod() throws InterruptedException { Jedis jedis = new Jedis("127.0.0.1",6379); int balance; //余额 int debt; //欠款 int amtToSubtract = 10; //实刷额度 jedis.watch("balance"); // Thread.sleep(7000); balance = Integer.parseInt(jedis.get("balance")); if (balance < amtToSubtract) { jedis.unwatch(); System.out.println("modify"); return false; }else { System.out.println("*******************transaction"); Transaction transaction = jedis.multi(); transaction.decrBy("balance",amtToSubtract); transaction.incrBy("debt",amtToSubtract); transaction.exec(); balance = Integer.parseInt(jedis.get("balance")); debt = Integer.parseInt(jedis.get("debt")); System.out.println("***************" + balance); System.out.println("***************" + debt); return true; } }
-
-
主从复制
-
JedisPool
public class JedisPoolUtil { private static volatile JedisPool jedisPool = null; public JedisPoolUtil(){} //创建 public static JedisPool getJedisPoolInstance() { if (null == jedisPool) { synchronized (JedisPoolUtil.class) { if (null == jedisPool) { JedisPoolConfig poolConfig = new JedisPoolConfig(); poolConfig.setMaxIdle(32); poolConfig.setMaxWaitMillis(100*1000); poolConfig.setMaxTotal(1000); poolConfig.setTestOnBorrow(true); jedisPool = new JedisPool(poolConfig,"127.0.0.1",6379); } } } return jedisPool; } //关闭 public static void release(JedisPool jedisPool,Jedis jedis) { if (jedis != null) { jedisPool.returnResourceObject(jedis); } } }
Jedis的配置参数大部分是由JedisPoolConfig的对应来完成的
- maxActive : 控制一个pool可分配多少个jedis 实例,通过pool.getResource()来获取:如果值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted
- maxldle: 控制一个pool最多有多少个状态为idle(空闲)的jedis 实例:
- whenExhaustedAction : 表示当pool引中的jedis 实例都被alloated完时,pool要采取的作: 默认有三种。
- WHEN_EXHAUSTED FAIL 一> 表示无jedis 实例时, 頁接抛出NoSuchEIementException :
- WHEN_EXHAUSTED BLOCK 一> 则表示阻塞住, 或者达到maxWait 时抛出JedisConnectionException :
- WHEN_EXHAUSTED_GROW — > 表示新建一个jedis实例, 也就说设置的maxActive 无用:
- maxWait : 表示当borrow一个jedis实例时,最大的等待时间, 如果超过等待时间, 则直接觉JedisConnectionException :
- testOnBorrow : 获得一个jedis实例的时候是否檜查连接可用性(ping()) :如果为true , 则得到的jedis实例均是可用的:
- testOnReturn : return 一个jedis实例给pool 时, 是否检查连接可用性(ping()) :
-