月度归档:2016年11月

隐藏Nginx和PHP版本号

配置完一台服务器后,并不是就可以高枕无忧了,前不久刚刚爆发的PHP 5.3.9版本的漏洞也搞得人心惶惶,所以说经常关注安全公告并及时升级服务器也是必要的。一般来说,黑客攻击服务器的首要步骤就是收集信息,比如说你的软件版本,这些将成为下一步有针对性攻击的依据。所以说一定程度的隐藏这些信息就显得非常有必要了,本文将简单介绍如何在网络上隐藏Nginx版本号以及PHP的版本号。

1.隐藏Nginx版本号,Nginx的版本号主要在两个地方会有,一个是HTTP header,有个Server:nginx/1.x.x类似会暴露Web服务器所用软件名称以及版本号,这个也是大多数Web服务器最容易暴露版本号的地方,第二个地方是Nginx出错页面,比如404页面没有找到等,这是如果用户没有指定页面的话,那么Nginx自己的页面会有版本戳记。

不过幸运的是对于这两个地方的版本号隐藏,Nginx都提供了简单的办法一步到位,参考server_tokens。通过在配置文件的http节配置server_tokens off来达到我们目的。

  http { # ...省略一些配置 server_tokens off; }

最后别忘了使用命令nginx -s reload刷新当前配置。完成后你可以查看所有页面的响应头或者错误页,看看是不是只看到nginx字样而看不到版本号?什么?你想连nginx也改掉?呵呵,这个恐怕就麻烦了,需要改动Nginx源代码然后重新编译,感兴趣的童鞋可以参考《Linux/VPS环境下Nginx安全配置小记(1)》

2.隐藏PHP的版本号,PHP容易暴露的版本号在什么地方呢?其实也是在HTTP头,以类似X-Powered-By: PHP/5.2.11这种形式存在,大家可能会想到会不会是Nginx问题,而去到Nginx里面找相关配置,呵呵,其实这个是在PHP的配置文件php.ini里改动,打开php.ini,找到下面叙述:

;;;;;;;;;;;;;;;;; ; Miscellaneous ; ;;;;;;;;;;;;;;;;;   ; Decides whether PHP may expose the fact that it is installed on the server ; (e.g. by adding its signature to the Web server header).  It is no security ; threat in any way, but it makes it possible to determine whether you use PHP ; on your server or not. ; http://php.net/expose-php expose_php = On

expose_php = On改为expose_php = Off就搞定了,当然,对于Apache服务器还有另外一个方法可以直接尝试在.htaccess文件中Header unset X-Powered-By,删除X-Powered-By节,不过我还是建议改动php.ini的expose_php。

单用户模式下 /etc/fstab文件不能修改的解决办法

1。进入Linux单用户模式

     执行 root# mount -o remount,rw /

     然后/etc/fstab就可以修改了

2。用光盘进入Linux修复模式 (光盘启动按F2 接着输入linux rescue回车进入)

    然后修改fstab

    注意进入修复模式后fstab路径为

   vi /mnt/sysimage/etc/fstab

2种方法解决mysql主从不同步

今天发现Mysql的主从数据库没有同步
 
先上Master库:
 
mysql>show processlist;   查看下进程是否Sleep太多。发现很正常。
show master status; 也正常。
 
mysql> show master status;
+——————-+———-+————–+——————————-+
| File              | Position | Binlog_Do_DB | Binlog_Ignore_DB              |
+——————-+———-+————–+——————————-+
| mysqld-bin.000001 |     3260 |              | mysql,test,information_schema |
+——————-+———-+————–+——————————-+
1 row in set (0.00 sec)
 
再到Slave上查看
 
mysql> show slave status\G                                                
 
Slave_IO_Running: Yes
Slave_SQL_Running: No
 
可见是Slave不同步
 
下面介绍两种解决方法:
 
 
方法一:忽略错误后,继续同步
该方法适用于主从库数据相差不大,或者要求数据可以不完全统一的情况,数据要求不严格的情况
 
解决: 
stop slave;
 
#表示跳过一步错误,后面的数字可变
set global sql_slave_skip_counter =1;
start slave;
 
之后再用mysql> show slave status\G  查看:
 
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
 
ok,现在主从同步状态正常了。。。
 
 
方式二:重新做主从,完全同步
该方法适用于主从库数据相差较大,或者要求数据完全统一的情况
 
解决步骤如下:
 
1.先进入主库,进行锁表,防止数据写入
 
使用命令:
 
mysql> flush tables with read lock;
 
注意:该处是锁定为只读状态,语句不区分大小写
 
2.进行数据备份 
 
#把数据备份到mysql.bak.sql文件
[root@server01 mysql]#mysqldump -uroot -p -hlocalhost > mysql.bak.sql
这里注意一点:数据库备份一定要定期进行,可以用shell脚本或者python脚本,都比较方便,确保数据万无一失
3.查看master 状态
 
mysql> show master status;
+——————-+———-+————–+——————————-+
| File              | Position | Binlog_Do_DB | Binlog_Ignore_DB              |
+——————-+———-+————–+——————————-+
| mysqld-bin.000001 |     3260 |              | mysql,test,information_schema |
+——————-+———-+————–+——————————-+
1 row in set (0.00 sec)
 
4.把mysql备份文件传到从库机器,进行数据恢复
 
#使用scp命令
[root@server01 mysql]# scp mysql.bak.sql root@192.168.128.101:/tmp/
 
5.停止从库的状态
mysql> stop slave;
 
 
6.然后到从库执行mysql命令,导入数据备份
 
mysql> source /tmp/mysql.bak.sql
 
7.设置从库同步,注意该处的同步点,就是主库show master status信息里的| File| Position两项
 
change master to master_host = ‘192.168.128.100’, master_user = ‘rsync’, master_port=3306, master_password=”, master_log_file = ‘mysqld-bin.000001’, master_log_pos=3260;
 
8.重新开启从同步
mysql> start slave;
 
9.查看同步状态
mysql> show slave status\G  查看:
 
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
 
好了,同步完成啦。

mysql运维-slave_skip_errors

1 简介

    mysql在主从复制过程中,由于各种的原因,从服务器可能会遇到执行BINLOG中的SQL出错的情况,在默认情况下,服务器会停止复制进程,不再进行同步,等到用户自行来处理。

    slave-skip-errors的作用就是用来定义复制过程中从服务器可以自动跳过的错误号,当复制过程中遇到定义的错误号,就可以自动跳过,直接执行后面的SQL语句。

2 官方参考


Command-Line Format

–slave-skip-errors=name

System Variable Name

slave_skip_errors

Variable Scope

Global

Dynamic Variable

No

 

Permitted Values

Type

string

Default

OFF

Valid Values

OFF

[list of error codes]

all

ddl_exist_errors

    slave_skip_errors选项有四个可用值,分别为:off,all,ErorCode,ddl_exist_errors

     默认情况下该参数值是off,我们可以列出具体的error code,也可以选择all,mysql5.6及MySQL Cluster NDB 7.3以及后续版本增加了参数ddl_exist_errors,该参数包含一系列error code(1007,1008,1050,1051,1054,1060,1061,1068,1094,1146)

    一些error code代表的错误如下:

    1007:数据库已存在,创建数据库失败

    1008:数据库不存在,删除数据库失败

    1050:数据表已存在,创建数据表失败

    1051:数据表不存在,删除数据表失败

    1054:字段不存在,或程序文件跟数据库有冲突

    1060:字段重复,导致无法插入

    1061:重复键名

    1068:定义了多个主键

    1094:位置线程ID

    1146:数据表缺失,请恢复数据库

    1053:复制过程中主服务器宕机

    1062:主键冲突 Duplicate entry ‘%s’ for key %d    my.cnf中的写法:

[sql] view plain copy

  1. slave_skip_errors=1062,1053  
  2. slave_skip_errors=all  
  3. slave_skip_errors=ddl_exist_errors  

    作为mysql启动参数的写法:

[sql] view plain copy

  1. –slave-skip-errors=1062,1053  
  2. –slave-skip-errors=all  
  3. –slave-skip-errors=ddl_exist_errors  

    从数据库中查看该参数的值:

[sql] view plain copy

  1. mysql> show variables like ‘slave_skip%’;  
  2. +——————-+——-+  
  3. | Variable_name     | Value |  
  4. +——————-+——-+  
  5. | slave_skip_errors | 1007  |  
  6. +——————-+——-+  

3 举例分析

    3.1 测试说明
    配置好MySQL主从同步,然后在从上写入数据,造成主从不一致。
    3.2 准备测试表结构
    在主机上创建表:

[sql] view plain copy

  1. create table replication (c1 int not null primary key, c2 varchar(10));  

    3.3 准备测试数据

    在主机上插入基础数据

[sql] view plain copy

  1. mysql> insert into replication values (1, ‘test1’);  
  2. mysql> insert into replication values (2, ‘test2’);  

    此时,主机从机replication表里面都有两条记录
    3.4 开始测试
    从机插入一条记录

[sql] view plain copy

  1. mysql> insert into replication values (3, ‘test3’);  

    然后在主机上执行相同的操作

[sql] view plain copy

  1. mysql> insert into replication values (3, ‘test3’);  

    在从机上查看复制状态

[sql] view plain copy

  1. mysql> show slave status \G  
  2. *************************** 1. row ***************************  
  3.                Slave_IO_State: Waiting for master to send event  
  4.                   Master_Host: 192.168.1.222  
  5.                   Master_User: repl  
  6.                   Master_Port: 3306  
  7.                 Connect_Retry: 60  
  8.               Master_Log_File: mysql-bin.000003  
  9.           Read_Master_Log_Pos: 16700  
  10.                Relay_Log_File: mysql-relay-bin.000003  
  11.                 Relay_Log_Pos: 16595  
  12.         Relay_Master_Log_File: mysql-bin.000003  
  13.              Slave_IO_Running: Yes  
  14.             Slave_SQL_Running: No  
  15.               Replicate_Do_DB:   
  16.           Replicate_Ignore_DB:   
  17.            Replicate_Do_Table:   
  18.        Replicate_Ignore_Table: mysql.ibbackup_binlog_marker  
  19.       Replicate_Wild_Do_Table:   
  20.   Replicate_Wild_Ignore_Table: mysql.backup_%  
  21.                    Last_Errno: 1062  
  22.                    Last_Error: Error ‘Duplicate entry ‘3‘ for key ‘PRIMARY on query. Default database‘test’. Query: ‘insert into replication values (3, ‘test3‘)’  
  23.                  Skip_Counter: 0  
  24.           Exec_Master_Log_Pos: 16425  
  25.               Relay_Log_Space: 17544  

    可以看到:sql线程已经停止工作 Slave_SQL_Running: No

                        错误号为:Last_Errno: 1062

                        错误信息为:Last_Error: Error ‘Duplicate entry ‘3’ for key ‘PRIMARY” on query. Default database: ‘test’. Query: ‘insert into replication values (3, ‘test3′)’

    如果我们在my.cnf中加入如下选项,则可跳过此错误,数据同步继续进行。

[sql] view plain copy

  1. [mysqld]  
  2. slave_skip_errors=1062  

    具体测试方法同上,大家可自己验证。

4 从backup恢复时从机复制出错的一些解释

    mysql企业版备份工具meb提供在线热备功能,如果在备份过程中执行ddl操作,从机需要从主机的备份恢复时可能会异常,从而导致从机同步数据失败。原因是从机恢复时需要先从备份文件恢复(包含备份过程中执行的ddl语句),同步时不是从全备后的最后一个位置同步,而是从ddl的上个位置同步,如果再次执行该ddl语句在从机上不会造成冲突,则同步继续,如果会造成冲突,同步终止。解决此冲突的办法是在my.cnf文件中加入一行

[sql] view plain copy

  1. [mysqld]  
  2. slave_skip_errors=ddl_exist_errors  

5 注意事项

    5.1 该参数为全局静态参数,不能动态调整,可在my.cnf中加入该参数列表后重启mysql服务器生效。

    5.2 必须注意的是,启动这个参数,如果处理不当,很可能造成主从数据库的数据不同步,在应用中需要根据实际情况,如果对数据完整性要求不是很严格,那么这个选项确实可以减轻维护的成本


解决办法一、
Slave_SQL_Running: No
1.程序可能在slave上进行了写操作
2.也可能是slave机器重起后,事务回滚造成的.



 Last_SQL_Errno: 1677
 Last_SQL_Error: Column 1 of table 'test.t' cannot be converted from type 'int' to type 'bigint(20)'
解决方法:这个案例是从网上找到的,自己动手实验了一把。从错误信息来看表面上是由于在slave上无法执行一条转换字段类型的SQL语句。实际上并不是有这种语句直接引起的,而是间接引起的(之前某些操作导致主从表字段类型不一致,接下来对这个表进行DML时就会报错)。它的意思是在对这个表t进行DML操作时,发现主从上表结果不一致,比如这里是说在主上t的字段1是int类型,但是从上t的字段1是bigint类型,所以报错。那么为什么要报错呢?这是从安全角度考虑,因为如果字段类型不一致可能会导致数据截断之类的问题。那么解决方法呢?通过参数slave_type_conversions进行控制,它有三种取值:
ALL_LOSSY:仅支持有损转换,什么叫有损?比如一个值本来是bigint存储为9999999999999,现在转换为int类型势必会要截断从而导致数据不一致。
ALL_NON_LOSSY:仅支持无损转换,只能在无损的情况下才能进行转换
ALL_LOSSY,ALL_NON_LOSSY:有损/无算转换都支持
空,即不设置这个参数:必须主从的字段类型一模一样。
注意: 前面说的这几中情况都只在binlog_format=ROW的情况下才有效。


 Last_SQL_Errno: 1194
 Last_SQL_Error: Error 'Table 'traincenter' is marked as crashed and should be repaired' on query. Default database: 'basketballman'. Query: 'update traincenter set points='4',pointstime='1361912066' where uid = '1847482697' limit 1'
 解决方法:myisam表traincenter损坏,直接repair table即可。至于为什么myisam类型表比innodb更容易损坏,我觉得有两个原因:1,innodb有double write机制,损坏或者half write的页可以用它恢复,第二innodb是事务引擎,都有操作都是事务的,而myisam是非事务的,存在写一半但是操作终止情况。


 Last_IO_Errno: 1236
 Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'Could not find first log file name in binary log index file'
 解决方法:主库上的binlog文件已经不存在但是在index file中确有相应记录存在。我这里发生这个错误的原因在于由于复制中断时间很长,报警出来一直没人处理,这个中断时间超过master上binlog超期时间,等恢复复制时需要的binlog已经由于其超期而被删掉,没办法只好重建这个实例了。以大家都要引以为戒
stop slave;
reset slave; 
slave start;


 Last_IO_Errno: 1593
 Last_IO_Error: Fatal error: The slave I/O thread stops because master and slave have equal MySQL server ids; these ids must be different for replication to work (or the --replicate-same-server-id option must be used on slave but this does not always make sense; please check the manual before using it).
 解决方法:主从配置的server-id一样,而在主从复制环境中server-id一样的binlog events都会被过滤掉。具体server-id的含义可以了解一下复制原理。这个一般是因为拷贝配置文件时忘记修改server-id导致,遇到这类问题也比较容易,平时操作谨慎一点即可。


 Last_Errno: 1053
 Last_Error: Query partially completed on the master (error on master: 1053) and was aborted. There is a chance that your master is inconsistent at this point. If you are sure that your master is ok, run this query manually on the slave and then restart the slave with SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; START SLAVE; . Query: 'insert into ...
 解决方法:查询在master上部分完成,然后终止了。这马上又能想到是myisam表,结果也正是这样。由于myisam不支持事务所以可能存在一个查询完成一部分然后失败的情况。解决方法一般也就是提示信息给出的跳过一个binlog event。不过确认跳过之前最好还是查询一下master上是否真的存在相应的记录,因为错误信息同时还会给出它认为在master上执行一部分然后终止的查询语句。


 Last_SQL_Errno: 1666
 Last_SQL_Error: Error executing row event: 'Cannot execute statement: impossible to write to binary log since statement is in row format and BINLOG_FORMAT = STATEMENT.' 
 解决方法:这个案例的背景是做一个ABC结构的复制,B、C中设定的binlog_format=statement,A中的是MIXED,所以当B尝试重做A过来的relay log,然后记录binlog(传给C)时发现relay log的binlog_format与自己设定的binlog_format不一致。我当时就是直接先更改BC的binlog_format=MIXED解决。


 Last_Errno: 1032
 Last_Error: Could not execute Update_rows event on table db.table; Can't find record in 'table', Error_code: 1032; handler error HA_ERR_KEY_NOT_FOUND; the event's master log mysql-bin.000064, end_log_pos 158847
解决方法:这个是在binlog_format=row复制下发生的。原因是因为row格式复制是最严格的,所以在mysql看来如果在从库上找不到要更新的这条记录,那么就代表主从数据不一致,因此报错。另外顺便说一句,对于row格式binlog,如果某个更新操作实际上并没有更新行,这个操作是不会记binlog的,因为row格式的binlog宗旨就是只记录发生了改变的行。所以这个解决办法根据你自己实际应用来定,最好的方法还是重做slave吧,这样更放心。


 Last_Errno: 28
 Last_Error: Error in Append_block event: write to '/tmp/SQL_LOAD-32343798-72213798-1.data' failed
 解决方法: 首先说错误原因:主库执行load data infile,同步到从库后load data infile存放的文件默认是放在/tmp(由参数slave_load_tmpdir控制),而/tmp空间不够因此报错。因此只要将从库上slave_load_tmpdir设置到一个磁盘空间足够大的分区就行。

利用Nginx的ngx_http_image_filter_module做实时的图片压缩缩略图

你还在用 ImageMagick 生成网站的上传图片缩略图吗?其实有更好的方法一部到位,简单有效。

现而今有非常多的云存储服务支持图片空间,并根据设定的规则来生成空间里面的图片缩略图了,例如 UpYun、Aliyun OSS 都支持。

但有时候我们会因为一些其他的考虑(例如:价格因素),选择本地文件存储上传文件,这个时候,我们如何实现图片缩略图呢?

其实 Nginx 内置了 ngx_http_image_filter_module 可以帮助你处理图片:

  • 缩放
  • 裁剪
  • 调整图片品质
  • 旋转
  • 锐化

我们常用的可能就是缩放和裁剪了,根据业务和设计需要,在合适的位置不同尺寸的缩略图。

安装

可能一些标准的 Nginx 安装包没有带这个 module 的,你需要使用 Nginx 官方的源安装,并额外安装 nginx-module-image-filter 这个包:

curl -O http://nginx.org/keys/nginx_signing.key
sudo apt-key add nginx_signing.key
sudo bash -c 'echo "deb http://nginx.org/packages/ubuntu/ $(lsb_release -cs) nginx
deb-src http://nginx.org/packages/ubuntu/ $(lsb_release -cs) nginx" > /etc/apt/sources.list.d/nginx-stable.list' sudo apt-get update
sudo apt-get install -y nginx nginx-module-image-filter 

也可以直接用做好的 安装脚本

curl -sSL https://git.io/vVHhf | bash 

场景

以 Ruby China 的场景为例,我设计了下面几种不同的缩略图版本:

版本名称 限定尺寸 (px) 缩略方式
large 1920 限定宽度,高度自适应
lg 192×192 固定宽度和高度
md 96×96 固定宽度和高度
sm 48×48 固定宽度和高度
xs 32×32 固定宽度和高度

配置 Nginx

假定我们的上传文件存放在 /var/www/homeland/public/uploads 里面。

下面是 Ruby China 这个缩略图规则的完整 Nginx 配置:

/etc/nginx/nginx.conf

user nobody;
worker_processes auto;
pid /var/www/pids/nginx.pid;
daemon on;

# 载入 ngx_http_image_filter_module
load_module modules/ngx_http_image_filter_module.so;

http {
   # ... 省略
} 

/etc/nginx/conf.d/ruby-china.conf

proxy_cache_path /var/www/cache/uploads-thumb levels=1:2 keys_zone=uploads_thumb:10m max_size=50G; server { listen 80 default_server; listen 443 ssl http2; root /var/www/homeland/public; location /uploads { expires 7d; gzip_static on; add_header Cache-Control public; add_header X-Pownered "nginx_image_filter"; # HTTP Response Header 增加 proxy_cache 的命中状态,以便于以后调试,检查问题  add_header X-Cache-Status $upstream_cache_status; proxy_pass http://127.0.0.1/_img/uploads; # 将缩略图缓存在服务,避免每次请求都重新生成  proxy_cache uploads_thumb; # 当收到 HTTP Header Pragma: no-cache 的时候,忽略 proxy_cache  # 此配置能让浏览器强制刷新的时候,忽略 proxy_cache 重新生成缩略图  proxy_cache_bypass $http_pragma; # 由于 Upload 文件一般都没参数的,所以至今用 host + document_uri 作为  proxy_cache_key "$host$document_uri"; # 有效的文件,在服务器缓存 7 天  proxy_cache_valid 200 7d; proxy_cache_use_stale error timeout invalid_header updating; proxy_cache_revalidate on; # 处理 proxy 的 error  proxy_intercept_errors on; error_page 415 = /assets/415.png; error_page 404 = /assets/404.png;
  } # 原始图片  location /_img/uploads { alias /var/www/homeland/public/uploads/$filename; expires 7d;
  } # 缩略图  location ~* /_img/uploads/(.+)!(large|lg|md|sm|xs)$ { set $filename /uploads/$1; if (-f $filename) { break;
    } # 根据 URL 地址 ! 后面的图片版本来准备好需要的参数(宽度、高度、裁剪或缩放)  set $img_version $2; set $img_type resize; set $img_w -; set $img_h -; if ($img_version = 'large') { set $img_type resize; set $img_w 1920;
    } if ($img_version = 'lg') { set $img_type crop; set $img_w 192; set $img_h 192;
    } if ($img_version = 'md') { set $img_type crop; set $img_w 96; set $img_h 96;
    } if ($img_version = 'sm') { set $img_type crop; set $img_w 48; set $img_h 48;
    } if ($img_version = 'xs') { set $img_type crop; set $img_w 32; set $img_h 32;
    } rewrite ^ /_$img_type;
  } # 缩放图片的处理  location /_resize { alias /var/www/homeland/public$filename; image_filter resize $img_w $img_h; image_filter_jpeg_quality 95; image_filter_buffer 20M; image_filter_interlace on;
  } # 裁剪图片的处理  location /_crop { alias /var/www/homeland/public$filename; image_filter crop $img_w $img_h; image_filter_jpeg_quality 95; image_filter_buffer 20M; image_filter_interlace on;
  }
} 

你可能会觉得上面为何写得这么绕啊!

没办法,Nginx 不支持在 if {} 这个 block 里面用 image_filter 函数,image_filter 的第一个参数 resize/crop 也不能用变量的方式传输,所以…

然后,重启 Nginx,就可以尝试了。

注意点

  • 由于开启了 proxy_cache 缩略图将会在服务器上以文件的形式存在,你需要确保每次上传新文件名尽可能的是唯一的(例如用时间,或文件内容 MD5 作为文件名,参考 CarrieWave 文件名设计
  • 浏览器强制刷新,会发起 Pragma: no-cache 的 Request Header,Nginx 会忽略 proxy_cache 重新生成图片。

效果演示

扩展阅读

配置mysql5.5主从服务器(转)

配置mysql5.5主从服务器

Mysql提供了主从复制的功能,作用类似oracle的dataguard,但是配置和管理远比dataguard简单,没有所谓的物理备库和逻辑备库之分,也没有提供相应的数据保护模式,只有master和slave数据库角色,这种架构广泛应用于各大门户,游戏网站中,提供数据库的读写分离功能;相比之下oracle的读写功能到了11g版本才能借助active dataguard完美实现,否则就只能用logical standby,但又有许多的数据类型和操作不被逻辑备库支持!先前使用过mysql5.1.36版本的master-slave架构做CMS数据库的读写分离,有着非常痛苦的使用经历,经常由于各种各样的原因的导致主从数据不同步,然后又没有提供额外的同步机制(确切的说是没学会),于是经常在下班时间重构主从架构;下一步将在mysql5.5平台测试mha架构,故本文记录下如何在mysql5.5平台下构建主从数据库复制环境;另外mysql的主从也可看为是mysql的实时备份,有一定的数据灾备功能,mysql本身没有提供类似oracle rman的热备份工具,因而多数场景下会使用主从对数据库做一个实时备份,以备不时只需!PS:一直比较不解的mysql如何做基于时间或者SCN的不完全恢复?难道真要一个个binlog分析过去?

一、安装MySQL

说明:在两台MySQL服务器192.168.1.2和192.168.1.3上分别进行如下操作,安装MySQL 5.5.22

 二、配置MySQL主服务器(192.168.1.2)
mysql  -uroot  -p    #进入MySQL控制台
create database osyunweidb;   #建立数据库osyunweidb
insert into mysql.user(Host,User,Password) values(‘localhost’,’osyunweiuser’,password(‘Mypasswd8800’));   #创建用户osyunweiuser

#建立MySQL主从数据库同步用户osyunweidbbak密码Mypasswd8800 

flush privileges;   #刷新系统授权表

#授权用户osyunweidbbak只能从192.168.1.3这个IP访问主服务器192.168.1.2上面的数据库,并且只具有数据库备份的权限
grant replication slave  on *.* to ‘osyunweidbbak’@’192.168.1.3’ identified by ‘Mypasswd8800’ with grant option; 

三、把MySQL主服务器192.168.1.2中的数据库osyunweidb导入到MySQL从服务器192.168.1.3中
1、导出数据库osyunweidb

mysqldump -u root -p osyunweidb > /home/osyunweidbbak.sql    #在MySQL主服务器进行操作,导出数据库osyunweidb到/home/osyunweidbbak.sql 

备注:在导出之前可以先进入MySQL控制台执行下面命令

flush tables with read lock;    #数据库只读锁定命令,防止导出数据库的时候有数据写入

unlock tables;   #解除锁定

2、导入数据库到MySQL从服务器

mysql  -u root -p  #进入从服务器MySQL控制台

create database osyunweidb;   #创建数据库

use osyunweidb    #进入数据库

source  /home/osyunweidbbak.sql  #导入备份文件到数据库

mysql -u osyunweidbbak -h 192.168.1.2 -p  #测试在从服务器上登录到主服务器
四、配置MySQL主服务器的my.cnf文件
vi /etc/my.cnf   #编辑配置文件,在[mysqld]部分添加下面内容
server-id=1   #设置服务器id,为1表示主服务器,注意:如果原来的配置文件中已经有这一行,就不用再添加了。
log-bin=mysql-bin  #启动MySQ二进制日志系统,注意:如果原来的配置文件中已经有这一行,就不用再添加了。
binlog-do-db=osyunweidb  #需要同步的数据库名,如果有多个数据库,可重复此参数,每个数据库一行
binlog-ignore-db=mysql   #不同步mysql系统数据库
service mysqld  restart  #重启MySQL
mysql -u root -p   #进入mysql控制台
show master status;  查看主服务器,出现以下类似信息
+——————+———-+————–+——————+
| File                        | Position  | Binlog_Do_DB | Binlog_Ignore_DB |
+——————+———-+————–+——————+
| mysql-bin.000019 |    7131    | osyunweidb    | mysql                  |
+——————+———-+————–+——————+
1 row in set (0.00 sec)
注意:这里记住File的值:mysql-bin.000019和Position的值:7131,后面会用到。
五、配置MySQL从服务器的my.cnf文件
vi /etc/my.cnf   #编辑配置文件,在[mysqld]部分添加下面内容
server-id=2   #配置文件中已经有一行server-id=1,修改其值为2,表示为从数据库
log-bin=mysql-bin  #启动MySQ二进制日志系统,注意:如果原来的配置文件中已经有这一行,就不用再添加了。
replicate-do-db=osyunweidb   #需要同步的数据库名,如果有多个数据库,可重复此参数,每个数据库一行
replicate-ignore-db=mysql   #不同步mysql系统数据库
:wq!    #保存退出
service mysqld restart   #重启MySQL
注意:MySQL 5.1.7版本之后,已经不支持把master配置属性写入my.cnf配置文件中了,只需要把同步的数据库和要忽略的数据库写入即可。
mysql  -u root -p  #进入MySQL控制台
slave stop;   #停止slave同步进程
change master to master_host=’192.168.1.2′,master_user=’osyunweidbbak’,master_password=’Mypasswd8800′,master_log_file=’mysql-bin.000019′ ,master_log_pos=7131;    #执行同步语句
slave start;    #开启slave同步进程
SHOW SLAVE STATUS\G   #查看slave同步信息,出现以下内容
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.1.2
                  Master_User: osyunweidbbak
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000019
          Read_Master_Log_Pos: 7131
               Relay_Log_File: MySQLSlave-relay-bin.000002
                Relay_Log_Pos: 253
        Relay_Master_Log_File: mysql-bin.000019
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB: osyunweidb
          Replicate_Ignore_DB: mysql
           Replicate_Do_Table:
       Replicate_Ignore_Table:
1 row in set (0.00 sec)
注意查看:
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
以上这两个参数的值为Yes,即说明配置成功!
 

六、测试MySQL主从服务器双机热备是否成功
1、进入MySQL主服务器

mysql -u root -p  #进入主服务器MySQL控制台

use osyunweidb   #进入数据库

CREATE TABLE test ( id int not null primary key,name char(20) );   #创建test表
2、进入MySQL从服务器

mysql -u root -p  #进入MySQL控制台

use osyunweidb   #进入数据库

show  tables;  #查看osyunweidb表结构,会看到有一个新建的表test,表示数据库同步成功

至此,MySQL数据库配置主从服务器实现双机热备实例教程完成

mysql slave同步错误:Last_Errno: 1062解决办法

场景重现:

      MySQL 双主实现同步之后,同步机器IP设置为:192.168.101.118和192.168.101.119

在同步数据库中创建一个表

 create table test (tno int(5),
tname char(10),
primary key(tno));

然后在118端插入数据如下:

+——-+———+
| tno   | tname   |
+——-+———+
| 10001 | liming  |
| 10002 | linxiao |

在119端实现了同步:

+——-+———+
| tno   | tname   |
+——-+———+
| 10001 | liming  |
| 10002 | linxiao |

然后把119的数据库关闭(模拟119机器环境突然宕机)

在118机器上面插入数据(10003,hanmeimei);

mysql> select * from test;
+——-+———–+
| tno   | tname     |
+——-+———–+
| 10001 | liming    |
| 10002 | linxiao   |
| 10003 | hanmeimei |
+——-+———–+

然后模拟118机器也宕机了,并恢复119的环境,然后在119库里面插入数据(10003,‘gaoyao’),,(10004, ‘chenhu’),插入成功

mysql> select * from test;
+——-+———+
| tno   | tname   |
+——-+———+
| 10001 | liming  |
| 10002 | linxiao |
| 10003 | gaoyao  |
| 10004 | chenhu  |
+——-+———+

然后恢复118机器的环境,此时问题出现,两边不能同步了,

查看记录如下:

mysql> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.101.118
                  Master_User: backup
                  Master_Port: 3306
                Connect_Retry: 50
              Master_Log_File: mysql-bin.000014
          Read_Master_Log_Pos: 202
               Relay_Log_File: localhost-relay-bin.000014
                Relay_Log_Pos: 251
        Relay_Master_Log_File: mysql-bin.000013
             Slave_IO_Running: Yes
            Slave_SQL_Running: No
              Replicate_Do_DB: cdn
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 1062
                   Last_Error: Error ‘Duplicate entry ‘10003’ for key ‘PRIMARY” on query. Default database: ‘cdn’. Query: ‘insert into test values(10003, ‘hanmeimei’)’

                   Last_Error: Error ‘Duplicate entry ‘10003’ for key ‘PRIMARY” on query. Default database: ‘cdn’. Query: ‘insert into test values(10003, ‘gaoyao’)’
                  (红色部分为118上面的日志)

            Skip_Counter: 0
          Exec_Master_Log_Pos: 497
              Relay_Log_Space: 915
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File: 
           Master_SSL_CA_Path: 
              Master_SSL_Cert: 
            Master_SSL_Cipher: 
               Master_SSL_Key: 
        Seconds_Behind_Master: NULL
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 1062
               Last_SQL_Error: Error ‘Duplicate entry ‘10003’ for key ‘PRIMARY” on query. Default database: ‘cdn’. Query: ‘insert into test values(10003, ‘hanmeimei’)’

              Last_SQL_Error: Error ‘Duplicate entry ‘10003’ for key ‘PRIMARY” on query. Default database: ‘cdn’. Query: ‘insert into test values(10003, ‘gaoyao’)’
1 row in set (0.00 sec)

原因分析:

两边数据不一致,数据库开始进行同步,但是由于在复制同步的时候,发现对方库中存在相同的主键,从而同步失败

并导致  Slave_SQL_Running: No  出现

要求:

要求模拟上述场景,并解决工作中实际出现的这种问题

即双主中有一台机器A宕机后,紧接着另一台B在插入了部分数据之后也宕机了,然后A机器先恢复启动,并在不知情的情况下也插入了相同主键但是内容不一致的数据,

然后B再启动,此时就会出现上述错误

解决(1)

此种情况下只要保证机器B先启动就不会存在此种问题,所以要解决的问题是怎么控制B先启动的问题

解决(2)

网上有其他修改参数的相关建议,但是可能场景不是很合要求

如:

修改mysql的配置文件,/etc/my.cnf,在[mysqld]下面添加一行

slave_skip_errors = 1062

保存、重启mysql服务,再次查看主从复制,问题解决。

此种方法在此场景只能保证忽略报错,在后序的数据中还能保持同步,但是对于已经不同步的数据不能恢复同步:

mysql> select * from test;    ————A
+——-+———–+
| tno   | tname     |
+——-+———–+
| 10001 | liming    |
| 10002 | hanmeimei |
| 10003 | Jimmy     |
+——-+———–+

mysql> select  * from test;            ——————B
+——-+———–+
| tno   | tname     |
+——-+———–+
| 10001 | liming    |
| 10002 | hanmeimei |
| 10003 | gaoyao    |
+——-+———–+

在A中插入一条数据(10004,’Green’), 这条数据马上能同步到B, 但是 tno = 10003的数据还是混乱的,不知道选择哪条了,所以此条记录没有同步

还有另外一种:  此种和上面方法类似,都是相当于路过了当前问题,令后面的同步

mysql> slave stop;
     mysql> set GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
     mysql> slave start;

使用ffmpeg合并视频文件的三种方法

ffmpeg合并视频的方法有三种。国内大多数仅介绍了其中之一。于是觉得有必要翻译一下。其实在ffmpeg的 FAQ文档中有比较详细的说明。

  1. 使用concat协议进行视频文件的合并

    这种方式的适用场景是:视频容器是MPEG-1, MPEG-2 PS或DV等可以直接进行合并的。换句话说,其实可以直接用cat或者copy之类的命令来对视频直接进行合并。很多文章介绍了这种方法,但适用性却没有提及。这并不是一个通用的方法。典型的命令示例如下:

    ffmpeg -i concat:"intermediate1.mpg|intermediate2.mpg" -c copy intermediate_all.mpg
  2. 使用concat demuxer进行视频文件的合并

    这种合并方式的适用场景是:当容器格式不支持文件层次的合并,而又不想(不需要)进行再编码的操作的时候。这种方式对源视频同样有同格式同性质的要求。其详细语法参见 这里 。典型的命令示例如下:

    ffmpeg -f concat -i Cam01.txt -c copy Cam01.mp4

    其中,Cam01.txt 为包含了输入文件的描述文件。

  3. 使用concat滤镜(filter)进行视频文件的合并:

    当需要进行任意程度的重新编解码时,官方推荐使用的方法即是用concat滤镜来进行视频文件的合并处理。详细说明参见 这里 。典型命令示例如下:

    ffmpeg -i opening.mkv -i episode.mkv -i ending.mkv -filter_complex \ '[0:0] [0:1] [0:2] [1:0] [1:1] [1:2] [2:0] [2:1] [2:2]
       concat=n=3:v=1:a=2 [v] [a1] [a2]' \
      -map '[v]' -map '[a1]' -map '[a2]' output.mkv

    这段命令目的是将三段双语格式的视频合并至最终的一段视频(output.mkv)。参数n=3说明待合成的视频有三段,v=1说明视频流为一,a=2说明音频流为二。 -map参数的详细说明可以从Filtergraph文档中找到。

众所周知,从某些视频网站下载的视频是分段的。比如新浪视频每隔6分钟分段,俗称“6分钟诅咒”。
现在的任务是将这些视频片段合并起来,并且尽量无损。

方法一:FFmpeg concat 协议

对于 MPEG 格式的视频,可以直接连接:

ffmpeg -i "concat:input1.mpg|input2.mpg|input3.mpg" -c copy output.mpg

对于非 MPEG 格式容器,但是是 MPEG 编码器(H.264、DivX、XviD、MPEG4、MPEG2、AAC、MP2、MP3 等),可以包装进 TS 格式的容器再合并。在新浪视频,有很多视频使用 H.264 编码器,可以采用这个方法
ffmpeg -i input1.flv -c copy -bsf:v h264_mp4toannexb -f mpegts input1.ts
ffmpeg -i input2.flv -c copy -bsf:v h264_mp4toannexb -f mpegts input2.ts
ffmpeg -i input3.flv -c copy -bsf:v h264_mp4toannexb -f mpegts input3.ts
ffmpeg -i "concat:input1.ts|input2.ts|input3.ts" -c copy -bsf:a aac_adtstoasc -movflags +faststart output.mp4
保存 QuickTime/MP4 格式容器的时候,建议加上 -movflags +faststart。这样分享文件给别人的时候可以边下边看。

方法二:FFmpeg concat 分离器

这种方法成功率很高,也是最好的,但是需要 FFmpeg 1.1 以上版本。先创建一个文本文件filelist.txt
file 'input1.mkv'
file 'input2.mkv'
file 'input3.mkv'
然后:

ffmpeg -f concat -i filelist.txt -c copy output.mkv

注意:使用 FFmpeg concat 分离器时,如果文件名有奇怪的字符,要在 filelist.txt 中转义。

方法三:Mencoder 连接文件并重建索引

这种方法只对很少的视频格式生效。幸运的是,新浪视频使用的 FLV 格式是可以这样连接的。对于没有使用 MPEG 编码器的视频(如 FLV1 编码器),可以尝试这种方法,或许能够成功。

mencoder -forceidx -of lavf -oac copy -ovc copy -o output.flv input1.flv input2.flv input3.flv

方法四:使用 FFmpeg concat 过滤器重新编码(有损)

语法有点复杂,但是其实不难。这个方法可以合并不同编码器的视频片段,也可以作为其他方法失效的后备措施。

ffmpeg -i input1.mp4 -i input2.webm -i input3.avi -filter_complex '[0:0] [0:1] [1:0] [1:1] [2:0] [2:1] concat=n=3:v=1:a=1 [v] [a]' -map '[v]' -map '[a]' <编码器选项> output.mkv

如你所见,上面的命令合并了三种不同格式的文件,FFmpeg concat 过滤器会重新编码它们。注意这是有损压缩。
[0:0] [0:1] [1:0] [1:1] [2:0] [2:1] 分别表示第一个输入文件的视频、音频、第二个输入文件的视频、音频、第三个输入文件的视频、音频。concat=n=3:v=1:a=1 表示有三个输入文件,输出一条视频流和一条音频流。[v] [a] 就是得到的视频流和音频流的名字,注意在 bash 等 shell 中需要用引号,防止通配符扩展。

提示

  1. 以上三种方法,在可能的情况下,最好使用第二种。第一种次之,第三种更次。第四种是后备方案,尽量避免。
  2. 规格不同的视频合并后可能会有无法预测的结果。
  3. 有些媒体需要先分离视频和音频,合并完成后再封装回去。
  4. 对于 Packed B-Frames 的视频,如果封装成 MKV 格式的时候提示 Can't write packet with unknown timestamp,尝试在 FFmpeg 命令的 ffmpeg 后面加上 -fflags +genpts