redis原理和使用

redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hashs(哈希类型)
这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的.
在此基础上,redis支持各种不同方式的排序.与memcached一样,为了保证效率,数据都是缓存在内存中.
区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步.
 
Redis的优点:
 
性能极高 – Redis能支持超过 100K+ 每秒的读写频率。
丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
原子 – Redis的所有操作都是原子性的,同时Redis还支持对几个操作全并后的原子性执行。
丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。
 
下面是官方的bench-mark数据:
测试完成了 50 个并发执行 100000 个请求。
设置和获取的值是一个 256 字节字符串。
Linux box是运行Linux 2.6 ,这是X3320 Xeon 2.5 ghz。
文本执行使用loopback接口( 127.0 . 0.1 )。
结果:写的速度是 110000 次/s,读的速度是 81000 次/s 。

Redis与其他key-value存储有什么不同?

Redis有着更为复杂的数据结构并且提供对他们的原子性操作,这是一个不同于其他数据库的进化路径。Redis的数据类型都是基于基本数据结构的同时对程序员透明,无需进行额外的抽象。

Redis运行在内存中但是可以持久化到磁盘,所以在对不同数据集进行高速读写时需要权衡内存,应为数据量不能大于硬件内存。在内存数据库方面的另一个优点是,相比在磁盘上相同的复杂的数据结构,在内存中操作起来非常简单,这样Redis可以做很多内部复杂性很强的事情。同时,在磁盘格式方面他们是紧凑的以追加的方式产生的,因为他们并不需要进行随机访问。


 
===================redis使用说明:
1 .cmd中启动
D:\Redis>redis-server.exe redis.conf
2 .执行命令:
D:\Redis>redis-cli.exe -h 172.16 . 147.121 -p 6379
3 .设置数值:
redis 172.16 . 147.121 : 6379 > set city Shanghai
4 .获取数值:
redis 172.16 . 147.121 : 6379 > get city
====================
using ServiceStack.Redis;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
 
namespace redis
{
     public partial class Form1 : Form
     {
         RedisClient redisClient = null ;
         public Form1()
         {
             InitializeComponent();
         }
 
         private void button1_Click(object sender, EventArgs e)
         {
             redisClient = new RedisClient( "localhost" , 6379 ); //redis服务IP和端口
         }
 
         private void button2_Click(object sender, EventArgs e)
         {
             redisClient.Add<string>( "name" , "郭泽峰" );
         }
 
         private void button3_Click(object sender, EventArgs e)
         {
             MessageBox.Show(redisClient.Get<string>( "name" ));
         }
     }
}
 
==========jedis:
   //连接redis服务器,192.168.0.100:6379
  19         jedis = new Jedis( "192.168.0.100" , 6379 );
  20         //权限认证
  21         jedis.auth( "admin" ); 
   jedis.set( "name" , "xinxin" ); //向key-->name中放入了value-->xinxin 
  31         System.out.println(jedis.get( "name" )); //执行结果:xinxin 
===主从监视器:sentinels
 
   JedisPoolConfig poolConfig = new JedisPoolConfig();
12         String masterName = "mymaster" ;
13         Set<String> sentinels = new HashSet<String>();
14         sentinels.add( "192.168.1.97:26379" );
15         sentinels.add( "192.168.1.96:26379" );
16         JedisSentinelPool jedisSentinelPool = new JedisSentinelPool(masterName, sentinels, poolConfig);
17         HostAndPort currentHostMaster = jedisSentinelPool.getCurrentHostMaster();
18         System.out.println(currentHostMaster.getHost()+ "--" +currentHostMaster.getPort()); //获取主节点的信息
19         Jedis resource = jedisSentinelPool.getResource();
20         String value = resource.get( "a" );
21         System.out.println(value); //获得键a对应的value值
22         resource.close();
23     }
 
================
JedisPoolConfig poolConfig = new JedisPoolConfig();
12         Set<HostAndPort> nodes = new HashSet<HostAndPort>();
13         HostAndPort hostAndPort = new HostAndPort( "192.168.1.99" , 7000 );
14         HostAndPort hostAndPort1 = new HostAndPort( "192.168.1.99" , 7001 );
15         HostAndPort hostAndPort2 = new HostAndPort( "192.168.1.99" , 7002 );
16         HostAndPort hostAndPort3 = new HostAndPort( "192.168.1.99" , 7003 );
17         HostAndPort hostAndPort4 = new HostAndPort( "192.168.1.99" , 7004 );
18         HostAndPort hostAndPort5 = new HostAndPort( "192.168.1.99" , 7005 );
19         nodes.add(hostAndPort);
20         nodes.add(hostAndPort1);
21         nodes.add(hostAndPort2);
22         nodes.add(hostAndPort3);
23         nodes.add(hostAndPort4);
24         nodes.add(hostAndPort5);
25         JedisCluster jedisCluster = new JedisCluster(nodes, poolConfig); //JedisCluster中默认分装好了连接池.
26         //redis内部会创建连接池,从连接池中获取连接使用,然后再把连接返回给连接池
27         String string = jedisCluster.get( "a" );
28         System.out.println(string);           
=======================================

  


reids存储类型:string list hash set sortedset.
高速缓存数据库。
缓存,数据缓存,页面缓存。

====redis优:

1.支持多数据类型,
2.支持主从模式
3.支持持久化
4.单个value限制是1GB,memcached为1M数据。

=================

redis可以做存储。

redis-server ./redis.conf 打开redis。
./redis-cli -h 172.17.5.20 -p 6379
10: 让redis以后台进程的形式运行
编辑conf配置文件,修改如下内容;

daemonize yes

==命令:
set key value;
del key1 key2 ... Keyn
rename key newkey(newkey已存在则会被覆盖)
renamenx key newkey (不存在才改变)返回0 失败

keys *

keys s* 模糊查询;
keys sit[ey] e后者
有3个通配符 *, ? ,[]
*: 通配任意多个字符
?: 通配单个字符
[]: 通配括号内的某1个字符

redis默认创建16个数据库:(0-15)
---databases 16 默认16个数据库

select 1 选择1号数据库。
select 0 选择2号数据库
---移动一个key到2号数据库。
move cc 2
----默认有效期:永久,但也可以设置有效期。

--
randomkey 返回随机key
exists key
判断key是否存在,返回1/0
type key
返回key存储的值的类型
有string,link,set,order set, hash

----查询有效期:
ttl key (-1:永久)(-2:不存在)(生命周期,以秒为单位)

expire key 10 设置10,10秒后消失。

---设置毫秒为生命周期:
pexpire key 毫秒数, 设置生命周期
pttl key, 以毫秒返回生命周期
---
persist key
作用: 把指定key置为永久有效

==============字符串操作相关:

set key val 返回nil 失败。

set key value [ex 秒数] / [px 毫秒数] [nx] /[xx]

如: set a 1 ex 10 , 10秒有效
Set a 1 px 9000 , 9秒有效
注: 如果ex,px同时写,以后面的有效期为准
如 set a 1 ex 100 px 9000, 实际有效期是9000毫秒

nx: 表示key不存在时,执行操作
xx: 表示key存在时,执行操作

-----
mset multi set , 一次性设置多个键值:

例: mset key1 v1 key2 v2 ....
mget key1 key2 ..keyn
作用:获取多个key的值

---
flushdb 清空

----偏移:s
setrange key offset value

比如 hellow setrange key offset 2 xx hexxow 就是从索引2开始替换,把xx填充并替换原来的.
-----
append key value
作用: 把value追加到key的原值上
--
'chinese'
getrange title 0 3 返回chin
----
getset key newvalue
作用: 获取并返回旧值,设置新值
--
incr key
作用: 指定的key的值加1,并返回加1后的值

---秒杀活动,比如1000部手机,1000个并发后,利用1000 decre ,之后用户获取资格,然后通过队列去下单。
---一次性增长number.
incrby key number
decrby key number
---增长浮点数
incrbyfloat key floatnumber
incrbyfloat age 3.5
---操作位(可以将大写变小写,差32位)
setbit key offset value
getbit key offset

=================link相关:链表:(l:头,r:尾)
lpush key value value2 value3, 注意:如果是lpush,顺序是倒序的。
作用: 把值插入到链接头部

rpop key
作用: 返回并删除链表尾元素

rpush,lpop: 不解释

lrange key start stop
作用: 返回链表中[start ,stop]中的元素
规律: 左数从0开始,右数从-1开始
===
lrem key count value
lrem key count value
作用: 从key链表中删除 value值
注: 删除count的绝对值个value后结束
Count>0 从表头删除
Count<0 从表尾删除

lrem key -2 a 从尾部删除两个a

-----------

ltrim key start stop
作用: 剪切key对应的链接,切[start,stop]一段,并把该段重新赋给key
lindex key index
作用: 返回index索引上的值,
如 lindex key 2
llen key
作用:计算链接表的元素个数
linsert key after|before search value
作用: 在key链表中寻找’search’,并在search值之前|之后,.插入value
注: 一旦找到一个search后,命令就结束了,因此不会插入多个value
比如:12345
linsert key before 3 0
120345

找不到返回-1;
--若果有多个,那只会插入第一个,就结束了。

----(source和dest是两个link),这个操作时原子性的。******************

rpoplpush source dest 返回移动的值。
作用: 把source的尾部拿出,放在dest的头部,
---
这个很有用,可以用做安全队列:
比如有两个链表,消费链表link 和备份链表bak
1.我们把消费订单存入link,
2.进行业务操作的时候,利用rpoplpush,拿到处理的订单编号进行处理,一旦成功,我们就把bak中删除(lpop bak),如果失败,我们继续从bak取出进行处理(rpop bak)--逐个处理错误item。

-----
brpop ,blpop key timeout
作用:等待弹出key的尾/头元素,
Timeout为等待超时时间
如果timeout为0,则一直等待

场景: 长轮询Ajax,在线聊天时,能够用到

====如果统计1亿用户周活跃数,比如一周登录4次的用户,我们就可以利用redis 位操作来实现:
用户登录1,未登录0.userid得到位的索引,
setbit mon=1000000000000001
setbit mon 3 1 将3用户设置为登录
.
.
.
每周都会产生一个1亿的位,
最后统计:
bittop add mon fe thr 累加得到一个数字,拿这个数字判断第几个位就可以得到登录次数;

------set:

集合 set 相关命令

集合的性质: 唯一性,无序性,确定性

注: 在string和link的命令中,可以通过range 来访问string中的某几个字符或某几个元素
但,因为集合的无序性,无法通过下标或范围来访问部分元素.
因此想看元素,要么随机先一个,要么全选.
smembers key
作用: 返回集中中所有的元素
srem value1 value2
作用: 删除集合中集为 value1 value2的元素
返回值: 忽略不存在的元素后,真正删除掉的元素的个数
srandmember key (不删除)
作用: 返回集合key中,随机的1个元素.
spop key
作用: 返回并删除集合中key中1个随机元素
随机--体现了无序性

sismember key value
作用: 判断value是否在key集合中
是返回1,否返回0
scard key
作用: 返回集合中元素的个数

move source dest value
作用:把source中的value删除,并添加到dest集合中
sinter key1 key2 key3
作用: 求出key1 key2 key3 三个集合中的交集,并返回
sinterstore dest key1 key2 key3
作用: 求出key1 key2 key3 三个集合中的交集,并赋给dest

suion key1 key2.. Keyn
作用: 求出key1 key2 keyn的并集,并返回

sdiff key1 key2 key3
作用: 求出key1与key2 key3的差集
即key1-key2-key3

==================有序set:添加权重score来排序:
order set 有序集合
zadd key score1 value1 score2 value2 ..
添加元素

redis 127.0.0.1:6379> zadd stu 18 lily 19 hmm 20 lilei 21 lilei
(integer) 3

-------------------------


---排名start到排名stop(数字位第几名,区分)
ZRANGE key start stop [WITHSCORES]
把集合排序后,返回名次[start,stop]的元素
默认是升续排列

--
zrangebyscore key min max [withscores] limit offset N
作用: 集合(升续)排序后,取score在[min,max]内的元素,
并跳过 offset个, 取出N个
zrangebyscore stu 3 12 limit 1 2 withscores
---withscores 把score也当成item打印出来:

---查询名次:(升序)
rank key member
查询member的排名(升续 0名开始)
---降序查询名次:
zrevrank key memeber
--------------
zrem key value1 value2 ..
作用: 删除集合中的元素

zremrangebyscore key min max
作用: 按照socre来删除元素,删除score在[min,max]之间的
redis 127.0.0.1:6379> zremrangebyscore stu 4 10
zremrangebyrank key start end
作用: 按排名删除元素,删除名次在[start,end]之间的
redis 127.0.0.1:6379> zremrangebyrank stu 0 1
----
zremrangebyrank key start end
作用: 按排名删除元素,删除名次在[start,end]之间的
redis 127.0.0.1:6379> zremrangebyrank stu 0 1
---
zcard key
返回元素个数

zcount key min max
返回[min,max] 区间内元素的数量

---------------切记[min,max],中括号也包括min和max的。

------numkeys:待求交集的数量,比如求key1和key2的交集则numkeys为2;
zinterstore destination numkeys key1 [key2 ...]
[WEIGHTS weight [weight ...]]
[AGGREGATE SUM|MIN|MAX]
求key1,key2的交集,key1,key2的权重分别是 weight1,weight2
聚合方法用: sum |min|max
聚合的结果,保存在dest集合内
注意: weights ,aggregate如何理解?
答: 如果有交集, 交集元素又有socre,score怎么处理?
Aggregate sum->score相加 , min 求最小score, max 最大score

另: 可以通过weigth设置不同key的权重, 交集时,socre * weights

-----------------------------Hash 哈希数据类型相关命令
hset key field value
作用: 把key中 filed域的值设为value
注:如果没有field域,直接添加,如果有,则覆盖原field域的值

----多个:

hmset key field1 value1 [field2 value2 field3 value3 ......fieldn valuen]
hmget key field1 field2 fieldN
作用: 返回key中field1 field2 fieldN域的值
hgetall key
作用:返回key中,所有域与其值
hdel key field
作用: 删除key中 field域
hlen key
作用: 返回key中元素的数量
hexists key field
作用: 判断key中有没有field域

------让值增加小数点。
hinrby key field value
作用: 是把key中的field域的值增长整型值value
hinrby float key field value
作用: 是把key中的field域的值增长浮点值value
hkeys key
作用: 返回key中所有的field
kvals key
作用: 返回key中所有的value

====
Redis 中的事务

Redis支持简单的事务

Redis与 mysql事务的对比

Mysql Redis
开启 start transaction muitl
语句 普通sql 普通命令
失败 rollback 回滚 discard 取消
成功 commit exec

注: rollback与discard 的区别
如果已经成功执行了2条语句, 第3条语句出错.
Rollback后,前2条的语句影响消失.
Discard只是结束本次事务,前2条语句造成的影响仍然还在
====原理:
muitl,s原理先放到queued队列中,exec之后再执行。
放入队列中时,只是检查语法的正确性,并没有检查类型啊(不如在数字上累加字母),
Exec之后,会执行正确的语句,并跳过有不适当的语句.根本不会回滚。
=====

注:
在mutil后面的语句中, 语句出错可能有2种情况
1: 语法就有问题,
这种,exec时,报错, 所有语句得不到执行

2: 语法本身没错,但适用对象有问题. 比如 zadd 操作list对象
Exec之后,会执行正确的语句,并跳过有不适当的语句.

(如果zadd操作list这种事怎么避免? 这一点,由程序员负责)


思考:
我正在买票
Ticket -1 , money -100
而票只有1张, 如果在我multi之后,和exec之前, 票被别人买了---即ticket变成0了.
我该如何观察这种情景,并不再提交

悲观的想法:
世界充满危险,肯定有人和我抢, 给 ticket上锁, 只有我能操作. [悲观锁]

乐观的想法:
没有那么人和我抢,因此,我只需要注意,
--有没有人更改ticket的值就可以了 [乐观锁]

Redis的事务中,启用的是乐观锁,只负责监测key没有被改动.
具体的命令---- watch命令
例:
redis 127.0.0.1:6379> watch ticket
OK
redis 127.0.0.1:6379> multi
OK
redis 127.0.0.1:6379> decr ticket
QUEUED
redis 127.0.0.1:6379> decrby money 100
QUEUED
redis 127.0.0.1:6379> exec
(nil) // 返回nil,说明监视的ticket已经改变了,事务就取消了.
redis 127.0.0.1:6379> get ticket
"0"
redis 127.0.0.1:6379> get money
"200"

watch 可以监视多个key,只要有一个变化,就取消事务
watch key1 key2 ... keyN
作用:监听key1 key2..keyN有没有变化,如果有变, 则事务取消

unwatch
作用: 取消所有watch监听

=======================
使用办法:
订阅端: Subscribe 频道名称
发布端: publish 频道名称 发布内容
客户端例子:
redis 127.0.0.1:6379> subscribe news
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "news"
3) (integer) 1
1) "message"
2) "news"
3) "good good study"
1) "message"
2) "news"
3) "day day up"
服务端例子:
redis 127.0.0.1:6379> publish news 'good good study'
(integer) 1
redis 127.0.0.1:6379> publish news 'day day up'
(integer) 1

=========

Redis持久化配置

Redis的持久化有2种方式 1快照(rdb) 2是日志

Rdb快照的配置选项:(rdbdump):优势,因为是快照,所以恢复速度相当快。
(原理:每隔n分钟或N次写入后从内存dump数据形成rdb文件压缩,放至到目录上。)


save 900 1 // 900内,有1条写入,则产生快照
save 300 1000 // 如果300秒内有1000次写入,则产生快照
save 60 10000 // 如果60秒内有10000次写入,则产生快照

(这3个选项都屏蔽,则rdb禁用)
---时间和更改频率来形成梯形的dump方案。

新版本由新的进程导出版本.


stop-writes-on-bgsave-error yes // 后台备份进程出错时,主进程停不停止写入? (rdb的导入进程出错了,redis停止写入)

rdbcompression yes // 导出的rdb文件是否压缩

Rdbchecksum yes // 导入rbd恢复时数据时,要不要检验rdb的完整性:

dbfilename dump.rdb //导出来的rdb文件名

dir ./ //rdb的放置路径

-------保存条件:1分钟,5分钟,15分钟才保存,所以不在里面做的修改,断电等
故障都会丢失。

-------rdb的缺点,时间间隔内容易造成数据丢失。


---为了更精准,新版本增加了aof日志持久化。如下:是(append)


Aof 的配置 主要是 only append file.

 

--rdb原理,rdb导出进程,根据配置导出rdb的条件设置,定期的导出rdb快照,容易丢失,但恢复快照比较快
--aof原理,每执行一个命令,aof进程都会将命令记录到txt文档中。
写txt会严重拖慢redis。

appendonly no # 是否打开 aof日志功能(yes:打开)

appendfsync always # 每1个命令,都立即同步到aof. 安全,速度慢
appendfsync everysec # 折衷方案,每秒写1次-----最佳方案***************8
appendfsync no # 写入工作交给操作系统,由操作系统判断缓冲区大小,统一写入到aof. 同步频率低,速度快,

no-appendfsync-on-rewrite yes: # 正在导出rdb快照的过程中,要不要停止同步aof
auto-aof-rewrite-percentage 100 #aof文件大小比起上次重写时的大小,增长率100%时,重写
auto-aof-rewrite-min-size 64mb #aof文件,至少超过64M时,重写
===
注: 在dump rdb过程中,aof如果停止同步,会不会丢失?
答: 不会,所有的操作缓存在内存的队列里, dump完成后,统一操作.
注: aof重写是指什么?

答: aof重写是指把内存中的数据,逆化成命令,写入到.aof日志里.
以解决 aof日志过大的问题.(因为对同一key value操作的步骤比较多,日志比较多,但内存中就有一个最终的状态,所以重写成简单一次性命令
比如最终set key value.降低文件的大小。

auto-aof-rewrite-percentage 100 #aof文件大小比起上次重写时的大小,增长率100%时,重写
auto-aof-rewrite-min-size 64mb #aof文件,至少超过64M时,重写


问: 如果rdb文件,和aof文件都存在,优先用谁来恢复数据?
答: aof
问: 2种是否可以同时用?
答: 可以,而且推荐这么做
问: 恢复时rdb和aof哪个恢复的快
答: rdb快,因为其是数据的内存映射,直接载入到内存,而aof是命令,需要逐条执行

----redis两种持久化同时配置,最终,可能会丢失1s的数据。


====================redis集群:
集群优点:
1.主从备份,防止主机宕机。
2.读写分离,分担master的任务。
3.任务分离,分担工作与计算。
----
方案:
1.master下面有两个孩子,两个孩子直接指向master(树).
2.线性,第一个孩子指向master,第二个孩子指向第一个孩子.

原理:
主从通信:slave启动之后链接master,slave发出同步命令,save拿到dump出的rdb
快照,之后再拿缓冲aof队列中的日志数据进行数据填充。

---master配置:
1.关闭rdb快照(备份工作交给slave)
2.可以开启aof

slave配置:
1.声明slave-of (slave-of localhsot 6379)
2.如果master有密码,slave也要有密码
3.打开rdb快照
4.配置是否只读[salve-read-only]

---主;
passwordrequire 密码
--slave
masterauth 密码

=============主从缺点:
每次slave断开后,无论是主动断开还是网络故障,再链接master,
都要master全部dump导出rdb再aof.
所以,启动slave要一个一个启动,且有时间间隔。要不然
master主IO剧增。

============
redis 服务器端命令
redis 127.0.0.1:6380> time ,显示服务器时间 , 时间戳(秒), 微秒数
1) "1375270361"
2) "504511"

redis 127.0.0.1:6380> dbsize // 当前数据库的key的数量 当前库,并不是当前服务器
(integer) 2
redis 127.0.0.1:6380> select 2 //选择库:
OK
redis 127.0.0.1:6380[2]> dbsize
(integer) 0
redis 127.0.0.1:6380[2]>


BGREWRITEAOF 后台进程重写AOF
BGSAVE 后台保存rdb快照—后台单起一个进程。
SAVE 保存rdb快照----当前进程,需要等待。
LASTSAVE 上次保存时间

Slaveof master-Host port , 把当前实例设为master的slave

Flushall 清空所有库所有键
Flushdb 清空当前库所有键---n号数据库
Showdown [save/nosave]

注: 如果不小心运行了flushall, 立即 shutdown nosave ,关闭服务器(shutdown会重写aof,所以加上nosave)
然后 手工编辑aof文件, 去掉文件中的 “flushall ”相关行, 然后开启服务器,就可以导入回原来数据.

如果,flushall之后,系统恰好bgrewriteaof了,那么aof就清空了,数据丢失.

Slowlog 显示慢查询
注:多慢才叫慢?
答: 由slowlog-log-slower-than 10000 ,来指定,(单位是微秒)

服务器储存多少条慢查询的记录?
答: 由 slowlog-max-len 128 ,来做限制

Info [Replication/CPU/Memory..]
查看redis服务器的信息

Config get 配置项
Config set 配置项 值 (特殊的选项,不允许用此命令设置,如slave-of, 需要用单独的slaveof命令来设置)

Redis运维时需要注意的参数
1: 内存
# Memory
used_memory:859192 数据结构的空间
used_memory_rss:7634944 实占空间
mem_fragmentation_ratio:8.89 前2者的比例,1.N为佳,如果此值过大,说明redis的内存的碎片化严重,可以导出再导入一次.
2: 主从复制
# Replication
role:slave
master_host:192.168.1.128
master_port:6379
master_link_status:up

3:持久化
# Persistence
rdb_changes_since_last_save:0
rdb_last_save_time:1375224063

4: fork耗时
#Status
latest_fork_usec:936 上次导出rdb快照,持久化花费微秒
注意: 如果某实例有10G内容,导出需要2分钟,
每分钟写入10000次,导致不断的rdb导出,磁盘始处于高IO状态.


5: 慢日志
config get/set slowlog-log-slower-than
CONFIG get/SET slowlog-max-len
slowlog get N 获取慢日志


运行时更改master-slave

修改一台slave(设为A)为new master
1) 命令该服务不做其他redis服务的slave
命令: slaveof no one
2) 修改其readonly为yes
命令:config set slave-read-only no
config get slave-read-only

其他的slave再指向new master A
1) 命令该服务为new master A的slave
命令格式 slaveof IP port

====

quit //关闭客户端.

==redis复制

save一下:

rdb文件复制,后配置redis.conf文件 rdb文件路径指向,重启就可以了.
注意:复制的时候,一定保证reb文件不被占用,停掉redis.

-------------copy bin下面sentinel.conf.

sentinel主要是监控主从redis是否运行正常,不正常切换主从.


sentinel监控主从原理:监控主redis,如果不回应出现问题,就会将slave设为master.
其他slave指向它。

Sentinel不断与master通信,获取master的slave信息.
监听master与slave的状态
如果某slave失效,直接通知master去除该slave.

如果master失效,,是按照slave优先级(可配置), 选取1个slave做 new master
,把其他slave--> new master

疑问: sentinel与master通信,如果某次因为master IO操作频繁,导致超时,
此时,认为master失效,很武断.
解决: sentnel允许多个实例看守1个master, 当N台(N可设置)sentinel都认为master失效,才正式失效.

Sentinel选项配置
port 26379 # 端口
sentinel monitor mymaster 127.0.0.1 6379 2 ,
给主机起的名字(不重即可),
当2个sentinel实例都认为master失效时,正式失效

sentinel down-after-milliseconds mymaster 30000 多少毫秒后连接不到master认为断开
sentinel can-failover mymaster yes #是否允许sentinel修改slave->master. 如为no,则只能监控,无权修改./
sentinel parallel-syncs mymaster 1 , 一次性修改几个slave指向新的new master.(一次性都指向,会
造成masterd umprdb和aof日志文件io读写,所以一台一台改)
sentinel client-reconfig-script mymaster /var/redis/reconfig.sh ,# 在重新配置new master,new slave过程,可以触发的脚本

启动:./redis-server ./sentinel.conf --sentinel

==========
Redis key 设计技巧

1: 把表名转换为key前缀 如, tag:
2: 第2段放置用于区分区key的字段--对应mysql中的主键的列名,如userid
3: 第3段放置主键值,如2,3,4...., a , b ,c
4: 第4段,写要存储的列名

用户表 user , 转换为key-value存储
userid username passworde email
9 Lisi 1111111 lisi@163.com

set user:userid:9:username lisi
set user:userid:9:password 111111
set user:userid:9:email lisi@163.com

keys user:userid:9*

2 注意:
在关系型数据中,除主键外,还有可能其他列也步骤查询,
如上表中, username 也是极频繁查询的,往往这种列也是加了索引的.

转换到k-v数据中,则也要相应的生成一条按照该列为主的key-value
Set user:username:lisi:uid 9

这样,我们可以根据username:lisi:uid ,查出userid=9,
再查user:9:password/email ...

完成了根据用户名来查询用户信息

====================新版集群:


=======redis集群:设置配置文件:
daemonize yes # redis默认不是后台启动,这里修改成后台启动
cluster-enabled yes # 允许redis支持集群模式
cluster-config-file nodes.conf # 节点配置文件
cluster-node-timeout 15000 # 节点超时毫秒
appendonly yes
注意:6个节点下的redis.conf都需要修改,可以修改一个之后拷贝过去。
然后6个节点执行
make
make install
启动实例
在6个节点分别执行redis-server redis.conf,在6个节点上启动6个redis的实例
搭建redis集群(在其中一个节点操作就可以了)
依赖于ruby环境,首先安装ruby (yum install ruby)
sudo apt-get install ruby
sudo apt-get install rubygem


---下载不下来可以用如下L
tar xvzf rubygems-1.3.4.tgz
cd rubygems-1.3.4
sudo ruby setup.rb 即可

接下去需要安装ruby的redis api,gem install redis,这个地方试过各种方法(切换为taobao的镜像源)都不可以,所以我们这边去官网下载一个,然后手动安装。
wget https://rubygems.global.ssl.fastly.net/gems/redis-3.2.2.gem

sudo gem install -l ./redis-3.2.2.gem

一定要安装 redis-3.2.2.gem,千万别忘了gzf;

--如果集群设置密码,那么这里面的也要设置密码

 

接下去启动集群
cd src
./redis-trib.rb create --replicas 1 xxx.xxx.xx.140:6379 xxx.xxx.xx.141:6379 xxx.xxx.xx.143:6379 xxx.xxx.xx.145:6379 xxx.xxx.xx.147:6379 xxx.xxx.xx.148:6379
注意ip修改成自己的~~
--replicas 1 表示我们希望为集群中的每个主节点创建一个从节点,由于sedis的集群最少需要3个主节点,如果我们每个主节点需要一个从节点,那么最少需要6台机器(或者说6个实例)。
145、147、148这3个将成为主节点,140、141、143将依次称为主节点的从节点,我们看命令执行之后的结果:

---
ruby redis-trib.rb create 127.0.0.1:6379 127.0.0.1:6380 127.0.0.1:6381

----reids设置密码,后masterauth也要设置相同密码;
requirepass和masterauth都需要设置
--修改这里的密码:
/usr/local/share/gems/gems/redis-3.2.2/lib/redis

-------测试集群:
./redis-cli -c -p 6379
cluster info
cluster nodes
-------密码测试集群:
./redis-cli -c -p 6379 -a gzf
========
redis集群主库之间是唯一的key,会根据key跳转到不同的master上;


##############sysctl文件###############
[root@redis ~]# echo "vm.overcommit_memory=1" >> /etc/sysctl.confs
[root@redis ~]# sysctl -p
#############kerbel####################
[root@redis ~]# echo never > /sys/kernel/mm/transparent_hugepage/enabled

第一个警告两个方式解决(overcommit_memory)
1. echo "vm.overcommit_memory=1" > /etc/sysctl.conf 或 vi /etcsysctl.conf , 然后reboot重启机器
2. echo 1 > /proc/sys/vm/overcommit_memory 不需要启机器就生


第二个警告解决
1. echo 511 > /proc/sys/net/core/somaxconn

====redis开机启动:

/root/tools/java/redis-3.0.5/utils/redis_init_script

#大致浏览下该启动脚本,发现redis习惯性用监听的端口名作为配置文件等命名,我们后面也遵循这个约定。
#redis服务器监听的端口
REDISPORT=6379
#服务端所处位置,在make install后默认存放与`/usr/local/bin/redis-server`,如果未make install则需要修改该路径,下同。
EXEC=/usr/local/bin/redis-server
#客户端位置
CLIEXEC=/usr/local/bin/redis-cli
#Redis的PID文件位置
PIDFILE=/var/run/redis_${REDISPORT}.pid
#配置文件位置,需要修改

复制到/
=================
#修改daemonize为yes,即默认以后台程序方式运行(还记得前面手动使用&号强制后台运行吗)。
daemonize no
#可修改默认监听端口
port 6379
#修改生成默认日志文件位置
logfile "/home/futeng/logs/redis.log"
#配置持久化文件存放位置
dir /home/futeng/data/redisData
启动时指定配置文件
redis-server ./redis.conf
#如果更改了端口,使用`redis-cli`客户端连接时,也需要指定端口,例如:
redis-cli -p 6380
其他启停同 直接启动 方式。配置文件是非常重要的配置工具,随着使用的逐渐深入将显得尤为重要,推荐在一开始就使用配置文件。

chkconfig --add redis 不支持添加如下:

#!/bin/sh
# chkconfig: 2345 90 10
# description: Redis is a persistent key-value database

==========

Redis 官方提供了 redis-trib.rb 这个工具,就在解压目录的 src 目录中,第三步中已将它复制到 /usr/local/bin 目录中,可以直接在命令行中使用了。使用下面这个命令即可完成安装。

redis-trib.rb create --replicas 1 192.168.31.245:7000 192.168.31.245:7001 192.168.31.245:7002 192.168.31.210:7003 192.168.31.210:7004 192.168.31.210:7005
其中,前三个 ip:port 为第一台机器的节点,剩下三个为第二台机器。

等等,出错了。这个工具是用 ruby 实现的,所以需要安装 ruby。安装命令如下:

yum -y install ruby ruby-devel rubygems rpm-build
gem install redis


简单说一下原理

redis cluster在设计的时候,就考虑到了去中心化,去中间件,也就是说,集群中的每个节点都是平等的关系,都是对等的,每个节点都保存各自的数据和整个集群的状态。
每个节点都和其他所有节点连接,而且这些连接保持活跃,这样就保证了我们只需要连接集群中的任意一个节点,就可以获取到其他节点的数据。

Redis 集群没有并使用传统的一致性哈希来分配数据,而是采用另外一种叫做哈希槽 (hash slot)的方式来分配的。
redis cluster 默认分配了 16384 个slot,当我们set一个key 时,会用CRC16算法来取模得到所属的slot,然后将这个key 分到哈希槽区间的节点上,
具体算法就是:CRC16(key) % 16384。所以我们在测试的时候看到set 和 get 的时候,直接跳转到了7000端口的节点。

Redis 集群会把数据存在一个 master 节点,然后在这个 master 和其对应的salve 之间进行数据同步。当读取数据时,也根据一致性哈希算法到对应的 master 节点获取数据。
只有当一个master 挂掉之后,才会启动一个对应的 salve 节点,充当 master 。

需要注意的是:必须要3个或以上的主节点,否则在创建集群时会失败,并且当存活的主节点数小于总节点数的一半时,整个集群就无法提供服务了。


====================
redis主从复制

redis主从配置比较简单,基本就是在从节点配置文件加上:slaveof 192.168.33.130 6379
主要是通过master server持久化的rdb文件实现的。master server 先dump出内存快照文件,然后将rdb文件传给slave server,slave server 根据rdb文件重建内存表。
redis复制过程如下:
1、slave server启动连接到master server之后,salve server主动发送SYNC命令给master server
2、master server接受SYNC命令之后,判断,是否有正在进行内存快照的子进程,如果有,则等待其结束,否则,fork一个子进程,子进程把内存数据保存为文件,并发送给slave server
3、master server子进程进程做数据快照时,父进程可以继续接收client端请求写数据,此时,父进程把新写入的数据放到待发送缓存队列中
4、slave server 接收内存快照文件之后,清空内存数据,根据接收的快照文件,重建内存表数据结构
5、master server把快照文件发送完毕之后,发送缓存队列中保存的子进程快照期间改变的数据给slave server,slave server做相同处理,保存数据一致性
6、master server 后续接收的数据,都会通过步骤1建立的连接,把数据发送到slave server
需要注意:slave server如果因为网络或其他原因断与master server的连接,当slave server重新连接时,需要重新获取master server的内存快照文件,slave server的数据会自动全部清空,然后再重新建立内存表,这样会让slave server 启动恢复服务比较慢,同时也给master server带来较大压力,可以看出redis的复制没有增量复制的概念,这是redis主从复制的一个主要弊端,在实际环境中,尽量规避中途增加从库
redis2.8之前不支持增量,到2.8之后就支持增量了!


redis cluster(集群)
redis集群配置参考我的博文:http://blog.csdn.net/nuli888/article/details/52134117
3.0之后的功能,至少需要3(Master)+3(Slave)才能建立集群,是无中心的分布式存储架构,可以在多个节点之间进行数据共享,解决了Redis高可用、可扩展等问题。
Redis集群提供了以下两个好处
1、将数据自动切分(split)到多个节点
2、当集群中的某一个节点故障时,redis还可以继续处理客户端的请求。
一个 redis 集群包含 16384 个哈希槽(hash slot),数据库中的每个数据都属于这16384个哈希槽中的一个。集群使用公式 CRC16(key) % 16384 来计算键 key 属于哪个槽。集群中的每一个节点负责处理一部分哈希槽。
集群中的主从复制
集群中的每个节点都有1个至N个复制品,其中一个为主节点,其余的为从节点,如果主节点下线了,集群就会把这个主节点的一个从节点设置为新的主节点,继续工作。这样集群就不会因为一个主节点的下线而无法正常工作
注意:
1、如果某一个主节点和他所有的从节点都下线的话,redis集群就会停止工作了。redis集群不保证数据的强一致性,在特定的情况下,redis集群会丢失已经被执行过的写命令
2、使用异步复制(asynchronous replication)是redis 集群可能会丢失写命令的其中一个原因,有时候由于网络原因,如果网络断开时间太长,redis集群就会启用新的主节点,之前发给主节点的数据就会丢失。


==========
Redis Cluster功能特点如下:

所有的节点相互连接

集群消息通信通过集群总线通信,,集群总线端口大小为客户端服务端口+10000,这个10000是固定值

节点与节点之间通过二进制协议进行通信

客户端和集群节点之间通信和通常一样,通过文本协议进行

集群节点不会代理查询

数据按照Slot存储分布在多个Redis实例上

集群节点挂掉会自动故障转移

可以相对平滑扩/缩容节点


==========

Redis Cluster采用无中心结构,每个节点保存数据和整个集群状态,每个节点都和其他所有节点连接。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SpringBoot整合Mybatis和Redis原理主要包括以下几个方面: 1. SpringBoot整合Mybatis:SpringBoot提供了Mybatis的自动配置功能,只需要在pom.xml中引入相关的依赖,配置好数据源,就可以使用Mybatis进行数据库操作。 2. SpringBoot整合Redis:SpringBoot提供了对Redis的支持,只需要在pom.xml中引入相关的依赖,配置好Redis的连接信息,就可以使用Redis进行缓存操作。 3. 整合过程:在整合过程中,需要将Mybatis的查询结果进行序列化,存入Redis缓存中,同时在查询数据时,先从Redis缓存中获取数据,如果获取不到再从数据库中获取数据,并将结果存入Redis缓存中。 具体实现可以参考以下步骤: 1. 配置数据源和Mybatis:在application.properties文件中配置数据源和Mybatis相关信息,例如: ``` spring.datasource.url=jdbc:mysql://localhost:3306/test?useSSL=false spring.datasource.username=root spring.datasource.password=123456 mybatis.mapper-locations=classpath:mapper/*.xml ``` 2. 配置Redis:在application.properties文件中配置Redis相关信息,例如: ``` spring.redis.host=localhost spring.redis.port=6379 spring.redis.password= spring.redis.database=0 ``` 3. 配置RedisTemplate:使用RedisTemplate进行Redis操作,可以在配置类中进行配置,例如: ``` @Configuration public class RedisConfig { @Autowired private RedisConnectionFactory redisConnectionFactory; @Bean public RedisTemplate<String, Object> redisTemplate() { RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory); redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer()); return redisTemplate; } } ``` 4. 编写缓存操作代码:在查询数据时,先从Redis缓存中获取数据,如果获取不到再从数据库中获取数据,并将结果存入Redis缓存中,例如: ``` @Service public class UserServiceImpl implements UserService { private static final String REDIS_KEY_PREFIX = "user:"; @Autowired private UserMapper userMapper; @Autowired private RedisTemplate<String, Object> redisTemplate; @Override public User getUserById(Integer id) { String key = REDIS_KEY_PREFIX + id; User user = (User) redisTemplate.opsForValue().get(key); if (user == null) { user = userMapper.getUserById(id); if (user != null) { redisTemplate.opsForValue().set(key, user); } } return user; } } ``` 以上就是SpringBoot整合Mybatis和Redis原理及实现步骤。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值