标签 mysql 下的文章

我使用的是 mysqld_multi 这种实现方式,每个实例有其独立的配置文件,适合强迫症患者服用。

首先配置 MariaDB 的官方 yum 源:

vim /etc/yum.repos.d/MariaDB.repo

在新建的文件中添加:

# MariaDB 10.3 CentOS repository list - created 2018-08-28 05:47 UTC
# http://downloads.mariadb.org/mariadb/repositories/
[mariadb]
name = MariaDB
baseurl = http://yum.mariadb.org/10.3/centos7-amd64
gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB
gpgcheck=1

这里使用的是 MariaDB 10.3,当前貌似有 10.4 版本,可自行在官网查询。

完事儿之后就可以安装 MariaDB 了,这里采用二进制文件而非源码编译:

yum -y install MariaDB-server MariaDB-client

现在我准备部署三套 MariaDB 实例,具体是:

端口:3307,对应数据目录:/data/mysql/3307;
端口:3308,对应数据目录:/data/mysql/3308;
端口:3309,对应数据目录:/data/mysql/3309。

那么先来创建每个实例对应的目录:

mkdir -pv /data/mysql/330{7,8,9}

然后将这些目录所属修改到 MariaDB 用户与用户组:

chown -R mysql:mysql /data/mysql/330{7,8,9}

初始化数据目录:

mysql_install_db --datadir=/data/mysql/330{7,8,9}/data --basedir=/usr --user=mysql

好了,创建 MariaDB 配置文件:

vim /etc/my.cnf

在新建的文件中添加:

[mysqld_multi]
mysqld     = /usr/bin/mysqld_safe
mysqladmin = /usr/bin/mysqladmin
user       = multi_admin
password   = YOUR_PASSWORD

[mysqld3307]
socket     = /data/mysql/3307/mariadb.sock
port       = 3307
pid-file   = /data/mysql/3307/mariadb.pid
datadir    = /data/mysql/3307/data
user       = mysql

[mysqld3308]
socket     = /data/mysql/3308/mariadb.sock
port       = 3308
pid-file   = /data/mysql/3308/mariadb.pid
datadir    = /data/mysql/3308/data
user       = mysql

[mysqld3309]
socket     = /data/mysql/3309/mariadb.sock
port       = 3309
pid-file   = /data/mysql/3309/mariadb.pid
datadir    = /data/mysql/3309/data
user       = mysql

到这里,已经可以启动这三个实例:

mysqld_multi start 3307-3309

接着再做一些配置,请 One By One 地来:

mysql_secure_installation -S /data/mysql/3307/mariadb.sock
mysql_secure_installation -S /data/mysql/3308/mariadb.sock
mysql_secure_installation -S /data/mysql/3309/mariadb.sock

现在我们修改 root 密码,依然是 One By One:

mysqladmin -u root -p password -S /data/mysql/3307/mariadb.sock
mysqladmin -u root -p password -S /data/mysql/3308/mariadb.sock
mysqladmin -u root -p password -S /data/mysql/3309/mariadb.sock

创建一个 SQL 文件:

vim /data/src/create_user.sql

在新建的文件中添加:

CREATE USER 'multi_admin'@'localhost' IDENTIFIED BY 'YOUR_PASSWORD';
GRANT SHUTDOWN ON *.* TO 'multi_admin'@'localhost';
flush privileges;

在每个实例中执行以创建多实例管理用户,嗯,One By One:

cat create_user.sql | mysql -u root -S /data/mysql/3307/mariadb.sock -p
cat create_user.sql | mysql -u root -S /data/mysql/3308/mariadb.sock -p
cat create_user.sql | mysql -u root -S /data/mysql/3309/mariadb.sock -p

然后再创建一个 sysv 脚本:

vim /etc/rc.d/init.d/mysqld_multi

在新建的文件中添加:

mysqld_multi=/usr/bin/mysqld_multi

instance_list="3307-3309"

start(){
    $mysqld_multi start $instance_list
}
stop(){
    $mysqld_multi stop $instance_list
}
status(){
    $mysqld_multi report
}
case "$1" in
    start)
start
;;
stop)
stop
;;
status)
status
;;
restart)
start
stop
;;
*)
echo $"Usage: $0 {start|stop|status}"
exit 2
esac

接着添加 sysv:

chkconfig --add mysqld_multi

启用服务:

chkconfig mysqld_multi on

实现开机启动:

echo mysqld_multi start 3307-3309 >> /etc/rc.local

- EOF -

这是在一个 BT 的运行环境下诞生的需求,折腾数日,写下来自己马克一下。

1、需求:

1.1、表单上传本地图片;
1.2、以指定最大宽或指定最大高处理缩略图;
1.3、以指定最大宽高缩放原图并添加图片水印;
1.4、缩略图及水印图须连同原图一同入库存储。

2、函数部分:

2.1、获取图片信息函数

function get_image_info($file) {
    $result = getimagesize($file);
    $info = array();
    $info['width'] = $result[0];
    $info['height'] = $result[1];
    $info['type'] = $result[2];
    return $info;
}

2.2、原图宽高与缩放宽高运算函数

function fix_image_size($source_width, $source_height, $max_width, $max_height) {
    $size = array();
    if ($max_width == false) {
        if ($max_height < $source_height) {
            $size['width'] = $max_width < $source_width ? floor($max_height / ($source_height / $source_width)) : $source_width;
            $size['height'] = $max_height;
        }
        else {
            $size['width'] = $source_width;
            $size['height'] = $source_height;
        }
    }
    elseif ($max_height == false) {
        if ($max_width < $source_width) {
            $size['width'] = $max_width;
            $size['height'] = $max_height < $source_height ? floor($max_width / ($source_width / $source_height)) : $source_height;
        }
        else {
            $size['width'] = $source_width;
            $size['height'] = $source_height;
        }
    }
    else {
        if (($max_width && $source_width > $max_width) || ($max_height && $source_height > $max_height)) {
            if ($max_width && $source_width > $max_width) {
                $width_ratio = $max_width / $source_width;
                $resize_width_tag = true;
            }
            if ($max_height && $source_height > $max_height) {
                $height_ratio = $max_height / $source_height;
                $resize_height_tag = true;
            }
            if ($resize_width_tag && $resize_height_tag) $ratio = $width_ratio < $height_ratio ? $width_ratio : $height_ratio;
            if ($resize_width_tag && !$resize_height_tag) $ratio = $width_ratio;
            if ($resize_height_tag && !$resize_width_tag) $ratio = $height_ratio;
            $size['width'] = floor($source_width * $ratio);
            $size['height'] = floor($source_height * $ratio);
        }
        else {
            $size['width'] = $source_width;
            $size['height'] = $source_height;
        }
    }
    return $size;
}

2.3、缩略图处理函数

function resize_image($source_image_string, $source_width, $source_height, $resize_width, $resize_height) {
    if (!empty($source_image_string) && !empty($source_width) && !empty($source_height) && (!empty($resize_width) || !empty($resize_height))) {
        $resize_image = imagecreatetruecolor($resize_width, $resize_height);
        $source_image = imagecreatefromstring(base64_decode($source_image_string));
        if (function_exists('imagecopyresampled')) imagecopyresampled($resize_image, $source_image, 0, 0, 0, 0, $resize_width, $resize_height, $source_width, $source_height);
        else imagecopyresized($resize_image, $source_image, 0, 0, 0, 0, $resize_width, $resize_height, $source_width, $source_height);
        $image_stream = array();
        ob_start();
        imagejpeg($resize_image, null, 100);
        $image_stream['data'] = ob_get_contents();
        $image_stream['length'] = ob_get_length();
        ob_end_clean();
        if (!empty($image_stream['data']) && $image_stream['length'] > 0) {
            imagedestroy($source_image);
            imagedestroy($resize_image);
            return $image_stream;
        }
        else return false;
    }
    else return false;
}

2.4、图片水印处理函数

function watermark_image($source_image_string, $source_width, $source_height, $watermark_image_file) {
    if (!empty($source_image_string) && !empty($source_width) && !empty($source_height) && !empty($watermark_image_file)) {
        $source_image = imagecreatefromstring(base64_decode($source_image_string));
        $watermark_image_info = get_image_info($watermark_image_file);
        if ($watermark_image_info['type'] == 1) $watermark_image = imagecreatefromgif($watermark_image_file);
        elseif ($watermark_image_info['type'] == 2) $watermark_image = imagecreatefromjpeg($watermark_image_file);
        elseif ($watermark_image_info['type'] == 3) $watermark_image = imagecreateFrompng($watermark_image_file);
        else return false;
        if (empty($watermark_image)) return false;
        $x = $source_width - $watermark_image_info['width'];
        $y = $source_height - $watermark_image_info['height'];
        imagecopy($source_image, $watermark_image, $x, $y, 0, 0, $watermark_image_info['width'], $watermark_image_info['height']) or die('Error');
        ob_start();
        imagejpeg($source_image, null, 100);
        $image_stream['data'] = ob_get_contents();
        $image_stream['length'] = ob_get_length();
        ob_end_clean();
        if (!empty($image_stream['data']) && $image_stream['length'] > 0) {
            imagedestroy($source_image);
            imagedestroy($watermark_image);
            return $image_stream;
        }
        else return false;
    }
    return false;
}

3、调用部分

3.1、表单数据获取

$attach_type = $_FILES['attach']['type'];
$attach_tmp_name = $_FILES['attach']['tmp_name'];
$attach_error = $_FILES['attach']['error'];
$attach_size = $_FILES['attach']['size'];

3.2、元数据处理

$source_image_file = $attach_tmp_name;
$source_image_info = get_image_info($source_image_file);
$source_image_string = base64_encode(file_get_contents($source_image_file));

3.3、入库原图处理

$fp_original_image = fopen($attach_tmp_name, 'rb');
if (!$fp_original_image) die('Error');
$original_image_content = addslashes(fread($fp_original_image, filesize($attach_tmp_name)));
fclose($fp_original_image);
unlink($attach_tmp_name);

3.4、缩略图处理

$thumbnail_image_width = 300;
$thumbnail_image_height = false;
$thumbnail_image_size = fix_image_size($source_image_info['width'], $source_image_info['height'], $thumbnail_image_width, $thumbnail_image_height);
$thumbnail_image = resize_image($source_image_string, $source_image_info['width'], $source_image_info['height'], $thumbnail_image_size['width'], $thumbnail_image_size['height']);
if (empty($thumbnail_image['data']) || $thumbnail_image['length'] <= 0) die('Error');

3.5、图片水印定义

$watermark_image_file = 'path/to/watermark.png';
$watermark_image_width = 900;
$watermark_image_height = 600;
$watermark_image_size = fix_image_size($source_image_info['width'], $source_image_info['height'], $watermark_image_width, $watermark_image_height);

3.6、处理水印前缩放处理

$watermark_resize_image = resize_image($source_image_string, $source_image_info['width'], $source_image_info['height'], $watermark_image_size['width'], $watermark_image_size['height']);
if (empty($watermark_resize_image['data']) || $watermark_resize_image['length'] <= 0) die('Error');

3.7、水印处理

$watermark_image = watermark_image(base64_encode($watermark_resize_image['data']), $watermark_image_size['width'], $watermark_image_size['height'], $watermark_image_file);
if (empty($watermark_image['data']) || $watermark_image['length'] <= 0) die('Error');

4、返回值

4.1、图片类型

$attach_type

4.2、原图

4.2.1、原图二进制数据

$original_image_content

4.2.2、原图大小

$attach_size

4.3、缩略图

4.3.1、缩略图二进制数据

addslashes($thumbnail_image['data'])

4.3.2、缩略图大小

$thumbnail_image['length']

4.4、水印图

4.4.1、水印图二进制数据

addslashes($watermark_image['data'])

4.4.2、水印图大小

$watermark_image['length']

5、入库 SQL 构造

略。

- EOF -

首先我想说,在 FreeBSD 7.2 上真的很折腾,尤其还是 64 位的系统。其次感谢贾同学的鼎力帮助,我们两个在这个环境上至少连续耗费 30 个小时以上。最后请原谅我不写注释以及 MySQL 主从的跳票(敬请期待),请理解我没有贴报错信息——虽然有太多太多,希望本文对有一定基础、且热爱折腾的同学有所帮助。

本文参考资料:张宴《Nginx 0.8.x + PHP 5.2.13(FastCGI)搭建胜过 Apache 十倍的 Web 服务器(第 6 版)》与袁旭东《FreeBSD 上搭建 nginx 0.7.x + PHP 5.2.x (FastCGI) + MySQL 5.1.x》。之所以要单独发文,是因为我在折腾过程中遇到了太多上述二位所没有遇到或者没有在文中叙述的问题。

由于没有搞定 sed 的原因,很遗憾暂时无法发布自动化脚本。先给个半自动的吧。

mkdir /home/work/src/

chown -R work:work /home/work/

cd /home/work/src/

fetch http://ftp.gnu.org/gnu/wget/wget-1.12.tar.gz
tar xzf wget-1.12.tar.gz
cd wget-1.12
./configure
make
make install
cd ..

rehash

wget -c "http://prdownloads.sourceforge.net/pcre/pcre/8.02/pcre-8.02.tar.gz?download"
tar xzf pcre-8.02.tar.gz
cd pcre-8.02
./configure
make
make install
cd ..

wget -c http://nginx.org/download/nginx-0.7.66.tar.gz
tar xzf nginx-0.7.66.tar.gz
cd nginx-0.7.66

vi auto/cc/gcc

# debug
CFLAGS="$CFLAGS -g"

修改为

# debug
# CFLAGS="$CFLAGS -g"

顺便期待 sed 脚本(下文半自动处同)。

./configure --user=work --group=work --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module
make
make install
cd ..

wget -c http://dev.mysql.com/get/Downloads/MySQL-5.1/mysql-5.1.47.tar.gz/from/http://ftp.jaist.ac.jp/pub/mysql/
tar xzf mysql-5.1.47.tar.gz
cd mysql-5.1.47
./configure --prefix=/usr/local/mysql/ --enable-assembler --with-extra-charsets=complex --enable-thread-safe-client --with-big-tables --with-readline --with-ssl --with-embedded-server --enable-local-infile --with-plugins=innobase --with-mysqld-user=work --without-ndb-debug --without-debug --with-charset=utf8 --localstatedir=/database --with-collation=utf8_general_ci

若有独立数据库服务器,只需客户端的话,加“--without-server”参数即可。

make
make install

/usr/local/mysql/bin/mysql_install_db --basedir=/usr/local/mysql --datadir=/database --user=work
chown -R work:work /database
cp support-files/my-large.cnf /etc/my.cnf
cp support-files/mysql.server /etc/rc.mysqld
chmod +x /etc/rc.mysqld
cd ..

pkg_add -r -f libiconv

wget -c "http://downloads.sourceforge.net/mcrypt/libmcrypt-2.5.8.tar.gz?modtime=1171868460&big_mirror=0"
tar xzf libmcrypt-2.5.8.tar.gz 
cd libmcrypt-2.5.8
./configure --prefix=/usr
make
make install
/sbin/ldconfig
cd libltdl
./configure --enable-ltdl-install
make
make install
cd ../../

wget -c "http://downloads.sourceforge.net/mhash/mhash-0.9.9.9.tar.gz?modtime=1175740843&big_mirror=0"
tar xzf mhash-0.9.9.9.tar.gz
cd mhash-0.9.9.9
./configure --prefix=/usr
make
make install
cd ..

wget -c "http://downloads.sourceforge.net/mcrypt/mcrypt-2.6.8.tar.gz?modtime=1194463373&big_mirror=0"
tar xzf mcrypt-2.6.8.tar.gz
cd mcrypt-2.6.8

vi src/rfc2440.c

include <malloc.h>

修改为

include <stdlib.h>

./configure --prefix=/usr
make
make install
cd ..

wget -c http://xmlsoft.org/sources/libxml2-2.7.7.tar.gz
tar xzf libxml2-2.7.7.tar.gz 
cd libxml2-2.7.7
./configure
make
make install
cd ..

wget -c http://curl.haxx.se/download/curl-7.20.0.tar.gz
tar xzf curl-7.20.1.tar.gz
cd curl-7.20.1
./configure
make
make install
cd ..

wget -c "http://prdownloads.sourceforge.net/libpng/libpng-1.4.2.tar.gz?download"
tar xzf libpng-1.4.2.tar.gz
cd libpng-1.4.2
./configure
make
make install
cd ..

wget -c http://www.ijg.org/files/jpegsrc.v8a.tar.gz
tar xzf jpegsrc.v8a.tar.gz
cd jpeg-8a
./configure
make
make install
cd ..

wget -c http://ftp.gnu.org/pub/gnu/make/make-3.79.tar.gz
tar xzf make-3.79.tar.gz
cd make-3.79
./configure
make
make install
cd ..

wget -c http://ftp.twaren.net/Unix/NonGNU/freetype/freetype-2.1.10.tar.gz
tar xzf freetype-2.1.9.tar.gz
cd freetype-2.1.9
/usr/local/bin/make CFLAGS="-O3 -fPIC"
/usr/local/bin/make
/usr/local/bin/make install
cd ..

wget -c http://ftp.gnu.org/gnu/libtool/libtool-2.2.tar.gz
tar xzf libtool-2.2.tar.gz
cd libtool-2.2
./configure
make
make install
cd ..

wget -c http://www.php.net/get/php-5.2.13.tar.gz/from/this/mirror
wget -c http://php-fpm.org/downloads/php-5.2.13-fpm-0.5.13.diff.gz
tar xzf php-5.2.13.tar.gz
gzip -cd php-5.2.13-fpm-0.5.13.diff.gz | patch -d php-5.2.13 -p1
cd php-5.2.13
./configure --prefix=/usr/local/php --with-config-file-path=/etc --with-mysql=/usr/local/mysql --with-mysqli=/usr/local/mysql/bin/mysql_config --with-iconv-dir=/usr --with-freetype-dir --with-jpeg-dir --with-png-dir --with-zlib --with-libxml-dir=/usr --enable-xml --disable-rpath --enable-discard-path --enable-safe-mode --enable-bcmath --enable-shmop --enable-sysvsem --enable-inline-optimization --with-curl --with-curlwrappers --enable-mbregex --enable-fastcgi --enable-fpm --enable-force-cgi-redirect --enable-mbstring --with-mcrypt --with-gd --enable-gd-native-ttf --with-openssl --with-mhash --enable-pcntl --enable-sockets --with-ldap-sasl --with-xmlrpc --enable-zip --enable-soap
make
make install

cp php.ini-dist /etc/php.ini
cd ..

pkg_add -r -f autoconf262

wget -c http://pecl.php.net/get/memcache-2.2.5.tgz
tar xzf memcache-2.2.5.tgz
cd memcache-2.2.5
/usr/local/php/bin/phpize
./configure --with-php-config=/usr/local/php/bin/php-config
make
make install
cd ..

wget -c http://bart.eaccelerator.net/source/0.9.6/eaccelerator-0.9.6.tar.bz2
tar xzf eaccelerator-0.9.6.tar.bz2
cd eaccelerator-0.9.6
/usr/local/php/bin/phpize
./configure --enable-eaccelerator=shared --with-php-config=/usr/local/php/bin/php-config
make with-eaccelerator-shared-memory=yes
make install
cd ..

wget -c http://pecl.php.net/get/PDO_MYSQL-1.0.2.tgz
tar xzf PDO_MYSQL-1.0.2.tgz
cd PDO_MYSQL-1.0.2
/usr/local/php/bin/phpize
./configure --with-php-config=/usr/local/php/bin/php-config --with-pdo-mysql=/usr/local/mysql
make
make install

由于死活没有成功安装 ImageMagick(低版本装了 PHP 不认,高版本报 png.c 错误),因此使用 GD 代替。安装后的配置方法与调整细节,可参见上文所述两篇参考文献。期待同行交流。

谨以此文,献给 12 年的今天离开我们的所有人。

易先生的要求,我对《快速搭建 FAMP 环境》一文作如下补充。

对 MySQL 依次进行 configure、make、make install 后,还需要执行初始化数据库、配置权限等操作,具体如下:

www# /usr/local/mysql/bin/script/mysql_install_db --user=mysql

www# pw groupadd mysql
www# pw useradd mysql -g mysql -s /sbin/nologin

www# chown -R mysql:mysql /usr/local/mysql/var

www# /usr/local/mysql/bin/mysqld_safe --user=mysql &
安装 PureFTPd 的过程简单,不再赘述。但经常能遇到这样的报错:

Shared object "libmysqlclient.so.15" not found, required by "pure-ftpd" 一般遇到这样的情况,可以这样操作:

- 阅读剩余部分 -

MySQL 是一个小型关系型数据库管理系统,被广泛用于各种中小 Web 应用中。常见的应用架构有:

1、单点(Single):适合小规模应用;
2、复制(Replication):适合中小规模应用;
3、集群(Cluster):适合大规模应用。

曾写过 httpd 服务端与 MySQL 数据库分开部署的情况的文章,那属于单点应用的范畴。而随着业务需求的不断增长,更高的负载量、更安全的系数、更可靠的存储,这一切都会让依然停留在单点应用的你举步维艰。

令人高兴的是,MySQL 早在 3.23.15 版本开始就提供了单向的异步复制功能。利用该功能可以实现两种数据库异步复制:主从模式(A -> B,或 A -> B、C、D)、互相备份模式(A <=> B)。后者也称“双向热备”或“双机热备”,是前者的扩展与补充。

值得注意的是,这种复制是异步的,有别于 MySQL 的同步复制实现(也称做 MySQL 集群、MySQL Cluster,本文不作讨论,感兴趣的话可参见这里)。

相关原理:当主库有更新的时候,主库会把更新操作的 SQL 写入二进制日志 (Bin log),并维护一个二进制日志文件的索引,以便于日志文件轮回(Rotate)。在从库启动异步复制的时候,从库会开启两个 I/O 线程,其中一个线程连接主库,要求主库把二进制日志的变化部分传给从库,并把传回的日志写入本地磁盘。另一个线程则负责读取本地写入的二进制日志,并在本地执行,以反映出这种变化。较老的版本在复制的时候只启用一个 I/O 线程,实现这两部分的功能。

需要注意的地方:

1、主库必须启用 Bin log,主库和从库必须有唯一的 Server Id;
2、从库必须清楚了解从主库的哪一个 Bin log 文件的哪一个偏移位置起开始复制;
3、从库可以从主库只复制指定的数据库,或者数据库的某些数据表;
4、主库和从库的数据库名称可以不一样,不过还是推荐使用一样的名称;
5、主库和从库的 MySQL 版本需保持一致。

由于 MySQL 复制功能的设置都在其配置文件 my.cnf 中体现,因此互相备份模式与主从模式大同小异。本文所涉方案为后者。

首先分别在两台服务器上下载、解压缩版本相同的 MySQL 源码包,并编译安装。此过程在此略过,并假设:

1、两台机器在同一子网内,且 IP 地址分别为 192.168.0.31(以下简称 A 机器) 与 192.168.0.15(以下简称 B 机器);
2、两台机器的数据库版本、目录、初始的库、表均一致;
3、MySQL 配置文件都位于 /etc/my.cnf;
4、需要同步的库:dbname,不需要同步的库:mysql、test。

在 A 机器上添加 mysqlrepl 为同步帐号:

GRANT REPLICATION SLAVE ON *.* TO 'mysqlrepl'@'192.168.0.15' IDENTIFIED BY '密码'; 然后:

vi /etc/my.cnf 修改:

# 日志的名称
log-bin=mysql-bin
# 主服务器 ID
server-id=1
# 需要备份的库
binlog-do-db=dbname
# 忽略的库
binlog-ignore-db=mysql
binlog-ignore-db=test
在 B 机器上:

vi /etc/my.cnf 修改:

# 日志的名称
log-bin=mysql-bin
# 从服务器 ID
server-id=2
# 主服务器的 IP 地址或者域名
master-host=192.168.0.31
# 主数据库的端口号
master-port=3306
# 同步数据库的用户
master-user=mysqlrepl
# 同步数据库的密码
master-password=
# 如果从服务器发现主服务器断开,重新连接的时间差(秒)
master-connect-retry=30
# 需要同步的库
replicate-do-db=dbname
# 忽略的库
replicate-ignore-db=mysql
replicate-ignore-db=test
重启两边的 MySQL,在 B 机器上登入 mysqld,执行:

mysql>slave start; 然后可以查看同步配置情况。在 A 机器上执行:

mysql>show master status; 在 B 机器上执行:

mysql>show slave status; 截止这里,我们只实现了 A -> B 的复制,要实现双向热备,仅需要将上面的步骤倒过来执行一遍即可。