mysql复制与redis复制_MySQL to Redis同步

方式1:使用MQ

20200504002150509kjy9y3bxogb8360_5.png

对于此类业务,增加一个消费订阅基本没什么成本,服务本身也不需要做任何更改。唯一需要担心的一个问题是丢消息的情况?因为现在消息是缓存数据的唯一来源,一旦出现丢消息,缓存里缺失的那条数据永远不会被补上。 MQ 集群,像 Kafka 或者 RocketMQ,它都有高可用和高可靠的保证机制,可以满足数据可靠性要求的。

方式2:使用 Binlog 实时更新 Redis 缓存

20200504002150509kjy9y3bxogb8360_2.png

数据更新服务只负责处理业务逻辑,更新 MySQL,完全不用管如何去更新缓存。另外起程序,支撑binlog的解析到更新redis的过程。

常用canal负责更新缓存的服务,把自己伪装成一个 MySQL 的从节点,从 MySQL 接收 Binlog,解析 Binlog 之后,可以得到实时的数据变更信息,然后根据这个变更信息去更新 Redis 缓存。

canal 官方图

20200504002150509kjy9y3bxogb8360_1.png

官方:canal 特别设计了 client-server 模式,交互协议使用 protobuf 3.0 , client 端可采用不同语言实现不同的消费逻辑。

我的配置过程:

开启binlog

[mysqld]

log-bin = /usr/local/var/mysql/mysql_bin_log/mysql-bin #开启binlog/路径

server_id = 1 ## 配置一个ServerID

binlog_format=ROW #格式

给 Canal 开一个专门的 MySQL 用户并授权,确保这个用户有复制 Binlog 的权限:

CREATE USER canal IDENTIFIED BY 'canal';

GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'canal'@'%';

FLUSH PRIVILEGES;

查看是否开启binlog:

show variables like '%log_bin%';

20200504002150509kjy9y3bxogb8360_3.png

查看对应的binlog以及对应记录行数位置:

show master status

20200504002150509kjy9y3bxogb8360_0.png

安装canal:

wget https://github.com/alibaba/canal/releases/download/canal-1.1.4/canal.deployer-1.1.4.tar.gz

tar zvfx canal.deployer-1.1.4.tar.gz

配置:

vim canal/conf/example/instance.properties

canal.instance.gtidon=false

# position info

canal.instance.master.address=127.0.0.1:3306

canal.instance.master.journal.name=mysql-bin.000007

canal.instance.master.position=1905

canal.instance.master.timestamp=

canal.instance.master.gtid=

# username/password

canal.instance.dbUsername=canal

canal.instance.dbPassword=canal

canal.instance.connectionCharset = UTF-8

canal.instance.defaultDatabaseName=test

# table regex

canal.instance.filter.regex=.*\\..

启动/重启/停止脚本位于bin目录下

使用canal/bin/startup.sh启动,启动之后看一下日志文件 canal/logs/example/example.log,如果里面没有报错,就说明启动成功并连接到我们的 MySQL 上了。

使用客户端进行消费(Python):

#encoding:utf-8

#author:donghao

import time

import redis

import json

from canal.client import Client

from canal.protocol import EntryProtocol_pb2

client = Client()

client.connect(host='127.0.0.1', port=11111)

client.check_valid(username=b'', password=b'')

client.subscribe(client_id=b'1001', destination=b'example', filter=b'.*\\..*')

pool = redis.ConnectionPool(host='127.0.0.1', port=6379, password='donghao')

cache = redis.Redis(connection_pool=pool)

while True:

message = client.get(100)

entries = message['entries']

for entry in entries:

entry_type = entry.entryType

if entry_type in [EntryProtocol_pb2.EntryType.TRANSACTIONBEGIN, EntryProtocol_pb2.EntryType.TRANSACTIONEND]:

continue

row_change = EntryProtocol_pb2.RowChange()

row_change.MergeFromString(entry.storeValue)

event_type = row_change.eventType

header = entry.header

database = header.schemaName

table = header.tableName

event_type = header.eventType

for row in row_change.rowDatas:

format_data = dict()

if event_type == EntryProtocol_pb2.EventType.DELETE:

for column in row.beforeColumns:

format_data = {

column.name: column.value

}

elif event_type == EntryProtocol_pb2.EventType.INSERT:

for column in row.afterColumns:

format_data = {

column.name: column.value

}

else:

format_data['before'] = format_data['after'] = dict()

for column in row.beforeColumns:

format_data['before'][column.name] = column.value

for column in row.afterColumns:

format_data['after'][column.name] = column.value

data = dict(

db=database,

table=table,

event_type=event_type,

data=format_data,

)

if event_type == EntryProtocol_pb2.EventType.UPDATE:

# 更新前

cache_key = "article:article_id_{}".format(format_data['before']['id'])

cached_article = cache.get(cache_key)

if cached_article:

print('更新前 ', json.loads(cached_article))

# 更新缓存

cache.set(cache_key, json.dumps(format_data['after']))

print('更新后 ', json.loads(cache.get(cache_key)))

print(data)

time.sleep(1)

client.disconnect()

20200504002150509kjy9y3bxogb8360_4.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值