• python创建MySQL多实例-1


    python创建MySQL多实例-1

    前言

    • 什么是多实例

    多实例就是允许在同一台机器上创建另外一套不同配置文件的数据库,他们之间是相互独立的,主要有以下特点,

    • 1》 不能同时使用一个端口
    • 2》 不可以使用同一个socket文件
    • 3》 也不可以使用同样的pid
    • 4》 配置文件也必须是不一样的
    • 5》 存入数据的data目录也不能一样
    • 6》 日志文件位置也不可以一样

    上面这些只是我个人的一些理解,具体的可能参考网上的一些文章
    https://www.percona.com/blog/2014/08/26/mysqld_multi-how-to-run-multiple-instances-of-mysql/

    https://freedo.ga/url?sa=t&rct=j&q=&esrc=s&source=web&cd=2&cad=rja&uact=8&ved=0ahUKEwjOr4-hj7LTAhXpiFQKHSKNDD4QFggrMAE&url=https%3A%2F%2Fdev.mysql.com%2Fdoc%2Fmysql%2Fen%2Fmultiple-servers.html&usg=AFQjCNGkZSDJbsHCVbm0n8cubpUha2SPsA

    https://dev.mysql.com/doc/refman/en/multiple-windows-services.html

    需求

    通过python脚本来实现创建多个实例

    使用方法

    程序的目录结构如下

    # tree mysql_tools/
    mysql_tools/
    ├── library
    │   ├── __init__.py
    │   ├── __init__.pyc
    │   ├── mysql.py
    │   └── mysql.pyc
    └── manager
        ├── __init__.py
        └── myman.py
    
    2 directories, 6 files
    
    # python myman.py  -h
    Usage: myman.py [options]
    
    Options:
      -h, --help            show this help message and exit
      -n NAME, --name=NAME  
      -p PORT, --port=PORT  
      -c COMMAND, --command=COMMAND
    

    如创建一个my02.cnf的配置文件,端口为3302

    python myman.py -n my02 -p 3302 -c create 
    

    实例目录结构

    # tree -L 3 /data/mysql/
    /data/mysql/
    ├── conf
    │   ├── my01.cnf
    │   └── my02.cnf
    └── data
        ├── my01
        │   ├── ibdata1
        │   ├── ib_logfile0
        │   ├── ib_logfile1
        │   ├── my01-err.log
        │   ├── my01.pid
        │   ├── my01.sock
        │   ├── mysql
        │   └── test
        └── my02
            ├── ibdata1
            ├── ib_logfile0
            ├── ib_logfile1
            ├── my02-err.log
            ├── my02.pid
            ├── my02.sock
            ├── mysql
            └── test
    
    8 directories, 14 files
    

    源码如下

    • ./library/mysql.py
    #!/usr/bin/env python
    #-*- coding:utf8 -*-
    
    from ConfigParser import ConfigParser
    import os
    
    class MySQLDConfig(ConfigParser):
    	def __init__(self, cfg, **kwargs):
    		ConfigParser.__init__(self, allow_no_value=True)
    		# super(ConfigParser, self).__init__(allow_no_value=True) # ConfigParser的你类是以传统方式定义的,所以这里不可以用super来重写方法
    		self.cfg = cfg
    		self.mysqld_vars = {}
    		
    		if os.path.exists(self.cfg):
    			self.config = cfg
    			self.read(self.config)
    			self.get_mysqld_vars()
    		else:
    			self.get_default_mysqld_vars()
    			
    		self.set_mysqld_vars(kwargs)
    		
    	def set_mysqld_vars(self, kwargs):
    		for k,v in kwargs.items():
    			setattr(self, k, v)
    			' add every k-v pairs to dictonary. '
    			self.mysqld_vars[k] = v
    			
    	def get_mysqld_vars(self):
    		result = {}
    		'return a list'
    		options = self.options('mysqld')
    		for opt in options:
    			result[opt] = self.get('mysqld', opt)
    		self.set_mysqld_vars(result)
    	
    	def get_default_mysqld_vars(self):
    		defaults = {
    			'user': 'mysql',
    			'port': '3307',
    			'socket': ' /var/lib/mysql/mysql.sock',
    		    # 'skip-locking': None,
    		    'key_buffer_size': '256M',
    		    'max_allowed_packet': '1M',
    		    'table_open_cache': '256',
    		    'sort_buffer_size': '1M',
    		    'read_buffer_size': '1M',
    		    'read_rnd_buffer_size': '4M',
    		    'myisam_sort_buffer_size': '64M',
    		    'thread_cache_size': '8',
    		    'query_cache_size': ' 16M',
    			}
    		' set default dict k-v to instance property. '
    		self.set_mysqld_vars(defaults)
    		
    	def set_vars(self, k, v):
    		self.mysqld_vars[k] = v
    		
    	' set propertyis for non-supported name, e.g. "skip-slave-start" '
    	def save_default_cfg(self):
    		if not self.has_section('mysqld'):
    			self.add_section('mysqld')
    		
    		for k,v in self.mysqld_vars.items():
    			self.set('mysqld', k, v)
    			
    		with open(self.cfg, 'wb') as fd:
    		    self.write(fd)
    
    if __name__ == '__main__':
    	cfg_file = '/tmp/my.cnf2'
    	mc = MySQLDConfig(cfg_file, max_connection=200, port=3307)
    	# mysqld_socket = mc.get('mysqld', 'socket')
    	# print mysqld_socket
    	mc.set_vars('skip-slave-start', None)
    	mc.save_default_cfg()
    	print mc.mysqld_vars['skip-slave-start']
    	print mc.max_connection
    	print mc.port
    	print mc.socket
    
    • ./library/mysql.py
    #!/usr/bin/env python
    #*-* coding: utf-8 -*-
    
    from optparse import OptionParser
    import sys
    import os
    from subprocess import Popen,PIPE
    import shlex
    import time
    import shutil
    
    current_dir = os.path.dirname(__file__)
    parent_dir = os.path.join(current_dir, '../')
    sys.path.append( os.path.abspath(parent_dir) )
    
    from library.mysql import MySQLDConfig
    
    MYSQL_DATA_DIR = '/data/mysql/data'
    MYSQL_CONF_DIR = '/data/mysql/conf'
    
    def opt():
        parser = OptionParser()
        parser.add_option('-n', '--name',
                          dest='name',
                          action='store',
                          default='myinstance'
                          )
        parser.add_option('-p', '--port',
                          dest='port',
                          action='store',
                          default='3306'
                          )
        parser.add_option('-c', '--command',
                          dest='command',
                          action='store',
                          default='check'
                          )
        options, args = parser.parse_args()
    
        return options, args
    
    def _init():
        if not os.path.exists(MYSQL_DATA_DIR):
            # os.mkdir(MYSQL_DATA_DIR)
            shutil.os.makedirs(MYSQL_DATA_DIR)
        if not os.path.exists(MYSQL_CONF_DIR):
            # os.mkdir(MYSQL_CONF_DIR)
            shutil.os.makedirs(MYSQL_CONF_DIR)
    
    def readConfs():
        from glob import glob
        confs = glob(MYSQL_CONF_DIR + '/*.cnf')
        return confs
    
    def checkPort(cfg_file, port):
        mc = MySQLDConfig(cfg_file)
        if mc.mysqld_vars['port'] == port:
            return True
        else:
            return False
    
    def _genDict(name, port):
        return {'pid-file': os.path.join(MYSQL_DATA_DIR, name, '%s.pid' % name),
                'socket': os.path.join(MYSQL_DATA_DIR, name, '%s.sock' % name),
                'port': port,
                'datadir': os.path.join(MYSQL_DATA_DIR, name),
                'log-error': os.path.join(MYSQL_DATA_DIR, name, '%s-err.log' % name)
                }
    
    def getCnf(name):
        return os.path.join(MYSQL_CONF_DIR, '%s.cnf' % name)
    
    def createInstance(name, port):
        confs = readConfs()
    
        for conf in confs:
            if conf.split('/')[-1].split('.')[0] == name:
                print >> sys.stderr, 'Instance: %s is already exists' % name
                sys.exit(-1)
            if checkPort(conf, port):
                print >> sys.stderr, 'Port: %s is already exists' % port
                sys.exit(-1)
        cnf = getCnf(name)
        if not os.path.exists(cnf):
            kwargs = _genDict(name, port)
            mc = MySQLDConfig(cnf, **kwargs)
            mc.save_default_cfg()
            
        datadir = os.path.join(MYSQL_DATA_DIR, name)
        if not os.path.exists(datadir):
            mysql_install(name)
            setOwner(datadir)
            mysqlRun(name)
    
    def mysql_install(name):
        cnf = getCnf(name)
        cmd = 'mysql_install_db --defaults-file=%s' % cnf
        p = Popen(shlex.split(cmd), stdout=PIPE, stderr=PIPE)
        p.communicate()
        p.returncode
        
    def setOwner(datadir):
        os.system('chown mysql:mysql %s' % datadir)
        
    def mysqlRun(name):
        cnf = getCnf(name)
        cmd = 'mysqld_safe --defaults-file=%s &' % cnf
        # 此行不知为什么会有问题,猜想可能与后台进程符号'&'有关
        # p = Popen(shlex.split(cmd), stdout=PIPE, stderr=PIPE)
        p = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True)
        # 如果是以后台进程启动的,那么就会hang住,因为后台进程并不会返回结果,所以p.communicate()就会一起处于等待状态
        # p.communicate()
        time.sleep(2)
        p.returncode
        
    if __name__ == '__main__':
        _init()
        options, args = opt()
        instance_name = options.name
        instance_port = options.port
        instance_cmd = options.command
        createInstance(instance_name, instance_port)
        # print options, args
    
  • 相关阅读:
    数组和字符串长度length
    Eclipse最有用快捷键整理
    Eclipse编辑java文件报Unhandled event loop exception错误的解决办法
    Java 删除项目中的.svn信息
    oracle 删除外键约束 禁用约束 启用约束
    Java Sftp上传下载文件
    java 如何判断操作系统是Linux还是Windows
    Javascript-正则表达式-开发中的使用.
    Eclipse和PyDev搭建完美Python开发环境 Windows篇
    ExtJS4为form表单必填项添加红色*标识
  • 原文地址:https://www.cnblogs.com/ZhangRuoXu/p/6738040.html
Copyright © 2020-2023  润新知