内存数据库专题
为什么要把数据存入内存?
快
常见的内存数据库:
MemCached:看成Redis前身,严格来说,MemCached不能叫数据库,只能叫缓存
不支持持久化。如果内存停电,数据丢失
Redis:内存数据库,支持持久化,支持HA
Oracle TimesTen
session一致性
MemCached + keepalive实现
一、Memcached
1、基本原理和体系架构
(*)在内存中,维护了一张巨大的Hash表
(*)通过路由算法来决定数据存储的位置。—> 客户端路由
注意:默认,官方版本MemCached实例彼此不会进行通信
第三方版本可以实现通信
2、安装配置MemCached
前提:
(1)gcc编译器
yum install gcc
gcc –version
(2)libevent库
tar -zxvf libevent-2.0.21-stable.tar.gz
cd libevent-2.0.21-stable
./configure --prefix
=/root/hd/libevent
make
make install
tar -zxvf memcached-1.4.25.tar.gz
cd memcached-1.4.25
./configure --prefix
=/root/hd/memcached --with-libevent
=/root/hd/libevent
make
make install
cd bin/
./memcached -u root -d -m 128 -p 11211
./memcached -u root -d -m 128 -p 11212
./memcached -u root -d -m 128 -p 11213
ps -ef | grep memcached
注意:
-u:root用户需要注明(其他用户可以不写)
-d:启动守护线程(在后天运行)
-m:占用多少内存
-p:运行在哪个端口
3、操作MemCached
(*)命令行
telnet 192.168.116.121 11211
保存数据:
set 如果key存在,替换原来的值
add 如果key存在,返回错误
set key1 | 0 | 0 | 4 |
key名字 | 标识位 | 数据过期时间0表示不过期 | value的长度 |
abcd
get key1
统计命令
stats items
stats
package day1;
import net.spy.memcached.MemcachedClient;
import net.spy.memcached.internal.OperationFuture;
import java.io.IOException;
import java.io.Serializable;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
/**
* java 操作Memcached
*/
public class Demo1 {
public static void main(String[] args) throws Exception {
//hello();
//testGet();
//setStudent();
testSets() ;
}
[root@hsiehchou121 memcached]# cd bin/
[root@hsiehchou121 bin]# ./memcached -u root -d -m 128 -p 11211
[root@hsiehchou121 bin]# ./memcached -u root -d -m 128 -p 11212
[root@hsiehchou121 bin]# ./memcached -u root -d -m 128 -p 11213
插入数据
public static void hello() throws Exception {
//连接到集群,set key
//建立MemcachedClient实例,指定Memcached服务器的IP地址和端口
MemcachedClient client = new MemcachedClient(new InetSocketAddress("192.168.116.121",11211));
Future<Boolean> f = client.set("key1", 0, "hello World");
if (f.get().booleanValue()){
client.shutdown();
}
}
[root@hsiehchou121 ~]# telnet 192.168.116.121 11211
get key1
查询数据
public static void testGet() throws Exception{
//连接到集群,set key
//建立MemcachedClient实例,指定Memcached服务器的IP地址和端口
MemcachedClient client = new MemcachedClient(new InetSocketAddress("192.168.116.121",11211));
//按照key取值,不存在的话返回null
Object o = client.get("key1");
System.out.println("取到的值为: " + o);
client.shutdown();
}
取到的值为:hello World
插入类
public static void setStudent() throws Exception{
//连接到集群,set key
//建立MemcachedClient实例,指定Memcached服务器的IP地址和端口
MemcachedClient client = new MemcachedClient(new InetSocketAddress("192.168.116.121",11211));
Future<Boolean> f = client.set("stu1", 0, new Student());
if (f.get().booleanValue()){
client.shutdown();
}
}
[root@hsiehchou121 ~]# telnet 192.168.116.121 11211
get stu1
基于客户端的分布式插入数据
public static void testSets() throws Exception{
//测试客户端路由算法
//构造每台Memcached服务器加入List
List<InetSocketAddress> list = new ArrayList<>();
list.add(new InetSocketAddress("192.168.116.121",11211));
list.add(new InetSocketAddress("192.168.116.121",11212));
list.add(new InetSocketAddress("192.168.116.121",11213));
//建立Memcached Client实例
MemcachedClient client = new MemcachedClient(list);
for (int i = 0; i < 20; i++){
System.out.println("插入数据:" + i);
client.set("key"+i,0, "value"+i);//(key1,value1)(key2,value2)
Thread.sleep(1000);
}
client.shutdown();
}
[root@hsiehchou121 ~]# telnet 192.168.116.121 11211
get key1
VALUE key1 0 6
value1
[root@hsiehchou121 ~]# telnet 192.168.116.121 11212
get key2
VALUE key2 0 6
value2
[root@hsiehchou121 ~]# telnet 192.168.116.121 11213
get key3
VALUE key3 0 6
value3
}
class Student implements Serializable{}
4、MemCached路由算法
1)求余数hash算法
用key做hash运算得到一个整数,根据余数路由
例如:服务器端有三台MemCached服务器
根据key,做hash运算
7%3=1,那么就路由到第2台服务器
6%3=0,那么路由到第1台服务器
5%3=2,那么路由到第3台服务器
优点:数据分布均衡在多台服务器中,适合大多数据需求
缺点:如果需要扩容或者有宕机的情况,会造成数据的丢失
2)一致性hash算法
基本原理:
key1 1-333 放在node1上
key2 334-666放在node2上
key3 667-1000放在hsiehchou121上
一致性hash算法下扩容
key1 1-333 放在node1上
key2 334-666放在node2上
key3 667-831放在hsiehchou121上
key4 832-1000放在node4上
如果扩容,增加一个新的节点,只影响扩容的节点,对其他节点不影响
一致性hash算法下DOWN机
key1 1-333 放在node1上
key2 334-666放在node2上
key3 667-1000放在hsiehchou121上
如果宕机,对key1 和 key2不产生影响,只对key3产生影响
5、MemCached的主主复制和HA
1)Memcached主主复制
架构图
主服务器 | 主服务器 | |
memcached | <——-> | memcached |
安装具有复制功能的memcached版本
tar zxvf memcached-1.2.8-repcached-2.2.tar.gz
cd memcached-1.2.8-repcached-2.2
./configure--prefix
=/root/hd/memcached_replication
--with-libevent
=/root/hd/libevent/--enable-replication
make
make install
出现以下错误
memcached.c: 696: error: `IOV MAX` undeclared (first use in this function)
memcached.c: 696: error: (Each undeclared identifier is reported only once
memcached.c: 696: error: for each function it appears in.)
解决办法
编辑memcached.c文件如下
55 /* FreeBSD 4.x doesn’t have IOV_MAX exposed. */
56 #ifndef IOV_MAX
57 #if defined(FreeBSD) || defined(APPLE)
58 # define IOV_MAX 1024
59 #endif
60 #endif
修改成如下形式
55 /* FreeBSD 4.x doesn’t have IOV_MAX exposed. */
56 #ifndef IOV_MAX
57 //#if defined(FreeBSD) || defined(APPLE)
58 # define IOV_MAX 1024
59 //#endif
60 #endif
启动第一台MemCached,使用-x指定对端服务器的地址
./memcached -u root -d -m 128 -x 192.168.116.121
启动第二台MemCached,使用-x指定对端服务器的地址
./memcached -u root -d -m 128 -x 192.168.116.122
出现以下错误
./memcached: error while loading shared libraries: libevent-2.0.so.5: cannot open shared object file: No such file or directory
解决办法
查找 libevent-2.0.so.5
whereis libevent-2.0.so.5
使用ldd命令查看memcached命令,发现找不到
[root@hsiehchou121 bin]# ldd /root/hd/memcached-1.2.8-repcached-2.2/bin/memcached
linux-gate.so.1 => (0x00255000)
libevent-2.0.so.5 => not found
libc.so.6 => /lib/libc.so.6 (0x00110000)
/lib/ld-linux.so.2(0x003a4000)
建立软连接
ln -s /root/hd/libevent/lib/libevent-2.0.so.5 /usr/lib/libevent-2.0.so.5
2)Memcached的HA(High Availablity)
Keepalived是一个交换机制的软件。Keepalived的作用是检测服务器的状态,如果有一台web服务器死机,或工作出现故障,Keepalived将检测到,并将有故障的服务器从系统中剔除,同时使用其他服务器代替该服务器的工作,当服务器工作正常后Keepalived自动将服务器加入到服务器群中,这些工作全部自动完成,不需要人工干涉,需要人工做的只是修复故障的服务器
利用Keepalived实现MemCached的主主复制高可用架构
Keepalived在memcached主服务器产生一个虚拟IP(VIP)
Keepalived可以通过不断的检测memcached主服务器的11211端口是否正常工作,
如果发现memcached Down机,虚拟IP就从主服务器移到从服务器
配置Keepalived(每台机器都要配置)
rpm -ivh keepalived-1.2.13-4.el6.i686.rpm
配置:主从节点都要配置,配置文件
/etc/keepalived/keepalived.conf
主节点配置信息
! Configuration File for keepalived
global_defs {
notification_email {
417952939@qq.com
}
notification_email_from collen_training@126.com
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id LVS_DEVEL
}
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 101
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.116.88
}
}
从节点配置信息
! Configuration File for keepalived
global_defs {
notification_email {
417952939@qq.com
}
notification_email_from collen_training@126.com
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id LVS_DEVEL
}
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.116.88
}
}
验证Keepalived: 使用命令 ip ad sh
查看虚拟ip地址
inet 192.168.116.88/32 scope global eth0
二、Redis
1、Redis简介
(1)Redis的前身:Memcached
(2)和Memcached区别“
(*)支持持久化:RDB快照、AOF日志
(*)支持丰富的数据类型
2、安装Redis
833 tar -zxvf redis-3.0.5.tar.gz
839 cd redis-3.0.5/
841 make
842 make PREFIX=/root/hd/redis install
redis-benchmark : Redis提供的压力测试工具。模拟产生客户端的压力
redis-check-aof: 检查aof日志文件
redis-check-dump: 检查rdb文件
redis-cli: Redis客户端脚本
redis-sentinel: 哨兵
redis-server: Redis服务器脚本
核心配置文件:redis.conf
[root@hsiehchou121 redis-3.0.5]# cp redis.conf /root/hd/redis/
[root@hsiehchou121 redis]# mkdir conf
[root@hsiehchou121 redis]# mv redis.conf conf/
[root@hsiehchou121 conf]# vi redis.conf
42 daemonize yes //后台方式运行
50 port 6379
启动redis ./bin/redis-server conf/redis.conf
检测是否启动好
[root@hsiehchou121 redis]# ./bin/redis-server conf/redis.conf
3、操作Redis
1)命令行
redis-cli
./bin/redis-cli
127.0.0.1:6379> set key1 value1
OK
127.0.0.1:6379> get key1
“value1”
127.0.0.1:6379> keys *
1) “key1”
对数据的操作:
127.0.0.1:6379> set money 100
OK
127.0.0.1:6379> incr money
(integer) 101
127.0.0.1:6379> get money
“101”
127.0.0.1:6379> incrby money 10000
(integer) 10101
2)数据类型
① 字符串
127.0.0.1:6379> set key1 “hello”
OK
127.0.0.1:6379> get key1
“hello”
127.0.0.1:6379>
127.0.0.1:6379> append key1 “*******
”
(integer) 12
127.0.0.1:6379> get key1
“hello*******
”
② 链表
127.0.0.1:6379>
127.0.0.1:6379> lpush list 11 22 33 44 55
(integer) 5
127.0.0.1:6379> lrange list 0 2
1) “55”
2) “44”
3) “33”
127.0.0.1:6379> lrange list 0 -1
1) “55”
2) “44”
3) “33”
4) “22”
5) “11”
127.0.0.1:6379> lpop list
“55”
③ Hash
127.0.0.1:6379> hset hashkey1 name ls
(integer) 1
127.0.0.1:6379> hset hashkey2 age 23
(integer) 1
127.0.0.1:6379> hmset user001 name ls age 23 gender mals
OK
127.0.0.1:6379> hmset user002 name xz age 24 gender mals
OK
127.0.0.1:6379> hmget user001 name age gender
1) “ls”
2) “23”
3) “mals”
127.0.0.1:6379> hgetall user001
1) “name”
2) “ls”
3) “age”
4) “23”
5) “gender”
6) “mals”
④ 无序集合
无序,不可重复的集合
127.0.0.1:6379> sadd setkey1 11 22 33 44 55
(integer) 5
127.0.0.1:6379> sadd setkey2 33 44 55 66 77 88
(integer) 6
127.0.0.1:6379> smembers setkey1
1) “11”
2) “22”
3) “33”
4) “44”
5) “55”
sdiif: 差集
sinter: 交集
suntion:并集
⑤ 有序集合
有序可以重复的集合,根据一个score来进行排序
127.0.0.1:6379> zadd chinese 90 Tom 92 Nary 83 Nike
(integer) 3
127.0.0.1:6379> zrange chinese 0 100
1) “Nike”
2) “Tom”
3) “Nary”
127.0.0.1:6379> zrange chinese 0 100 withscores
1) “Nike”
2) “83”
3) “Tom”
4) “90”
5) “Nary”
6) “92”
⑥ Redis数据类型案例分析:网站统计用户登录的次数
a. 1亿个用户,有经常登录的,也有不经常登录的
b. 如何来记录用户的登录信息
c. 如何查询活跃用户:比如:一周内,登录3次的
解决方案一:采用关系型数据库
建立表:记录一周内,每天登录的情况
采用关系型数据库保存登录信息存在的问题,每天产生一亿条数据,一周就是7亿条数据
解决方案二:采用Redis存储登录信息
可以使用Redis的setbit,登录与否:有1和0就可以表示
一亿个用户,每天是否登录,用1或者0表示即可,每天产生约12M的数据
一亿个用户一周的登录信息:
12M*7=84M
3)Java Api
① 基本操作
@Test
public void testString(){
Jedis jedis = new Jedis("192.168.116.121",6379);
//添加数据
jedis.set("name","ls");//向key-->name中放入了value-->ls
System.out.println(jedis.get("name"));//执行结果:ls
jedis.append("name"," is my lover");//拼接
System.out.println(jedis.get("name"));//执行结果:ls is my lover
jedis.del("name");//删除某个键
System.out.println(jedis.get("name"));//执行结果:null
//设置多个键值对
jedis.mset("name","tom","age","23","qq","123456789");
jedis.incr("age");//进行加1操作
System.out.println(jedis.get("name") + "-" + jedis.get("age") + "-" + jedis.get("qq"));//执行结果:tom-24-123456789
jedis.disconnect();
}
② 连接池
public class RedisUtils {
private static JedisPool jedisPool = null;
static {
try {
JedisPoolConfig config = new JedisPoolConfig();
//可用连接实例的最大数目,默认值为8 如果赋值为-1,则表示不限制
config.setMaxTotal(1024);
//控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值也是8
config.setMaxIdle(200);
//等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时
config.setMaxWaitMillis(10000);
//在borrow一个jedis实例时,是否提前进行validate操作,如果为true,则得到的jedis实例均是可用的
config.setTestOnBorrow(true);
jedisPool = new JedisPool(config, "192.168.116.121");
}catch (Exception e) {
e.printStackTrace();
}
}
public synchronized static Jedis getJedis(){
try {
if (jedisPool != null)
return jedisPool.getResource();
}catch (Exception e){
e.printStackTrace();
}
return null;
}
public static void returnResource(final Jedis jedis){
if (jedis != null)
jedisPool.returnResource(jedis);
}
}
③ 使用Redis实现分布式锁
使用Maven搭建工程:
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
4、Redis的事务:不是真正的事务,是一种模拟
1)复习:事务(关系型数据库)
(*)什么是事务?
事务有一组DML(Data Manipulation Language)语句组成。DML 插入更新删除操作
(*)事务的特点
要么都成功,要么都失败
(*)Oracle中事务的本质:将事务的DML操作写入日志。日志写入成功,则事务执行成功
2)Redis事务的本质:将一组操作放入队列中,一次执行(批处理)
3)对比Oracle和Redis事务的区别
操作 | Oracle | Redis |
开启事务 | 自动开启 | 命令:multi |
执行语句 | DML | Redis命令 |
提交事务 | 显式提交:commit;隐式提交:DDL语句(create table) | 命令:exec 执行放在multi里面的操作 |
回滚事务 | 显式回滚:rollback;隐式回滚:系统掉电,客户端退出 | 命令:discard 把队列中的操作废弃掉 |
注意:不是真正的事务,只是一种模拟
4)举例:模拟银行转账
set tom 1000
set mike 1000
tom –> mike 转账操作必须在事务中,要么都成功,要么都不成功
multi
decrby tom 100
incrby mike 100
exec
127.0.0.1:6379> set tom 1000
OK
127.0.0.1:6379> set mike 1000
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby tom 100
QUEUED
127.0.0.1:6379> incrby mike 100
QUEUED
127.0.0.1:6379> exec
1) (integer) 900
2) (integer) 1100
5)举例:买票
set tom 1000
set ticket 1
multi
decrby tom 500
decr ticket
exec
在exec前,从另一个窗口,decr ticket
127.0.0.1:6379> set tom 1000
OK
127.0.0.1:6379> set ticket 1
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby tom 500
QUEUED
127.0.0.1:6379> decr ticket
QUEUED
127.0.0.1:6379> exec
1) (integer) 500
2) (integer) -1
5、Redis锁机制
执行事务操作的时候,如果监视的值发生了变化,则提交失败
命令:watch
举例:买票
set tom 1000
set ticket 1
watch ticket —–> 相当于给ticket加了锁。认为在下面执行事务的时候,值不会变
multi
decrby tom 500
decr ticket
exec
127.0.0.1:6379> set tom 1000
OK
127.0.0.1:6379> set ticket 1
OK
127.0.0.1:6379> watch ticket
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby tom 500
QUEUED
127.0.0.1:6379> decr ticket
QUEUED
127.0.0.1:6379> exec
(nil)
127.0.0.1:6379> get tom
“1000”
nil
代表操作没有执行或者执行失败
Java应用程序中的事务和锁
① 事务
@Test
public void testTransaction(){
Jedis jedis = new Jedis("192.168.116.121",6379);
Transaction tc = null;
try{
//开启事务
tc = jedis.multi();
tc.decrBy("tom", 100);
tc.incrBy("mike", 100);
//提交事务
tc.exec();
}catch (Exception e){
e.printStackTrace();
//回滚事务
tc.discard();
}
jedis.disconnect();
}
② 锁
@Test
public void testLock(){
Jedis jedis = new Jedis("192.168.116.121",6379);
//对ticket加锁,如果在事务执行过程中,该值有变化,则抛出异常
jedis.watch("ticket");
Transaction tc = null;
try{
//开启事务
tc = jedis.multi();
tc.decr("ticket");//车票数量减一
Thread.sleep(5000);
tc.decrBy("tom", 100);//扣tom 100块钱买票的钱
//提交事务
tc.exec();
}catch (Exception e){
e.printStackTrace();
//回滚事务
tc.discard();
}
jedis.disconnect();
}
6、Redis的消息机制:消息系统
1)消息的类型
(*)Queue消息:队列,点对点
(*)Topic消息:主题,群发:发布消息,订阅消息
2)Redis消息机制
只支持Topic消息
命令:发布消息 publish 格式:publish channel名称 “消息内容”
订阅:subscribe 格式:subscribe channel名称
psubscribe 订阅消息 —— 可以用通配符来订阅消息
格式:psubscribe channel*名称
3)常用的消息系统:
Redis 只支持 Topic
Kafka 只支持Topic 需要Zookeeper支持
JMS Java Messging Service java消息服务标准。支持Queue Topic
产品:Weblogic
例子:
窗口1(发):
127.0.0.1:6379> PUBLISH c1 hello
(integer) 2
127.0.0.1:6379> PUBLISH c1 test
(integer) 2
窗口2(订):
127.0.0.1:6379> SUBSCRIBE c1
Reading messages… (press Ctrl-C to quit)
1) “subscribe”
2) “c1”
3) (integer) 1
1) “message”
2) “c1”
3) “hello”
1) “message”
2) “c1”
3) “test”
窗口3(订):
127.0.0.1:6379> SUBSCRIBE c1
Reading messages… (press Ctrl-C to quit)
1) “subscribe”
2) “c1”
3) (integer) 1
1) “message”
2) “c1”
3) “hello”
1) “message”
2) “c1”
3) “test”
通过通配符订阅
窗口1(发):
127.0.0.1:6379> PUBLISH c2 hello
(integer) 1
127.0.0.1:6379> PUBLISH c4 hello
(integer) 1
窗口2(发):
127.0.0.1:6379> PUBLISH c1 dfg
(integer) 1
窗口3(订):
127.0.0.1:6379> PSUBSCRIBE c*
Reading messages… (press Ctrl-C to quit)
1) “psubscribe”
2) “c*”
3) (integer) 1
1) “pmessage”
2) “c*”
3) “c2”
4) “hello”
1) “pmessage”
2) “c*”
3) “c4”
4) “hello”
1) “pmessage”
2) “c*”
3) “c1”
4) “dfg”
使用Java程序实现消息的发布与订阅
需要继承JedisPubSub类
@Test
public void testMessage(){
Jedis jedis = new Jedis("192.168.116.121", 6379);
//subscribe和psubcribe不能同时订阅
jedis.subscribe(new MyListener(), "channel");
//jedis.psubscribe(new MyListener(), "channel*");
}
class MyListener extends JedisPubSub{
public void onMessage(String channel, String message){
System.out.println("onMessage channel is " + channel + " message is " + message);
}
public void onPMessage(String pattern, String channel, String message){
System.out.println("onPMessage channel is " + pattern);
System.out.println("onPMessage channel is " + channel);
System.out.println("onPMessage message is " + message);
}
public void onPSubscribe(String arg0, int arg1){}
public void onPUnsubscribe(String arg0, int arg1){}
public void onSubscribe(String arg0, int arg1){}
public void onUnsubscribe(String arg0, int arg1){}
}
7、Redis持久化
本质:备份和恢复
1)RDB快照:默认
(*)看成一种快照,备份。每隔段时间,将内存汇总的数据保存到硬盘上。产生RDB文件
(*)RDB 生成策略
redis.conf中
147 save 900 1 900秒内,有1个key发生变化,执行RDB
148 save 300 10 300内,如果有10个key发生变化,执行RDB
149 save 60 10000 60秒内,如果有10000个key发生变化,执行RDB
save —- 时间 —– 发生变化的key的个数
(*)其他参数
164 stop-writes-on-bgsave-error yes 当后台写进程出错时,禁止写入新的数据
170 rdbcompression yes 是否压缩。如果看重性能,设置成no
压缩会节省空间,但会影响备份和恢复性能
182 dbfilename dump.rdb RDB的文件名字
192 dir ./ RDB的文件地址
(*)RDB的优点和缺点
优点:快,恢复速度快
缺点:在两次RDB之间,可能会造成数据的丢失
解决:AOF
2)AOF日志
客户端在操作Redis时,把操作记录到文件中,如果发生崩溃,读取日志,把操作完全执行一遍
(*)默认是禁用
509 appendonly no 参数修改成yes
(*)AOF记录策略
538 # appendfsync always 每条操作都记录日志:优点安全 缺点:慢
539 appendfsync everysec 每秒写入一次
540 # appendfsync no 由操作系统来决定记录日志的方式。不会用的到。
(*)AOF日志重写:overwrite
举例:
set money 0
incr money
..100次
set money 100
./redis-benchmark -n 100000
模拟客户端100000次请求
(*)参数设置
561 no-appendfsync-on-rewrite no 执行重写的时候,不写入新的aof日志
//561 no-appendfsync-on-rewrite yes 生成rdb的时候,是否不写入aof
580 auto-aof-rewrite-percentage 100 aof文件比上次重写时,超过的百分比
581 auto-aof-rewrite-min-size 64mb 执行重写的文件大小。到64M触发重写
3)当两个同时存在时,优先执行哪个?
504 # If the AOF is enabled on startup Redis will load the AOF, that is the file
505 # with the better durability guarantees.
AOF开启时,优先使用AOF
8、Redis的主从复制
1)Redis主从复制集群
作用:
主从复制,主从备份,防止主节点down机
任务分离:分摊主节点压力。读写分离
Memcacached:主主复制
Redis:主从复制
Redis集群两种部署方式
星型模型:
优点:效率高,两个slave地位一样,可以直接从主节点取出信息
缺点:HA比较麻烦
线性模型:
优点:HA简单,master宕机后,可以直接切换到slave1
缺点:效率不如星型模型
cp redis.conf redis6379.conf
cp redis.conf redis6380.conf
cp redis.conf redis6381.conf
主节点(redis6379.conf ):关闭rdb aof
509 appendonly no
147 #save 900 1
148 #save 300 10
149 #save 60 10000
从节点(redis6380.conf redis6381.conf)
不同机器有的可以不改
改端口号
50 port 6380
改aof rdb文件名:
182 dbfilename dump6380.rdb
211 slaveof 192.168.116.121 6379
513 appendfilename “appendonly6380.aof”
改端口号
50 port 6381
改aof rdb文件名:
182 dbfilename dump6381.rdb
211 slaveof 192.168.116.121 6379
513 appendfilename “appendonly6381.aof”
[]root@hsiehchou121 redis]# ./bin/redis-server ./conf/redis6379.conf
[root@hsiehchou121 redis]# ./bin/redis-server ./conf/redis6380.conf
[root@hsiehchou121 redis]# ./bin/redis-server ./conf/redis6381.conf
[root@hsiehchou121 redis]# ps -ef | grep redis
root 6371 1 1 16:31 ? 00:00:00 ./bin/redis-server *:6379
root 6375 1 4 16:31 ? 00:00:01 ./bin/redis-server *:6380
root 6381 1 0 16:31 ? 00:00:00 ./bin/redis-server *:6381
root 6395 5432 0 16:31 pts/0 00:00:00 grep –color=auto redis
[root@hsiehchou121 redis]# ./bin/redis-cli -p 6379
127.0.0.1:6379> set tom 10000
OK
127.0.0.1:6379> quit
[root@hsiehchou121 redis]# ./bin/redis-cli -p 6380
127.0.0.1:6380> get tom
“10000”
默认情况下,从节点只读,不可以写入数据
注意:一次性启动从节点不要太多
2)Redis的分片
多个从节点分摊读的压力
客户端代理分片工具:Twemproxy
解压
[root@hsiehchou121 nutcracker-0.3.0]# ./configure --prefix
=/root/hd/nutcracker
[root@hsiehchou121 nutcracker-0.3.0]# make
[root@hsiehchou121 nutcracker-0.3.0]# make install
cp /root/hd/nutcracker-0.3.0/conf/nutcracker.yml ./conf/
修改server信息
alpha:
listen: 127.0.0.1:22121
hash: fnv1a_64
distribution: ketama
auto_eject_hosts: true
redis: true
server_retry_timeout: 2000
server_failure_limit: 1
servers:
- 192.168.116.121:6380:1
- 192.168.116.121:6381:1
启动redis
[root@hsiehchou121 redis]# ./bin/redis-server ./conf/redis6379.conf
[root@hsiehchou121 redis]# ./bin/redis-server ./conf/redis6380.conf
[root@hsiehchou121 redis]# ./bin/redis-server ./conf/redis6381.conf
检查配置文件是否正确
[root@hsiehchou121 nutcracker]# ./sbin/nutcracker -t conf/nutcracker.yml
启动代理分片
[root@hsiehchou121 nutcracker]# ./sbin/nutcracker -d -c conf/nutcracker.yml
[root@hsiehchou121 redis]# ./bin/redis-cli -p 22121 访问
9、Redis的HA(哨兵机制)
主从结构,存在单点故障问题
redis2.4版本之后有
redis-sentinel 就是哨兵
vi redis6380.conf
211 slaveof 192.168.116.121 6379
vi redis6381.conf
211 slaveof 192.168.116.121 6379
配置:
cp /root/hd/redis-3.0.5/sentinel.conf ./conf/
vim sentinel.conf
53 sentinel monitor mymaster 192.168.116.121 6379 1
[root@hsiehchou121 redis]# ./bin/redis-sentinel conf/sentinel.conf
看日志:
3085:X 23 Apr 17:04:17.522 # +monitor master mymaster 192.168.116.121 6379 quorum 1
3085:X 23 Apr 17:04:18.524 * +slave slave 192.168.116.121:6380 192.168.116.121 6380 @ mymaster 192.168.116.121 6379
3085:X 23 Apr 17:04:18.526 * +slave slave 192.168.116.121:6381 192.168.116.121 6381 @ mymaster 192.168.116.121 6379
kill master 检测到
看日志:
try-failover master mymaster 192.168.109.134 6379
检测到6379挂了
3085:X 23 Apr 17:05:14.647 # +selected-slave slave 192.168.116.121:6381 192.168.116.121 6381 @ mymaster 192.168.116.121 6379
select slave 选举新的主节点
3085:X 23 Apr 17:05:16.830 * +slave slave 192.168.116.121:6380 192.168.116.121 6380 @ mymaster 192.168.116.121 6381
把其他的从节点连接到主节点上
注意:一定要按步骤来,一步一步配置
亲测排坑
划重点
此处的Redis的HA高可用的redis主节点和从节点的变化会导致sentinel monitor mymaster(sentinel.conf的第53行)和slaveof一起变化(从节点的第211行)。而且这个过程是不可逆的,就是更新了变只有自己手动去修改下。
所以,如果停止重新运行,便会报错,需要自己自行修改这些内容。