Oracle数据库有其公司开发的配套rac来实现负载均衡,目前已知的最大节点数能到128个,但是其带来的维护成本无疑是很高的,并且rac的稳定性也并不是特别理想,尤其是节点很多的时候。

但是,相对mysql来说,rac的实用性要比mysql的配套集群软件mysql-cluster要高很多。因为从网上了解到情况来看,很少公司在使用mysql-cluster,大多数企业都会选择第三方代理软件,例如MySQL Proxy、Mycat、haproxy等,但是这会引起另外一个问题:单点故障(包括mysql-cluster:管理节点)。如果要解决这个问题,就需要给代理软件搭建集群,在访问量很大的情况下,代理软件的双机或三机集群会成为访问瓶颈,继续增加其节点数,无疑会带来各方面的成本。

那么,如何可以解决这个问题呢?

解决上述问题,最好的方式个人认为应该是在程序中实现。通过和其他mysql DBA的沟通,也证实了这个想法。但是由此带来的疑问也就产生了:会不会增加开发成本?对现有的应用系统做修改会不会改动很大?会不会增加后期版本升级的难度?等等。

对于一个架构设计良好的应用系统可以很肯定的回答:不会。

那么怎么算一个架构设计良好的应用系统呢?

简单来说,就是分层合理、功能模块之间耦合性底。以本人的经验来说,系统设计基本上可以划分为以下四层:

1.  实体层:主要定义一些实体类

2.  数据层:也可以叫SQL处理层。主要负责跟数据库交互取得数据

3.  业务处:主要是根据业务流程及功能区分模块(或者说定义不同的业务类)

4.  表现层:呈现最终结果给用户

实现上述功能(mysql的读写分离及负载均衡),在这四个层次中,仅仅涉及到数据层。

严格来说,对于设计良好的系统,只涉及到一个类的一个函数:在数据层中,一般都会单独划分出一个连接类,并且这个连接类中会有一个连接函数,需要改动的就是这个函数:在读取连接字符串之前加一个功能函数返回需要的主机、ip、端口号等信息(没有开发经历的同学可能理解这段话有点费劲)。

流程图如下:

代码如下:

import mmap
import json
import random
import mysql.connector
import time##公有变量
#dbinfos={#         "db0":{'host':'192.168.42.60','user':'root','pwd':'Abcd1234','my_user':'root','my_pwd':'Abcd.1234',"port":3306,"database":"","role":"RW","weight":10,"status":1},
#         "db1":{'host':'192.168.42.61','user':'root','pwd':'Abcd1234','my_user':'root','my_pwd':'Abcd.1234',"port":3306,,"database":"":"R","weight":20,"status":1}
#         }

dbinfos={}
mmap_file = None
mmap_time=None##这个函数返回json格式的字符串,也是实现初始化数据库信息的地方
##使用json格式是为了方便数据转换,从字符串---》二进制--》字符串---》字典
##如果采用其它方式共享dbinfos的方法,可以不用此方式
##配置库的地址
def get_json_str1():return json.dumps(dbinfos)##读取配置库中的内容
def get_json_str():try:global dbinfoscnx = mysql.connector.connect(user='root', password='Abcd.1234',host='192.168.42.60',database='rwlb')cursor = cnx.cursor()cmdString="select * from rwlb"cnt=-1cursor.execute(cmdString)for (host,user,pwd,my_user,my_pwd,role,weight,status,port,db ) in cursor:cnt=cnt+1dict_db={'host':host,'user':user,'pwd':pwd,'my_user':my_user,'my_pwd':my_pwd,"port":port,"database":db,"role":role,"weight":weight,"status":status}dbinfos["db"+str(cnt)]=dict_dbcursor.close()cnx.close()return json.dumps(dbinfos)except:cursor.close()cnx.close()return ""##判断是否能正常连接到数据库
def check_conn_host():try:cnx = mysql.connector.connect(user='root', password='Abcd.1234',host='192.168.42.60',database='rwlb')cursor = cnx.cursor()cmdString="select user()"cnt=-1cursor.execute(cmdString)for user in cursor:cnt=len(user)cursor.close()cnx.close()return cntexcept :return -1;##select 属于读操作,其他属于写操作-----这里可以划分的更详细,比如执行存储过程等
def analyze_sql_state(sql):if "select" in sql:return "R"else:return "W"##读取时间信息
def read_mmap_time():global mmap_time,mmap_filemmap_time.seek(0)##初始时间inittime=int(mmap_time.read().translate(None, b'\x00').decode())##当前时间endtime=int(time.time())##时间差dis_time=endtime-inittimeprint("dis_time:"+str(dis_time))#重新读取数据if dis_time>10:##当配置库正常的情况下才重新读取数据print(str(check_conn_host()))if check_conn_host()>0:           print("read data again")mmap_time.seek(0)mmap_file.seek(0)mmap_time.write(b'\x00')mmap_file.write(b'\x00')get_mmap_time()get_mmap_info()else:print("can not connect to host")            #不重新读取数据else:print("do not read data again")##从内存中读取信息,
def read_mmap_info(sql):read_mmap_time()print("The data is in memory")global mmap_file,dict_dbmmap_file.seek(0)##把二进制转换为字符串info_str=mmap_file.read().translate(None, b'\x00').decode()#3把字符串转成json格式,方便后面转换为字典使用infos=json.loads(info_str)   host_count=len(infos)##权重列表listw=[]##总的权重数量wtotal=0##数据库角色dbrole=analyze_sql_state(sql)##根据权重初始化一个列表。这个是比较简单的算法,所以权重和控制在100以内比较好----这里可以选择其他比较好的算法for i in range(host_count):db="db"+str(i)if dbrole in infos[db]["role"]:if int(infos[db]["status"])==1:w=infos[db]["weight"]wtotal=wtotal+wfor j in range(w):listw.append(i)if wtotal >0:##产生一个随机数rad=random.randint(0,wtotal-1)##读取随机数所在的列表位置的数据dbindex=listw[rad]##确定选择的是哪个dbdb="db"+str(dbindex)##为dict_db赋值,即选取的db的信息dict_db=infos[db]return dict_dbelse :return {}##如果内存中没有时间信息,则向内存红写入时间信息
def get_mmap_time():global mmap_time##第二个参数1024是设定的内存大小,单位:字节。如果内容较多,可以调大一点mmap_time = mmap.mmap(-1, 1024, access = mmap.ACCESS_WRITE, tagname = 'share_time')##读取有效比特数,不包括空比特cnt=mmap_time.read_byte()if cnt==0:print("Load time to memory")mmap_time = mmap.mmap(0, 1024, access = mmap.ACCESS_WRITE, tagname = 'share_time')inittime=str(int(time.time()))mmap_time.write(inittime.encode())##如果内存中没有对应信息,则向内存中写信息以供下次调用使用
def get_mmap_info():global mmap_file##第二个参数1024是设定的内存大小,单位:字节。如果内容较多,可以调大一点mmap_file = mmap.mmap(-1, 1024, access = mmap.ACCESS_WRITE, tagname = 'share_mmap')##读取有效比特数,不包括空比特cnt=mmap_file.read_byte()if cnt==0:print("Load data to memory")mmap_file = mmap.mmap(0, 1024, access = mmap.ACCESS_WRITE, tagname = 'share_mmap')mmap_file.write(get_json_str().encode())##测试函数
def test1():get_mmap_time()get_mmap_info()for i in range(10):sql="select * from db"#sql="update t set col1=a where b=2"dbrole=analyze_sql_state(sql)dict_db=read_mmap_info(sql)print(dict_db["host"])def test2():sql="select * from db"res=analyze_sql_state(sql)print("select:"+res)sql="update t set col1=a where b=2"res=analyze_sql_state(sql)print("update:"+res)sql="insert into t values(1,2)"res=analyze_sql_state(sql)print("insert:"+res)sql="delete from t where b=2"res=analyze_sql_state(sql)print("delete:"+res)##类似主函数
if __name__=="__main__":test2()

测试结果:

从结果可以看出,只有第一次向内存加载数据,并且按照权重实现了负载均衡。

因为测试函数test1()写的是固定语句,所以读写分离的结果没有显示出来。

另外:测试使用的数据库表结构及数据:

 desc rwlb;
+---------+-------------+------+-----+---------+-------+
| Field   | Type        | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| host    | varchar(50) | YES  |     | NULL    |       |
| user    | varchar(50) | YES  |     | NULL    |       |
| pwd     | varchar(50) | YES  |     | NULL    |       |
| my_user | varchar(50) | YES  |     | NULL    |       |
| my_pwd  | varchar(50) | YES  |     | NULL    |       |
| role    | varchar(10) | YES  |     | NULL    |       |
| weight  | int(11)     | YES  |     | NULL    |       |
| status  | int(11)     | YES  |     | NULL    |       |
| port    | int(11)     | YES  |     | NULL    |       |
| db      | varchar(50) | YES  |     | NULL    |       |
+---------+-------------+------+-----+---------+-------+
select * from rwlb;
+---------------+------+----------+---------+-----------+------+--------+--------+------+------+
| host          | user | pwd      | my_user | my_pwd    | role | weight | status | port | db   |
+---------------+------+----------+---------+-----------+------+--------+--------+------+------+
| 192.168.42.60 | root | Abcd1234 | root    | Abcd.1234 | RW   |     10 |      1 | NULL | NULL |
| 192.168.42.61 | root | Abcd1234 | root    | Abcd.1234 | R    |     20 |      1 | NULL | NULL |
+---------------+------+----------+---------+-----------+------+--------+--------+------+------+

转载于:https://www.cnblogs.com/lc1217/p/6514349.html

python实现mysql的读写分离及负载均衡相关推荐

  1. OneProxy实现MySQL读写分离与负载均衡

    Part1:写在最前 OneProxy平民软件完全自主开发的分布式数据访问层,帮助用户在MySQL/PostgreSQL集群上快速搭建支持分库分表的分布式数据库中间件,也是一款具有SQL白名单(防SQ ...

  2. oneproxy mysql_在OneProxy的基础上实行MySQL读写分离与负载均衡

    简介 Part1:写在最前 OneProxy平民软件完全自主开发的分布式数据访问层,帮助用户在MySQL/PostgreSQL集群上快速搭建支持分库分表的分布式数据库中间件,也是一款具有SQL白名单( ...

  3. MaxScale:实现MySQL读写分离与负载均衡的中间件利器

    1.MaxScale 是干什么的? 配置好了MySQL的主从复制结构后,我们希望实现读写分离,把读操作分散到从服务器中,并且对多个从服务器能实现负载均衡. 读写分离和负载均衡是MySQL集群的基础需求 ...

  4. 【DB宝42】MySQL高可用架构MHA+ProxySQL实现读写分离和负载均衡

    文章目录 一.MHA+ProxySQL架构 二.快速搭建MHA环境 2.1 下载MHA镜像 2.2 编辑yml文件,创建MHA相关容器 2.3 安装docker-compose软件(若已安装,可忽略) ...

  5. 读写分离和负载均衡介绍

    通常我们所说的读写分离和负载均衡,实际上是两个不同的概念,读写分离主要做的工作,是把对数据库的读操作和写操作,来分开,我们进行MYSQL主从复制配置的一个主要目的呢,就是为了分担主库的读负载,就是因为 ...

  6. PG基于pgpool-II实现读写分离和负载均衡

    PG基于pgpool-II实现读写分离和负载均衡 PG:12 pgpool-II:4.2.2 OS:CentOS7.6 IP 主机名 作用 port 类型 备注 172.72.6.2 mambapg6 ...

  7. mysql读写分离和组复制_数据库主从复制,读写分离,负载均衡,分库分表分别表达的什么概念?...

    谢邀,这是个好问题,而且这个问题好在即使概念非常容易理解,但是这几个不同的概念细节太多太多,而且理解了概念,自己要用,又需要做很多的调研评估和开发工作.作为在这个领域爬坑多年的人,我这里就先介绍下概念 ...

  8. mysql 读写分离 max_MaxScale实现MySQL读写分离和负载均衡

    MaxScale安装 服务器 主1:192.168.0.131 从1:192.168.0.7 从2:192.168.0.9 1.在从2服务器上下载安装包 如若缺少依赖包请自行安装 [root@hado ...

  9. mysql+读的负载均衡_MySQL Proxy快速实现读写分离以及负载均衡

    作/译者:叶金荣(Email: ),来源:http://imysql.cn,转载请注明作/译者和出处,并且不能用于商业用途,违者必究. 1. 安装 下载已经编译好的安装包,或者预编译安装包均可,在这里 ...

  10. php laravel 默认cookie加密 读取怎么办_Laravel+Nginx轻松实现读写分离、负载均衡,网站并发能力提升N倍...

    前言: 随着互联网应用的广泛普及,海量数据的存储和访问成为了系统设计的瓶颈问题.对于一个大型的互联网应用,每天百万级甚至上亿的PV无疑对数据库造成了相当高的负载.对于系统的稳定性和扩展性造成了极大的问 ...

最新文章

  1. 云服务器 ECS快速入门:远程连接 ECS 实例
  2. 操作iframe里面的标签内容
  3. CRMEB删除公众号首页logo动画
  4. is transfer = C ( only read dynamically) not supported in one order scenario
  5. 可由一个尾指针唯一确定的链表有_六十九、数据结构链表的实现
  6. android播放器demo,Android 简单的本地音乐播放器Demo
  7. 小米5splus(高配版/全网通)解BL锁教程申请BootLoader解锁教程
  8. 考研408院校合集以及学科评估
  9. 怎么查询网站最近的cdn服务器,如何查看网站是否cdn加速
  10. win7 计算机定时关机脚本,Win7定时关机命令 win7系统怎么设置定时关机
  11. 浅析关键词密度你真的控制好了吗
  12. 爱荷华大学计算机科学专业,爱荷华大学计算机科学
  13. 站队(使用插入排序完成)——————来自MC老玩家的怒吼
  14. 图深度学习模型进展和在阿里搜索广告中的应用创新
  15. 金山wps c++开发二面总结
  16. C 语言 switch 语句
  17. SpringMVC个人零碎总结
  18. 通过字体映射 Fontlink 美化中文显示
  19. 在c++中关于堆和堆栈的区别
  20. 《生成式对抗网络GAN的研究进展与展望》论文笔记

热门文章

  1. Add NIC to Openfiler 2.3
  2. 数据挖掘学习07 - 《数据挖掘导论》第二章:数据
  3. [蛋蛋涂鸦]蜡笔蛋&某蛋真面目(表被吓着)
  4. 也乱弹Book.Save而引OO对话
  5. 使用spring cloud,nacos,dubbo,gateway搭建微服务
  6. mysql 数据库隔离级别_彻底搞懂mysql数据库四种隔离级别,实验实战
  7. e class connect.php,帝国CMS6.6程序剖析——e/class/connect.php
  8. Nginx源码分析 - 主流程篇 - 多进程实现(14)
  9. Springboot2.x 集成 jedis和spring-boot-starter-data-redis的性能测试比较(Jedis完胜:附带源码)
  10. springboot的restful接口成功失败返回值设计