怎么模拟mysql主从同

怎么模拟mysql主从同,第1张

        -+-+-+-+-+-+-+-+-+-+-+-

        -+-+mysql的主从配置+-+-

        -+-+-+-+-+-+-+-+-+-+-+-

#############################################################################

常用命令

1.安装一个mysqld服务

  mysqld  install  

2.开启mysql服务        关闭mysql服务  

  net start mysql      net stop mysql

2.开启一个 mysql 的 3307端口

  命令行 进入解压目录\bin目录下

   解压目录\bin> mysql -uroot  -p  -P3307 -h127.0.0.1

-u 用户名

-p密码

-P端口

-h网址

#启动从库

Start slave

#停止从库

Stop slave

#############################################################################

开始

用一台电脑测试

先在本电脑上安装一个mysql(集成的也行)

解压文件

然后解压另一个mysql到电脑目录

》》》》》1.

在解压目录创建一个mysql.ini

把一下文档写进去配置一个端口号为3307

#mysqld

[mysqld]

port=3307

basedir=D:\mysqlsever         #D:\mysqlsever 改成你解压目录

datadir=D:\mysqlsever\data    #D:\mysqlsever 改成你解压目录

安装一个mysqld服务    mysqld  install

开启mysql服务         net start mysql

不能正常启动请查看配置

》》》》2.

#主库3306

在命令行或者

grant 权限 on 数据库对象 to 用户

GRANT all privileges REPLICATION SLAVE,RELOAD,SUPER ON *.*

TO mysql_backup1@'*'

IDENTIFIED BY '123456'with grant option

flush privileges

》》》3.

在主库运行   SHOW MASTER STATUS       //运行后查看File和Postion

如  File mysql-bin.000002   Postion 120

在从库运行  

CHANGE MASTER TO master_host = '127.0.0.1',

master_user = 'mysql_backup',

master_password = '123456',

master_log_file = 'mysql-bin.000001',#看上面的File  从库对照主库写

master_log_pos = 4791#看上面的Postion    从库对照主库写

如果报错就停止就重新运行

#启动从库

Start slave

#停止从库

Stop slave

在从库运行  Show slave status

Slave_IO_Running

Slave_SQL_Running

两个字段全部是是Yes基本上就成功了

测试

在主库上建立一个表  在从库上刷新

############################################################################

通常大家都会使用redis作为应用的任务队列表,redis的List结构,在一段进行任务的插入,在另一端进行任务的提取。

任务的插入

$redis->lPush("key:task:list",$task)

任务的提取

$tasks = $redis->RPop("key:task:list",0,-1)

可是大家想,如何使用mysql来实现一个队列表呢?

映入大家脑海的一个典型的模式是一个表包含多种类型的记录:未处理记录,已处理记录,正在处理记录等。一个或者多个消费者线程在表中查询未处理的记录,然后声称正在处理这个任务,处理完成之后,再讲记录更新为已处理状态。

这个典型的模式,存在两个问题;1:随着队列表越来越大,查找未处理记录的速度会越来越慢。2:频繁的加锁会让多个消费者线程增加竞争。

首先我们来创建一个表

create table unsent_emails{id int not null primary key auto_increment,status enum("unsent","claimed","sent"),

owner int unsigned not null default 0,

ts timestamp,key (owner,status,ts)

}

该表的列owner用来存储当前正在处理这个记录的连接id,由函数 CONNECTION_ID()返回的连接id或者线程id。如果这个记录当前被没有被处理,则该值为0

我们在 owner status ts上面做了索引的处理,所以查找未处理的记录会很快。

通过我们会采用 select for update的方式来标记待处理的记录,方法如下

beginselect id from unsent_emailswhere owner = 0 and status = 'unsent'

limit 10 for update-- result 10,20,33update unsent_emailsset status = 'claimed',owner = CONNECTION_ID()where id in (10,20,33)

commit

select的时候,使用了两个索引,应该会很快。问题出在select 和 update两个查询之间的间隙,这里的加锁会让其他相同的查询全部阻塞。

如果我们采用update then select的方式,那么效果就会更加高效,代码如下

set autocommit=1commitupdate unsent_emailsset statue = 'claimed',owner = CONNECTION_ID()where owner = 0 and status = 'unsent'

limit 10set autocommit=0select id from unsent_emailswhere owner = CONNECTION_ID() and status = 'claimed'

根本无需使用select去查找哪些记录还没有处理。客户端协议会告诉你更新了几条记录,就可以知道这次需要处理多少条记录。

这样是不是解决了上面的第二个问题,select for update的模式的加锁会增加多个消费队列的竞争问题。

其实所有的select for update 都可以替换为 update then select模式。

问题还没有结束,还有一种情况需要处理,就是比如正在处理任务的进程异常退出了,那么对应的进程正在处理的任务也就变为僵尸任务了。如何避免这种情况的发生呢?

所以我们还是需要一个新的定时器或者线程来定时检测并且update,将那些僵尸任务的记录更新到原始状态,就可以了。

僵尸任务的定义必须符合两点,1:任务被搁置了很久,比如十分钟,而通常一个任务只需要10秒就可以处理完;2:任务的owner(线程id或者连接id)已经不存在,只需要执行show processlist就可以获取当前正在工作的线程id了。代码如下

update unsent_emailsset owner = 0,status = 'unsent'

where owner not in (10,20,33,44) and status = 'claimed'

and ts <current_timestamp - interval 10 minute

一个基于mysql构建的队列表就完成了。

当然,最好的办法就是将任务队列从数据库中迁移出来。redis真是一个很好的队列容器,当然也可以使用ssdb(基于leveldb,内存占用更少)。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/8484500.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-16
下一篇 2023-04-16

发表评论

登录后才能评论

评论列表(0条)

保存