Heim >Backend-Entwicklung >PHP-Tutorial >响应版主号召,发点入门教学文章 - 简单说下redis主从复制过程以及小弟我发现的一个导致小弟我线上业务出bug的不起眼特性

响应版主号召,发点入门教学文章 - 简单说下redis主从复制过程以及小弟我发现的一个导致小弟我线上业务出bug的不起眼特性

WBOY
WBOYOriginal
2016-06-13 12:03:23958Durchsuche

响应版主号召,发点入门教学文章 - 简单说下redis主从复制过程以及我发现的一个导致我线上业务出bug的不起眼特性
写在前面:

虽然和php没啥直接关系,但我想现在redis是非常主流的,看着很多朋友在抱怨效率低下且还在实时查着mysql。因此介绍下redis,毕竟是内存,读写速度超过磁盘n个档次,并且redis学习成本比起mysql、mongo、cassandra这些低很多。绝对值得你去尝试。

如果您是新手,您可以仔细看下redis的同步方式,了解个大概。
如果您是redis的老用户,就当我给您提个醒,那个细节很不起眼,但确实可能会在将来影响到您。

此文并不是redis的教程文章,也不是深入redis源代码分析的核心原理介绍。我只是想从一个特别的角度让大家看到redis的好处,以及一些需要注意的地方。如果有需要,我以后会重点介绍一些redis的使用细节,参数设置之类的。跟一些精通linux c、擅长分析源码的大牛比起来我还是入门级的,如果有错误之处,请直接指出,不甚感激!



redis的数据持久化有两种方案:

1 写aof文件
2 写快照rdb文件

如果两种同时打开,redis启动后会优先尝试从aof文件中恢复数据。另外如果做主从,redis以slave会向master拉aof文件来实现主从同步的目的。

快照rdb就不说了,这里主要说一下aof。当你在redis中执行了一条命令后,redis就会以追加方式写入aof文件中。

我在本机先开好两个redis server,一个监听12345端口做master。另一个监听12346端口做slave。


然后redis-cli连接redis-server master,并写入一个测试用的值:


同样再来个redis-cli连接redis-server slave,可以看到,这个值被同步过来了。


现在我们看一下master和redis的aof文件,可以看到,完全一致。
master:

slave:


现在我从master中删了这个mytestkey,也会写入aof文件,并且会同步到slave。
master中执行del mytestkey:

查看slave的aof文件,注意最后三行,已经同步过来了。


这就是redis主从同步的基本原理。
在redis中执行的命令,会被写入aof文件,并且在master中执行的命令,会将aof文件同步到slave(准确的说是由slave向master发送sync命令拉aof文件)。

但也有例外:

刚才我新建了一个key,又把它删除了,那么库里应该啥都没了。这时如果我再删除,就等于是删除一个不存在的key,redis会返回:(integer) 0。flushdb是清库操作,无论库里是否有数据,都会返回ok。
那么这条两条命令在库里没有数据的情况下,是否会被写入aof文件并且同步呢?

答案是否定的,它并没有第二次写入del mytestkey,也没有写入flushdb。同样更不会同步给slave的aof文件。

我之所以要提这一点,是因为前两天因为这个性质导致线上业务出了个重大bug。我们线上业务是多台php web server+多台redis。redis同样也做了主从,主从关系采用单向链表式结构。即master->slave->slave->slave...master中存储着所有slave需要的公共数据。而每一台slave,都需要写自己独特的cache,因为一台php web server读一台redis slave。这样看似完美,即做到了redis的负载均衡,又避免了内存数据冗余。我们为了避免cache的冗余。也为了避免cache key的冲突(其实这个很好解决,加个key前缀就可以解决了),就违背了主从同步的核心理念 - 数据一致性,每台php web server都向自己对应的那台slave中写入数据。cache毕竟是cache,这些cache会造成数据更新的问题,我没有在set的时候给key设置失效时间。而是采用事件驱动的方式来统一一次性清除掉所有机器上的cache。

每天晚上有一系列脚本,用来更新所有redis中的公共数据,公共数据和cache存储在不同的分区中,假如公共数据存储在0库,那cache就存储在1库。我向master执行
select 0
flushdb
select 1
flushdb

接下来问题就来了,由于master的cache分区1库中一条数据都没有。所以这条flushdb实际并不会写入本机aof文件,更不会被同步到各个slave。结果就是cache根本没被清理掉,造成第二天数据没更新的bug,这里我也没设置monitor,第二天被n多部门追问起来才知道出了问题,找了一下午才找到原因。被一通谴责。。。。

解决方案嘛也很简单:
A 修改为统一向master写数据
B 晚上脚本在master上清理cache分区时,先随便set一个key,然后再执行flushdb

为了数据不冗余,也为了偷懒(这样改动最小),我采取了Plan B。
最后为了追根究底,我去看了redis的源码,发现在写aof模块中,果然有那么一段,大概意思就是执行del或flushdb之类的命令时发现没什么可释放的,就不向aof文件中追加此命令。另外,info、monitor这种和监控相关的,不对数据产生影响的命令也不会写入aof文件。
------解决方案--------------------
用了Mysql的内存表 深深的知道 内存和硬盘上数据读取的差距.redis还没部署 基本上都是memcache
------解决方案--------------------
不错 mark
------解决方案--------------------
灰常不错,了解一个。。。
------解决方案--------------------
赞,有机会也想学学PHP编程
------解决方案--------------------

------解决方案--------------------

------解决方案--------------------
支持一个 :)
------解决方案--------------------


多谢 ShadowSniper大哥!
------解决方案--------------------
感谢楼主分享
------解决方案--------------------
php新手路过
------解决方案--------------------
不错,有机会学习一下
------解决方案--------------------
了解啦,谢谢分享!
------解决方案--------------------
小顶一下下
------解决方案--------------------
了解啦,谢谢分享!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Vorheriger Artikel:读取树状数据的方法解决办法Nächster Artikel:PHP基础知识(1)