内存数据库专题(MemCached 和Redis)

内存数据库专题

为什么要把数据存入内存?

常见的内存数据库:
MemCached:看成Redis前身,严格来说,MemCached不能叫数据库,只能叫缓存
不支持持久化。如果内存停电,数据丢失

Redis:内存数据库,支持持久化,支持HA

Oracle TimesTen

session一致性

MemCached + keepalive实现

一、Memcached

1、基本原理和体系架构

(*)在内存中,维护了一张巨大的Hash表
(*)通过路由算法来决定数据存储的位置。—> 客户端路由

Memcached基本原理和体系架构

Memcached基本原理和体系架构.

注意:默认,官方版本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
  1. 安装具有复制功能的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”

默认情况下,从节点只读,不可以写入数据

注意:一次性启动从节点不要太多

Redis 主从服务的通信原理

Redis 主从服务的通信原理

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行)。而且这个过程是不可逆的,就是更新了变只有自己手动去修改下。

所以,如果停止重新运行,便会报错,需要自己自行修改这些内容。

posted @ 2019-04-23 17:50  hsiehchou  阅读(378)  评论(0编辑  收藏  举报