简介
在介绍redis之前先简单介绍一下NoSQL(非关系型数据库)。
为什么要用非关系型数据库呢?因为互联网的发展太迅速,在海量数据,高并发的情况下,传统的关系型数据库显得有些力不从心了,暴露出了很多问题:
对数据库高并发读写的需求:
关系型数据在应付上万次SQL查询时还勉强扛得住,但是,应付上万次写数据的请求,硬盘IO就无法承受了。像微博,发生一个热点事件,它要记录点赞次数,转发次数等。
对海量数据的高效率存储和访问的需求:
比如登陆系统,腾讯,新浪那种上亿的账号,关系型数据库也很难应付。
对数据库高可拓展性和高可用性的需求:
在基于web的架构当中,数据库是最难进行横向扩展的,当一个应用系统的用户量和访问量与日俱增的时候,你的数据库却没有办法像web server和app server那样简单的通过添加更多的硬件和服务节点来扩展性能和负载能力。
因此,关系数据库在这些越来越多的应用场景下显得不那么合适了,为了解决这类问题的非关系数据库应运而生。
NoSQL(Not Only SQL)的类型大致可以分为以下几种:
- k/v:Dynamo, redis
- column Family:列式数据库, hbase
- document:文档数据库,mongodb
- GraphDB:图式数据库,Neo4j
redis是一个k/v存储的NoSQL,支持非常大的并发场景,它与memcached不同的是,它是单进程,并且支持持久化存储。它可以用来当作缓存服务器,可以做消息队列。
redis的数据结构
redis共有五种数据类型:
string
:字符,值类似于 key valuesets
:集合,值类似于 key value1 [value2 value3...]sorted_set
:有序的集合,值类似于 key score1 value1 [score2 value2 score3 value3...]hash
:哈希kv,值类似于 key field1 value1 [field2 value2]list
:列表,值类似于集合,只不过采用了双向链表的方式,存取采用left 与right两个方向的push于pop动作方式
redis的数据持久化实现
RDB:
RDB
:snapshotting, 二进制格式;按事先定制的策略,周期性地将数据从内存同步至磁盘;数据文件默认为dump.rdb。
- 有save和bgsave两种方式:save,同步,即在主线程中保存快照,此时会阻塞所有客户端请求;BGSAVE,异步;
AOF
:Append Only File, fsync。AOF的方式是采用存储数据操作命令到磁盘来实现持久化,类似于mariadb的binary-log;当redis重启时,可通过重新执行文件中的命令在内存中重建出数据库;
- AOF持久化通过重写(
rewrite
)的方式来实现。(BGREWRITEAOF) - 重写过程中的写入请求不会影响重写,新的请求会被附加在原AOF文件后。
- 存储的是操作命令,所以对于磁盘占用较大,数据可以看作是伪数据。
rewrite流程:
1. redis主进程去fork一个子进程用来读取当前的操作命令到临时文件存储。
2. 主进程会继续接受用户的写入操作,并且一方面附加到临时文件末尾,一方面存储到当前的AOF中。
#存储两份是为了防止子进程重写失败而导致一部分的写入数据丢失。
3. 子进程完成重写并且去替换原来的AOF文件,完成新的AOF文件存储。
注意:持久机制本身不能取代备份;应该制订备份策略,对redis库定期备份;
RDB与AOF同时启用:
- (1) BGSAVE和BGREWRITEAOF不会同时进行;
- (2) Redis服务器启动时用持久化的数据文件恢复数据,会优先使用AOF;
redis程序和配置文件
程序和文件
/etc/redis-sentinel.conf #redis的高可用组件sentinel的默认配置文件。
/etc/redis.conf #redis的默认配置文件。
/usr/bin/redis-cli #redis的命令行工具,支持远程连接到redis进行基于command的操作。
/usr/bin/redis-sentinel #sentinel的主程序,实际上可以认为是是redis [option] <config-file> -sentinel的alias。
/usr/bin/redis-server #redis的主程序,主要的格式redis [option] <config-file> 。
/var/lib/redis #redis的默认库目录。
/var/log/redis #redis的默认日志目录。
/var/run/redis #redis的允许中产生的文件存放的默认目录。
/usr/lib/systemd/system/redis-sentinel.service #sentinel的systemd文件。
/usr/lib/systemd/system/redis.service #redis的systemd文件。
redis.conf配置参数
#### GENERAL ####
daemonize yes #以守护进程的方式运行
pidfile "/var/run/redis/redis.pid" #pidfile
port 6379 #port
tcp-backlog 511 #tcp的backlog队列长度,backlog的长度是未建立的tcp连接和已经建立的tcp连接之和,等待进程从队列中调用建立的连接。
bind 192.168.1.30 10.0.0.1 #监听的地址,可以指定多个,0.0.0.0代表本机所有所有地址。
timeout 5000 #客户端连接的超时时间,单位是毫秒。
loglevel notice #日志的记录等级。
logfile "/var/log/redis/redis.log" #日志的存放位置。
databases 16 #设定数据库数量,默认为16个,每个数据库的名字均为整数,从0开始编号,默认操作的数据库为0;切换数据库的方法:SELECT <dbid>
tcp-backlog 511 ###tcp三次握手等待确认ack最大的队列数
## SNAPSHOTTING ##
save 900 1 #RDB方式的持久化策略,也就是说RDB方式下,数据被定期存储到磁盘的策略。
save 300 10 #此处三个save依次表示,在900秒内,如果1个key发生改变就写一次磁盘;
save 60 10000 #在300秒内,如果10个key发生改变就写一次磁盘;在60秒内如果10000个key发生改变就写一次磁盘。
stop-writes-on-bgsave-error yes #在bgsave时,发生写入操作时会报告错误么,即在bgsave时不允许写入数据。
rdbcompression yes #rdb文件可以被压缩。
rdbchecksum yes #rdb文件开启校验。
dbfilename "dump.rdb" #db的名称为 dump.rdb
dir "/redis/data1" #RDB的数据目录,在指定非默认目录时,需要修改目录的属主属组为你当前redis进程的属主属组,一般为redis。
# APPEND ONLY MODE #
appendonly yes #开启AOF持久化方式。
appendfilename "appendonly.aof" #AOF文件名。
appendfsync everysec #AOF的持久化策略,有三个值,always表示只要发生数据操作就执行保存或者重写AOF;everysec表示一秒一次;no表示关闭;
no-appendfsync-on-rewrite yes #在重写时将当前AOF的日志存储在内存中,防止AOF附加操作与重写产生数据写入堵塞问题,提高了性能却增加了数据的风险性。
auto-aof-rewrite-percentage 100 #每当AOF日志是上次重写的一倍时就自动触发重写操作。
auto-aof-rewrite-min-size 64mb #自动触发重写的最低AOF日志大小为64MB,为了防止在AOF数据量较小的情况话频繁发生重写操作。
aof-load-truncated yes #当redis发生奔溃,通过AOF恢复时,不执行最后最后那条因为中断而发生问题的语句。
#### LIMITS ####
maxclients 10000 #限制最大的并发用户连接数为10000条。
# maxmemory <bytes> #限制最大的内存使用量。
### SECURITY ###
requirepass <password> #设定认证的密码,如果设定了,在远程cli登录,主从配置和sentinel时都需要指定对应参数为此passwd。
redis-cli命令
redis-cli [-h <hostname> -p <port> -a <password>]
@generic
DEL KEYS(KEYS *列出所有键) MOVE ...
@server
SYNC SLAVEOF SAVE BGSAVE SHUTDOWN ... (CLIENT ... CONFIG ...)
@connection
AUTH(认证) ECHO PING QUIT SELECT(切换数据库) ...
@string
GET SET INCR(+1) DECR(-1) SETNX STRLEN ...
@list
LINDEX LINSERT LLEN LPOP LPUSH LPUSHX LRANGE LSET RPOP RPUSH RPUSHX(值不存在才设置) ...
@set
SADD SCARD SMEMBERS(get值) SRANDMEMBER(随机get值) SDIFF(求差异) SDIFFSTORE SINTER(交集) SINTERSTORE SUNION(并集) SUNIONSTORE ...
@sorted_set
ZADD ZCARD ZCOUNT(返回有序集中range间的所有值) ZSCORE(根据序号get值) ...
@hash
HDEL HGET HGETALL HINCRBY HKEYS HSET HSETNX ...
redis主从复制
redis的主从复制非常简单,下面我们来演示一下:
- node2(172.16.47.102)为master;
- node3(172.16.47.103)为slave;
- node4(172.16.47.104)为slave;
在node3和node4上执行如下命令:
172.16.47.104:6379> slaveof 172.16.47.102 6379 #不过这种方式只是保证了在执行slaveof命令之后,node3,4成为了node2的slave,一旦服务重启之后,他们之间的复制关系也将终止,如果希望长久保存的话,可以在node3,4的配置文件中配置:
vim /etcredis.conf
主从复制的主要参数:
### REPLICATION ###
slaveof 172.16.47.102 6379 #主节点地址,<host> <port>。
masterauth admin@123 #如果设置了访问认证就需要设定此项。
slave-server-stale-data yes #当slave与master连接断开或者slave正处于同步状态时,如果slave收到请求允许响应,no表示返回错误。
slave-read-only yes #slave节点是否为只读。
slave-priority 100 #设定此节点的优先级,是否优先被同步。
配置完成之后,重启redis服务,我们来验证同步的结果:
在node2上info
:
node3,4上:
在node2上写入一条数据:
在node3,4上查看,也能看到该数据,主从复制成功。
我的博客iLurker.cn