简介

Linux rcp命令用于复制远程文件或目录。

rcp指令用在远端复制文件或目录,如同时指定两个以上的文件或目录,且最后的目的地是一个已经存在的目录,则它会把前面指定的所有文件或目录复制到该目录中。

语法

1
2
rcp [-pr][源文件或目录][目标文件或目录]
rcp [-pr][源文件或目录...][目标文件]

参数:

1
2
-p: 保留源文件或目录的属性,包括拥有者,所属群组,权限与时间。
-r: 递归处理,将指定目录下的文件与子目录一并处理。

实例

使用rcp指令复制远程文件到本地进行保存。

设本地主机当前账户为rootlocal,远程主机账户为root,要将远程主机(192.125.30.5)主目录下的文件”testfile” 复制到本地目录 “test” 中,则输入如下命令:

1
2
3
4
5
6
# 复制远程文件到本地
rcp root@192.125.30.5:./testfile testfile
rcp root@192.125.30.5:home/rootlocal/testfile testfile

# 要求当前登录账户cmd 登录到远程主机
rcp 192.125.30.5:./testfile testfile

注意:指令 rcp 执行以后不会有返回信息,仅需要在目录 “test” 下查看是否存在文件 “testfile”。
若存在,则表示远程复制操作成功,否则远程复制操作失败。

参考:

Linux rcp命令

简介

Linux scp 命令用于 Linux 之间复制文件和目录。
scp 是 secure copy 的缩写, scp 是 linux 系统下基于 ssh 登陆进行安全的远程文件拷贝命令。
scp 是加密的,rcp 是不加密的,scp 是 rcp 的加强版。

语法

1
2
3
scp [-1246BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file]
[-l limit] [-o ssh_option] [-P port] [-S program]
[[user@]host1:]file1 [...] [[user@]host2:]file2

简易写法:

scp [可选参数] file_source file_target

参数说明:

  • -1: 强制scp命令使用协议ssh1
  • -2: 强制scp命令使用协议ssh2
  • -4: 强制scp命令只使用IPv4寻址
  • -6: 强制scp命令只使用IPv6寻址
  • -B: 使用批处理模式(传输过程中不询问传输口令或短语)
  • -C: 允许压缩。(将-C标志传递给ssh,从而打开压缩功能)
  • -p: 保留原文件的修改时间,访问时间和访问权限。
  • -q: 不显示传输进度条。
  • -r: 递归复制整个目录。
  • -v: 详细方式显示输出。scp和ssh(1)会显示出整个过程的调试信息。这些信息用于调试连接,验证和配置问题。
  • -c: cipher: 以cipher将数据传输进行加密,这个选项将直接传递给ssh。
  • -F: ssh_config: 指定一个替代的ssh配置文件,此参数直接传递给ssh。
  • -i: identity_file: 从指定文件中读取传输时使用的密钥文件,此参数直接传递给ssh。
  • -l: limit: 限定用户所能使用的带宽,以Kbit/s为单位。
  • -o: ssh_option: 如果习惯于使用ssh_config(5)中的参数传递方式,
  • -P: port:注意是大写的P, port是指定数据传输用到的端口号
  • -S: program: 指定加密传输时所使用的程序。此程序必须能够理解ssh(1)的选项。

实例

从本地复制到远程

文件复制

1
2
3
4
5
6
7
8
9
10
11
12
13
# 1,2 指定了用户名,命令执行后需要再输入密码,
# 1,指定了远程的目录,文件名字不变
scp local_file remote_username@remote_ip:remote_folder

# 2,指定了文件名;
scp local_file remote_username@remote_ip:remote_file

# 3,4指定用户名,命令执行后需要输入用户名和密码
# 3,指定了远程的目录,文件名字不变
scp local_file remote_ip:remote_folder

# 4,指定了文件名;
scp local_file remote_ip:remote_file

复制目录

命令格式:

1
2
3
4
5
# 指定了用户名,命令执行后需要再输入密码;
scp -r local_folder remote_username@remote_ip:remote_folder

# 没有指定用户名,命令执行后需要输入用户名和密码;
scp -r local_folder remote_ip:remote_folder

从远程复制到本地

从远程复制到本地,只要将从本地复制到远程的命令的后2个参数调换顺序即可。

应用实例:

1
2
scp root@www.runoob.com:/home/root/others/music /home/space/music/1.mp3 
scp -r www.runoob.com:/home/root/others/ /home/space/music/

注意事项

1.如果远程服务器防火墙有为scp命令设置了指定的端口,我们需要使用 -P 参数来设置命令的端口号。

命令格式如下:

1
2
#scp 命令使用端口号 4588
scp -P 4588 remote@www.runoob.com:/usr/local/sin.sh /home/administrator

2.使用scp命令要确保使用的用户具有可读取远程服务器相应文件的权限,否则scp命令是无法起作用的。

参考:

Linux scp命令

mysql执行刷新权限报错:Table 'mysql.servers' doesn't exist

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
mysql> flush privileges;
ERROR 1146 (42S02): Table 'mysql.servers' doesn't exist

mysql> show warnings;
+---------+------+-------------------------------------+
| Level | Code | Message |
+---------+------+-------------------------------------+
| Warning | 1146 | Table 'mysql.servers' doesn't exist |
+---------+------+-------------------------------------+
1 row in set (0.00 sec)

mysql> drop table if exists servers;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> CREATE TABLE `servers` (
-> `Server_name` char(64) NOT NULL,
-> `Host` char(64) NOT NULL,`Db` char(64) NOT NULL,
-> `Username` char(64) NOT NULL,
-> `Password` char(64) NOT NULL,
-> `Port` int(4) DEFAULT NULL,
-> `Socket` char(64) DEFAULT NULL,
-> `Wrapper` char(64) NOT NULL,
-> `Owner` char(64) NOT NULL,
-> PRIMARY KEY (`Server_name`)
-> ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='MySQL Foreign Servers table';
Query OK, 0 rows affected (0.01 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)

SQL脚本:

1
2
3
4
5
6
7
8
9
10
11
CREATE TABLE `servers` (
`Server_name` char(64) NOT NULL,
`Host` char(64) NOT NULL,`Db` char(64) NOT NULL,
`Username` char(64) NOT NULL,
`Password` char(64) NOT NULL,
`Port` int(4) DEFAULT NULL,
`Socket` char(64) DEFAULT NULL,
`Wrapper` char(64) NOT NULL,
`Owner` char(64) NOT NULL,
PRIMARY KEY (`Server_name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='MySQL Foreign Servers table';

参考:

ERROR 1146 (42S02): Table ‘mysql.servers’ doesn’t exist

MYSQL ERROR 1146 Table doesnt exist 解析

简介

主从复制(也称 Replication, AB 复制)允许将来自一个MySQL数据库服务器(主服务器)的数据复制到一个或多个MySQL数据库服务器(从服务器)。

复制是异步的 从站不需要永久连接以接收来自主站的更新,从服务器甚至可以通过拨号断断续续地连接主服务器。

根据配置,可以复制数据库中的所有数据库,所选数据库甚至选定的表。

有以下几种形式:

  • 一主一从
  • 主主复制
  • 一主多从—扩展系统读取的性能,因为读是在从库读取的;
  • 多主一从—5.7开始支持
  • 联级复制—

MySQL中复制的优点:

1,横向扩展解决方案 - 在多个从站之间分配负载以提高性能。在此环境中,所有写入和更新都必须在主服务器上进行。但是,读取可以在一个或多个从设备上进行。该模型可以提高写入性能(因为主设备专用于更新),同时显着提高了越来越多的从设备的读取速度。
2,数据安全性 - 因为数据被复制到从站,并且从站可以暂停复制过程,所以可以在从站上运行备份服务而不会破坏相应的主数据。
3,分析 - 可以在主服务器上创建实时数据,而信息分析可以在从服务器上进行,而不会影响主服务器的性能。
4,远程数据分发 - 您可以使用复制为远程站点创建数据的本地副本,而无需永久访问主服务器。

主要过程

1、主服务器MySQL服务将所有的写操作记录在 binlog 日志中,并生成 log dump 线程,将 binlog 日志传给从服务器MySQL服务的 I/O 线程。
2、从服务器MySQL服务生成两个线程,一个是 I/O 线程,另一个是 SQL 线程。
3、从库 I/O 线程去请求主库的 binlog 日志,并将 binlog 日志中的文件写入 relaylog(中继日志)中。
4、从库的 SQL 线程会读取 relaylog 中的内容,并解析成具体的操作,来实现主从的操作一致,达到最终两个数据库数据一致的目的。

202051293523201.jpg

注意点:

  • 主从复制是异步的逻辑的 SQL 语句级的复制;
  • 复制时,主库有一个 I/O 线程,从库有两个线程,及 I/O 和 SQL 线程;
  • 实现主从复制的必要条件是主库要开启记录 binlog 的功能;
  • 作为复制的所有 MySQL 节点的 server-id 都不能相同;
  • binlog 文件只记录对数据内容有更改的 SQL 语句,不记录任何查询语句。
  • 无法将主服务器配置为仅记录特定事件。

二进制日志

mysqld将数字扩展名附加到二进制日志基本名称以生成二进制日志文件名。每次服务器创建新日志文件时,该数字都会增加,从而创建一系列有序的文件。每次启动或刷新日志时,服务器都会在系列中创建一个新文件。服务器还会在当前日志大小达到 max_binlog_size 参数设置的大小后自动创建新的二进制日志文件 。二进制日志文件可能会比 max_binlog_size 使用大型事务时更大, 因为事务是以一个部分写入文件,而不是在文件之间分割。

为了跟踪已使用的二进制日志文件, mysqld 还创建了一个二进制日志索引文件,其中包含所有使用的二进制日志文件的名称。默认情况下,它具有与二进制日志文件相同的基本名称,并带有扩展名 .index。在 mysqld 运行时,您不应手动编辑此文件。

二进制日志文件 通常表示包含数据库事件的单个编号文件。
二进制日志 表示含编号的二进制日志文件集加上索引文件。

SUPER 权限的用户可以使用 SET sql_log_bin=0 语句禁用其当前环境下自己的语句的二进制日志记录。

配置部署

主从部署必要条件:

  • 主库开启binlog日志(设置log-bin参数)
  • 主从server-id不同
  • 从库服务器能连通主库

主服务器:

1、开启二进制日志
2、配置唯一的server-id
3、获得master二进制日志文件名及位置
4、创建一个用于slave和master通信的用户账号

从服务器:

1、配置唯一的server-id
2、使用master分配的用户账号读取master二进制日志
3、启用slave服务

服务器配置

主节点修改配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 服务器唯一ID,一般取IP最后一段
server-id=1

# 要同步的数据库(可以不指定)
binlog-do-db=test

# 要生成二进制日志文件 主服务器一定要开启
log-bin=/usr/local/mysql/binlogs/bin-log

# 不可以被从服务器复制的库
binlog-ignore-db=mysql

# binlog日志格式,mysql默认采用ROW,建议使用mixed
binlog_format=MIXED

# binlog日志文件
log-bin=/usr/local/mysql/binlogs/bin-log

# binlog过期清理时间
expire_logs_days=7

# binlog每个日志文件大小
max_binlog_size=100m

# binlog缓存大小
binlog_cache_size=4m

# 最大binlog缓存大小
max_binlog_cache_size=512m

创建日志目录,并赋予权限:

1
2
mkdir /usr/local/mysql/binlogs
chown mysql.mysql /usr/local/mysql/binlogs

重启:

/etc/init.d/mysqld restart

如果省略 server-id(或将其显式设置为默认值0),则主服务器拒绝来自从服务器的任何连接。

为了在使用带事务的 InnoDB 进行复制设置时尽可能提高持久性和一致性,
您应该在master my.cnf 文件中使用以下配置项:

1
2
innodb_flush_log_at_trx_commit = 1
sync_binlog = 1

确保在主服务器上 skip_networking 选项处于 OFF 关闭状态, 这是默认值。
如果是启用的,则从站无法与主站通信,并且复制失败。

1
2
3
4
5
6
7
mysql> show variables like '%skip_networking%';
+-----------------+-------+
| Variable_name | Value |
+-----------------+-------+
| skip_networking | OFF |
+-----------------+-------+
1 row in set (0.01 sec)

从服务器配置

1
2
3
4
5
6
7
8
9
# my.cnf 文件
[mysqld]
server-id=2

#要同步的数据库 (可选)
binlog-do-db=test

#要生成二进制日志文件(可选)
log-bin=mysql-bin

主服务器创建用于复制数据的用户

语法:

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

grant 权限1,权限2,…权限n on 数据库名称.表名称 to 用户名@用户地址 identified by ‘连接口令’ WITH GRANT OPTION;

示例:

GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '123456' WITH GRANT OPTION;

取消权限:
revoke all on *.* from root@localhost;

最后执行:
flush privileges;

GRANT:赋权命令

ALL PRIVILEGES:当前用户的所有权限
ON:介词
*.*:当前用户对所有数据库和表的相应操作权限
TO:介词
‘root’@’%’:权限赋给root用户,所有ip都能连接
IDENTIFIED BY ‘123456’:连接时输入密码,密码为123456
WITH GRANT OPTION:允许级联赋权,表示该用户可以将自己拥有的权限授权给别人。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 连接到mysql,输入密码
mysql -uroot -h 127.0.0.1 -p

# 创建用户
create user 'slave'@'%' identified by '123456';
# 或
CREATE USER 'slave'@'%'

# 设置用户权限
# 授予复制账号 REPLICATION CLIENT 权限,复制用户可以使用
# SHOW MASTER STATUS, SHOW SLAVE STATUS 和 SHOW BINARY LOGS来确定复制状态。
# 授予复制账号 REPLICATION SLAVE 权限,复制才能真正地工作。
grant replication slave,replication client on *.* to 'slave'@'%';
# 或
GRANT REPLICATION SLAVE ON *.* TO 'slave'@'%' identified by '123456';

# 查看用户
select host,user from user;

# 刷新权限
flush privileges;

# 查看用户权限
show grants for 'slave'@'%';

备份主服务器数据

使用 scp 或 rsync 等工具,把备份出来的数据传输到从服务器中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 进入 mysql 安装目录
cd /usr/local/mysql/bin
# 如果不使用 --master-data 参数,则需要手动锁定单独会话中的所有表
./mysqldump -u用户名 -p密码 --all-databases --master-data=1 > dbdump.db
# 或 备份指定库
./mysqldump -uroot -proot --databases db1 db2 > dbdump.db

# 或
# 1,加锁
FLUSH TABLES WITH READ LOCK;

# 2. 将master中需要同步的db的数据dump出来
./mysqldump -uroot -p testdb > testdb.dump

# 3. 将数据导入slave
mysql -uroot -h192.123.75.69 -p testdb < testdb.dump

# 4. 解锁master
UNLOCK TABLES;

从服务器开始复制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 登录 主mysql
mysql -uroot -h192.123.75.68 -p

# 主服务器复制状态
show master status\G

# 登录从服务器
# 连接主服务器及设置复制的起始节点
change master to master_host='192.123.75.68',
master_port=3306,
master_user='slave',
master_password='123456',
master_log_file='bin-log.000001',
master_log_pos=154;

# 开始复制
start slave;

# 查看 从 复制状态
# 输出结果中应该看到 I/O 线程和 SQL 线程都是 YES, 就表示成功。
show slave status \G

# 查看 主 复制状态
show master status \G

# 查看数据表数据
mysql> show create table user\G

设置从库只读

1
2
3
4
5
6
7
8
# 查看当前只读的状态
SHOW VARIABLES LIKE '%read_only%';

# 设置普通用户只读
SET GLOBAL read_only=1;

# 设置超级用户只读
SET GLOBAL super_read_only=1;

复制相关命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 停止slave
stop slave;

# 重置slave
reset slave;

# 开启slave
start slave;

# 查看主从服务器进程
show processlist;

# 指定线程类型单独 暂停I/O或SQL线程
STOP SLAVE IO_THREAD;
STOP SLAVE SQL_THREAD;

# 指定线程类型单独 启动I/O或SQL线程
START SLAVE IO_THREAD;
START SLAVE SQL_THREAD;

查看 binlog 日志

show binlog events\G

  • Log_name 是二进制日志文件的名称,一个事件不能横跨两个文件
  • Pos 这是该事件在文件中的开始位置
  • Event_type 事件的类型,事件类型是给slave传递信息的基本方法,每个新的binlog都以Format_desc类型开始,以Rotate类型结束
  • Server_id 创建该事件的服务器id
  • End_log_pos 该事件的结束位置,也是下一个事件的开始位置,因此事件范围为 Pos~End_log_pos - 1
  • Info 事件信息的可读文本,不同的事件有不同的信息

复制原理实现细节

MySQL复制功能使用三个线程实现,一个在主服务器上,两个在从服务器上:

  • Binlog转储线程 主设备创建一个线程,以便在从设备连接时将二进制日志内容发送到从设备。可以 SHOW PROCESSLIST 在主服务器的输出中将此线程标识为 Binlog Dump 线程。

    二进制日志转储线程获取主机二进制日志上的锁,用于读取要发送到从机的每个事件。一旦读取了事件,即使在事件发送到从站之前,锁也会被释放。

  • 从属 I/O线程 在从属服务器上发出 START SLAVE 语句时,从属服务器会创建一个 I/O 线程,该线程连接到主服务器并要求主服务器发送其在二进制日志中的更新记录。

    从属 I/O 线程读取主 Binlog Dump 线程发送的更新,并将它们复制到包含从属中继日志的本地文件。

    此线程的状态显示为 Slave_IO_running 输出 SHOW SLAVE STATUSSlave_running 输出中的状态 SHOW STATUS

  • 从属SQL线程 从属设备创建一个SQL线程来读取由从属 I/O 线程写入的中继日志,并执行其中包含的事件。

    当从属服务器从放的事件,追干上主服务器的事件后,从属服务器的 I/O 线程将会处于休眠状态,直到主服务器的事件有更新时,被主服务器发送的信号唤醒。

    每个 主/从 连接有三个线程。具有多个从站的主站为每个当前连接的从站创建一个二进制日志转储线程,每个从站都有自己的 I/O和SQL线程。

从站使用两个线程将读取更新与主站分开并将它们执行到独立任务中。因此,如果语句执行缓慢,则不会减慢读取语句的任务。例如,如果从服务器尚未运行一段时间,则当从服务器启动时,其 I/O 线程可以快速从主服务器获取所有二进制日志内容,即使SQL线程远远落后。如果从服务器在SQL线程执行了所有获取的语句之前停止,则 I/O 线程至少已获取所有内容,以便语句的安全副本本地存储在从属的中继日志中,准备在下次执行时执行 SLAVE开始。

主服务器上,输入 SHOW PROCESSLIST 如下所示:

1
2
3
4
5
6
7
8
9
10
mysql> show processlist\G
*************************** 1. row ***************************
Id: 69
User: slave
Host: 192.123.75.69:55453
db: NULL
Command: Binlog Dump
Time: 63184
State: Master has sent all binlog to slave; waiting for more updates
Info: NULL

该线程是 Binlog Dump 为连接的从属服务的复制线程。该 State 信息表明所有未完成的更新已发送到从站,并且主站正在等待更多更新发生。如果 Binlog Dump 在主服务器上看不到任何 线程,则表示复制未运行,说明目前没有连接任何从站。

配置多线程复制

多线程复制在 5.6 中被引入,并且在 5.7 中得到了进一步的完善。5.7 中是基于逻辑时钟的方式进行的多线程复制。

临时配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 1,从库上查看默认的多线程复制类型
mysql> show variables like "slave_parallel_type";
+---------------------+----------+
| Variable_name | Value |
+---------------------+----------+
| slave_parallel_type | DATABASE |
+---------------------+----------+
1 row in set (0.00 sec)

#2,停止之前可以查看目前的线程数

show processlist;
stop slave;

# 3,配置并发线程的方式
mysql> set global slave_parallel_type = "logical_clock";
Query OK, 0 rows affected (0.00 sec)

# 4,配置并发数量
mysql> set global slave_parallel_workers = 4;
Query OK, 0 rows affected (0.00 sec)

mysql> show variables like "slave_parallel_workers";
+------------------------+-------+
| Variable_name | Value |
+------------------------+-------+
| slave_parallel_workers | 16 |
+------------------------+-------+
1 row in set (0.00 sec)

# 5,启动从服务器的复制链路
mysql> start slave;

永久生效

vim /usr/local/mysql/my.cnf

在 [mysqld] 下添加:

1
2
3
4
5
slave-parallel-type=LOGICAL_CLOCK
slave-parallel-workers=16
master_info_repository=TABLE
relay_log_info_repository=TABLE
relay_log_recovery=ON

重启mysql

1
2
3
4
/etc/init.d/mysqld restart

# 或
service mysqld restart

验证:

1
2
show variables like "slave_parallel_type";
show variables like "slave_parallel_workers";

参考:

Mysql 主从复制

MySQL 主从复制原理与实践详解

MySQL5.6 新特性之GTID

[MySQL] 号称永久解决了复制延迟问题的并行复制,MySQL5.7

下载

下载离线包:

https://dl.min.io/server/minio/release/linux-amd64/minio

或者使用命令下载(需要接入互联网):

1
wget https://dl.min.io/server/minio/release/linux-amd64/minio

移动到/usr/local/minio文件夹

1
2
3
4
5
6
mkdir -p /usr/local/minio/bin
cp /ldjc/rj/minio /usr/local/minio/bin
cd /usr/local/minio/bin

# 添加执行权限
chmod +x minio

启动

命令格式:

1
./minio -C \"${minio_config}\" server --address=\"${minio_address}\" ${minio_disks}

-C:配置文件

终端方式启动

进入到软件包所在目录:

终端启动,这种方式关闭终端,服务会停止。

1
2
3
4
5
cd /ldjc/rj

export MINIO_ACCESS_KEY=admin
export MINIO_SECRET_KEY=test
./minio server -C minio.conf /ldjc/minio/data --address :9010

后台运行

1
2
3
4
5
cd /ldjc/rj
export MINIO_ACCESS_KEY=admin
export MINIO_SECRET_KEY=test
nohup ./minio server -C minio.conf /ldjc/minio/data --address 192.125.30.71:9010
nohup ./minio server -C minio.conf /ldjc/minio/data --address :9010

配置文件启动

新建配置文件

1
2
3
cd /usr/local/minio
touch minio.conf
vi minio.conf

配置文件内容:

1
2
3
4
MINIO_ACCESS_KEY=admin
MINIO_SECRET_KEY=admin
MINIO_VOLUMES="/test/minio/data"
MINIO_OPTS=" --address 192.125.31.71:9010"

新建服务

/etc/systemd/system,新建一个 minio.service :

1
2
touch /etc/systemd/system/minio.service
vim /etc/systemd/system/minio.service

参考:linux-systemd/minio.service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
[Unit]
Description=MinIO
Documentation=https://docs.min.io
Wants=network-online.target
After=network-online.target
AssertFileIsExecutable=/usr/local/minio/bin/minio

[Service]
WorkingDirectory=/usr/local/

User=root
Group=root

EnvironmentFile=/usr/local/minio/minio.conf
ExecStartPre=/bin/bash -c "if [ -z \"${MINIO_VOLUMES}\" ]; then echo \"Variable MINIO_VOLUMES not set in /etc/default/minio\"; exit 1; fi"

ExecStart=/usr/local/minio/bin/minio server $MINIO_OPTS $MINIO_VOLUMES

# Let systemd restart this service always
Restart=always

# Specifies the maximum file descriptor number that can be opened by this process
LimitNOFILE=65536

# Disable timeout logic and wait until process is stopped
TimeoutStopSec=infinity
SendSIGKILL=no

[Install]
WantedBy=multi-user.target

# Built for ${project.name}-${project.version} (${project.name})

启动服务

1
2
3
4
5
6
7
8
9
systemctl enable minio.service
systemctl start minio.service
systemctl stop minio.service
systemctl status minio.service

systemctl restart minio.service

# 更新服务文件后,需要重新加载
systemctl daemon-reload

查看进程

1
2
3
4
5
#查看端口
netstat -tunpl | grep 9010

#查看进程
ps aux | grep minio

TLS

详细信息请参考官网:How to secure access to MinIO server with TLS

生成域名证书

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
openssl genrsa -out private-pkcs8-key.key 2048

# 或者使用下面命令给证书加上密码
openssl genrsa -aes256 -passout pass:123456 -out private-pkcs8-key.key 2048

# 如果设置密码 启动minio的时候,需要设置证书密码
export MINIO_CERT_PASSWD=<123456>

# 私有加密密钥的默认 OpenSSL 格式为 PKCS-8,但 MinIO 仅支持 PKCS-1
# pkcs8 转 pkcs1
openssl rsa -in private-pkcs8-key.key -aes256 -passout pass:123456 -out private.key

# 生成自签名证书
# 注:domain.com,需要替换成自己的域名
openssl req -new -x509 -days 3650 -key private.key -out public.crt -subj "/C=US/ST=state/L=location/O=organization/CN=<domain.com>"

# 或者使用下面的命令生成自签名通配符证书,该证书该所有子域名都有效。
openssl req -new -x509 -days 3650 -key private.key -out public.crt -subj "/C=US/ST=state/L=location/O=organization/CN=<*.domain.com>"

生成IP证书

生成配置文件 openssl.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_req
prompt = no

[req_distinguished_name]
C = US
ST = VA
L = Somewhere
O = MyOrg
OU = MyOU
CN = MyServerName

[v3_req]
subjectAltName = @alt_names

[alt_names]
IP.1 = 127.0.0.1

使用配置文件生成证书:

1
openssl req -x509 -nodes -days 730 -newkey rsa:2048 -keyout private.key -out public.crt -config openssl.conf

参考:

Minio 文件服务(1)—— Minio部署使用及存储机制分析

MinIO Server Config Guide

How to run MinIO in FreeNAS

5.7 以及之后的版本中会遇到这样的错误:

1
2
3
4
Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'name' which is not functionally dependent on columns in GROUP BY clause;
this is incompatible with sql_mode=only_full_group_by

Expression #1 of ORDER BY clause is not in SELECT list, references column 'sort' which is not in SELECT list; this is incompatible with DISTINCT

说明

mysql 5.7版本默认的sql配置是:sql_mode=”ONLY_FULL_GROUP_BY”,这个配置严格执行了”SQL92标准”。

查看sql_mode的语句:

1
2
3
4
select @@GLOBAL.sql_mode;

##输出:
ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION

很多从5.6升级到5.7时,为了语法兼容,大部分都会选择调整sql_mode,使其保持跟5.6一致,为了尽量兼容程序。

原因分析:
再输出的结果 target list 中,即select后面跟着的字段,还有一个地方 group by column,就是 group by后面跟着的字段。由于开启了 ONLY_FULL_GROUP_BY 的设置,所以如果一个字段没有在 target list
group by 字段中同时出现,或者是聚合函数的值的话,那么这条sql查询是被mysql认为非法的,会报错误。

解决方法

暂时修改sql_mode

重启mysql数据库服务之后,ONLY_FULL_GROUP_BY还会出现。

1
set @@GLOBAL.sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION

修改mysql配置文件

修改 mysql 配置文件,/usr/local/mysql/my.cnf,添加如下代码,之后重启mysql服务。

1
2
#主要需要添加到 [mysql] [mysqld] 标签下,加入到其他地方,即使重启后也不生效。
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION

重启:

1
/etc/init.d/mysqld restart

参考:

5分钟学会MySQL-this is incompatible with sql_mode=only_full_group_by错误解决方案

mysql5.7.x:this is incompatible with DISTINCT

转载:

跨域资源共享 CORS 详解

简介

CORS是一个W3C标准,全称是”跨域资源共享”(Cross-origin resource sharing)。

它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。

CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。

整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。

因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。

与JSONP的比较

CORSJSONP 的使用目的相同,但是比 JSONP 更强大。

JSONP 只支持 GET 请求,CORS 支持所有类型的 HTTP 请求。JSONP 的优势在于支持老式浏览器,以及可以向不支持 CORS 的网站请求数据。

两种请求

浏览器将 CORS 请求分成两类:

简单请求(simple request)和 非简单请求(not-so-simple request)。

只要同时满足以下两大条件,就属于简单请求。

1
2
3
4
5
6
7
8
9
10
11
2.请求方法是以下三种方法之一:
HEAD
GET
POST

2.HTTP的头信息不超出以下几种字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

这是为了兼容表单(form),因为历史上表单一直可以发出跨域请求。AJAX 的跨域设计就是,只要表单可以发,AJAX 就可以直接发。

凡是不同时满足上面两个条件,就属于非简单请求。

浏览器对这两种请求的处理,是不一样的。

简单请求

浏览器直接发出 CORS 请求。具体来说,就是在头信息之中,增加一个 Origin 字段。

下面是一个例子,浏览器发现这次跨源 AJAX 请求是简单请求,就自动在头信息之中,添加一个Origin字段。

1
2
3
4
5
6
GET /cors HTTP/1.1
Origin: http://api.bob.com
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...

Origin 字段用来说明,本次请求来自哪个源(协议 + 域名 + 端口)。服务器根据这个值,决定是否同意这次请求。

如果Origin指定的源,不在许可范围内,服务器会返回一个正常的HTTP回应。浏览器发现,这个回应的头信息没有包含 Access-Control-Allow-Origin 字段,就知道出错了,从而抛出一个错误,被 XMLHttpRequest 的onerror回调函数捕获。注意,这种错误无法通过状态码识别,因为HTTP回应的状态码有可能是200。

如果Origin指定的域名在许可范围内,服务器返回的响应,会多出几个头信息字段,都以 Access-Control- 开头。

1
2
3
4
Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: FooBar
Content-Type: text/html; charset=utf-8

Access-Control-Allow-Origin

该字段是必须的。它的值要么是请求时 Origin 字段的值,要么是一个*,表示接受任意域名的请求。

Access-Control-Allow-Credentials

该字段可选。它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。设为true,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器。这个值也只能设为true,如果服务器不要浏览器发送Cookie,删除该字段即可。

Access-Control-Expose-Headers

该字段可选。CORS请求时,XMLHttpRequest 对象的getResponseHeader()方法只能拿到6个基本字段:Cache-ControlContent-LanguageContent-TypeExpiresLast-ModifiedPragma。如果想拿到其他字段,就必须在 Access-Control-Expose-Headers 里面指定。上面的例子指定,getResponseHeader(‘FooBar’)可以返回FooBar字段的值。

withCredentials 属性

CORS请求默认不发送Cookie和HTTP认证信息。如果要把Cookie发到服务器,一方面要服务器同意,指定

Access-Control-Allow-Credentials 字段。

1
Access-Control-Allow-Credentials: true

另一方面,开发者必须在AJAX请求中打开 withCredentials 属性。

1
2
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

否则,即使服务器同意发送Cookie,浏览器也不会发送。或者,服务器要求设置Cookie,浏览器也不会处理。

但是,如果省略 withCredentials 设置,有的浏览器还是会一起发送Cookie。这时,可以显式关闭 withCredentials

1
xhr.withCredentials = false;

需要注意的是,如果要发送Cookie,Access-Control-Allow-Origin 就不能设为星号,必须指定明确的、与请求网页一致的域名。同时,Cookie依然遵循同源政策,只有用服务器域名设置的Cookie才会上传,其他域名的Cookie并不会上传,且(跨源)原网页代码中的document.cookie也无法读取服务器域名下的Cookie。

非简单请求

预检请求

非简单请求是那种对服务器有特殊要求的请求,比如请求方法是 PUTDELETE ,或者 Content-Type 字段的类型是 application/json

非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为”预检”请求(preflight)。

浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的 XMLHttpRequest 请求,否则就报错。

下面是一段浏览器的JavaScript脚本。

1
2
3
4
5
var url = 'http://api.alice.com/cors';
var xhr = new XMLHttpRequest();
xhr.open('PUT', url, true);
xhr.setRequestHeader('X-Custom-Header', 'value');
xhr.send();

上面代码中,HTTP请求的方法是PUT,并且发送一个自定义头信息 X-Custom-Header

浏览器发现,这是一个非简单请求,就自动发出一个”预检”请求,要求服务器确认可以这样请求。下面是这个”预检”请求的HTTP头信息。

1
2
3
4
5
6
7
8
OPTIONS /cors HTTP/1.1
Origin: http://api.bob.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...

“预检”请求用的请求方法是 OPTIONS,表示这个请求是用来询问的。头信息里面,关键字段是Origin,表示请求来自哪个源。

除了 Origin 字段,”预检”请求的头信息包括两个特殊字段。

Access-Control-Request-Method

该字段是必须的,用来列出浏览器的 CORS 请求会用到哪些HTTP方法,上例是PUT。

Access-Control-Request-Headers

该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段,上例是 X-Custom-Header

预检请求的回应

服务器收到”预检”请求以后,检查了 OriginAccess-Control-Request-MethodAccess-Control-Request-Headers 字段以后,确认允许跨源请求,就可以做出回应。

1
2
3
4
5
6
7
8
9
10
11
12
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain

上面的HTTP回应中,关键的是 Access-Control-Allow-Origin 字段,表示 http://api.bob.com 可以请求数据。该字段也可以设为星号,表示同意任意跨源请求。

1
Access-Control-Allow-Origin: *

如果服务器否定了”预检”请求,会返回一个正常的HTTP回应,但是没有任何 CORS 相关的头信息字段。这时,浏览器就会认定,服务器不同意预检请求,因此触发一个错误,被 XMLHttpRequest 对象的 onerror 回调函数捕获。控制台会打印出如下的报错信息。

1
2
XMLHttpRequest cannot load http://api.alice.com.
Origin http://api.bob.com is not allowed by Access-Control-Allow-Origin.

服务器回应的其他 CORS 相关字段如下。

1
2
3
4
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 1728000

Access-Control-Allow-Methods

该字段必需,它的值是逗号分隔的一个字符串,表明服务器支持的所有跨域请求的方法。注意,返回的是所有支持的方法,而不单是浏览器请求的那个方法。这是为了避免多次”预检”请求。

Access-Control-Allow-Headers

如果浏览器请求包括 Access-Control-Request-Headers 字段,则 Access-Control-Allow-Headers 字段是必需的。它也是一个逗号分隔的字符串,表明服务器支持的所有头信息字段,不限于浏览器在”预检”中请求的字段。

Access-Control-Allow-Credentials

该字段与简单请求时的含义相同。

Access-Control-Max-Age

该字段可选,用来指定本次预检请求的有效期,单位为秒。上面结果中,有效期是20天(1728000秒),即允许缓存该条回应1728000秒(即20天),在此期间,不用发出另一条预检请求。

浏览器的正常请求和回应

一旦服务器通过了”预检”请求,以后每次浏览器正常的CORS请求,就都跟简单请求一样,会有一个 Origin 头信息字段。服务器的回应,也都会有一个 Access-Control-Allow-Origin 头信息字段。

下面是”预检”请求之后,浏览器的正常CORS请求。

1
2
3
4
5
6
7
PUT /cors HTTP/1.1
Origin: http://api.bob.com
Host: api.alice.com
X-Custom-Header: value
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...

上面头信息的Origin字段是浏览器自动添加的。

下面是服务器正常的回应。

1
2
Access-Control-Allow-Origin: http://api.bob.com
Content-Type: text/html; charset=utf-8

上面头信息中,Access-Control-Allow-Origin 字段是每次回应都必定包含的。

Linux crontab简介

Linux crontab是用来定期执行程序的命令。
当安装完成操作系统之后,默认便会启动此任务调度命令。

注意:新创建的 cron 任务,不会马上执行,至少要过 2 分钟后才可以,当然你可以重启 cron 来马上执行。

crontab命令用于设置周期性被执行的指令。该命令从标准输入设备读取指令,并将其存放于 /etc/crontab 文件中,以供之后读取和执行。

cron 系统调度进程。 可以使用它在每天的非高峰负荷时间段运行作业,或在一周或一月中的不同时段运行。cron是系统主要的调度进程,可以在无需人工干预的情况下运行作业。crontab命令允许用户提交、编辑或删除相应的作业。每一个用户都可以有一个crontab文件来保存调度信息。

linux 任务调度的工作主要分为以下两类:

1、系统执行的工作:系统周期性所要执行的工作,如备份系统数据、清理缓存
2、个人执行的工作:某个用户定期要做的工作,例如每隔10分钟检查邮件服务器是否有新信,这些工作可由每个用户自行设置

crontab 命令

crontab命令是 cron table 的简写,它是 cron 的配置文件,也可以叫它作业列表,我们可以在以下文件夹内找到相关配置文件。

/var/spool/cron/ 目录下存放的是每个用户包括root的crontab任务,每个任务以创建者的名字命名
/etc/crontab 这个文件负责调度各种管理和维护任务。
/etc/cron.d/ 这个目录用来存放任何要执行的crontab文件或脚本。

/etc/crontab

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
more /etc/crontab
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root

# For details see man 4 crontabs

# Example of job definition:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# | | | | |
# * * * * * user-name command to be executed

/var/spool/cron

每个用户都会生成一个自动生成一个自己的 crontab 文件,一般位于 /var/spool/cron 目录下

1
cd /var/spool/cron

如果你用命令 crontab -r 就会删除当前用户的crontab文件,例如你切换到oracle账号下,执行了该命令,那么 /var/spool/cron/oracle 文件就会删除,如果要创建该文件只需要用 crontab -e 命令即可。注意,普通用户一般没有权限访问 /var/spool/cron

我们还可以把脚本放在 /etc/cron.hourly/etc/cron.daily/etc/cron.weekly/etc/cron.monthly 目录中,让它每小时/天/星期、月执行一次。

系统管理员可以通过 cron.deny 和 cron.allow 这两个文件来禁止或允许用户拥有自己的crontab文件。

/etc/cron.deny 表示不能使用 crontab 命令的用户

/etc/cron.allow 表示能使用 crontab 的用户。

默认情况下,cron.allow 文件不存在。如果两个文件同时存在,那么 /etc/cron.allow 优先。如果两个文件都不存在,那么只有超级用户可以安排作业。

ls -lrt cron*

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
ls -lrt cron*
-rw-r--r--. 1 root root 451 6月 10 2014 crontab
-rw-------. 1 root root 0 11月 20 2018 cron.deny

cron.weekly:
总用量 0

cron.monthly:
总用量 0

cron.hourly:
总用量 4
-rwxr-xr-x. 1 root root 392 11月 20 2018 0anacron

cron.daily:
总用量 8
-rwxr-xr-x. 1 root root 618 10月 30 2018 man-db.cron
-rwx------. 1 root root 219 10月 31 2018 logrotate

cron.d:
总用量 4
-rw-r--r--. 1 root root 128 11月 20 2018 0hourl

CRONTAB在线手册

注意:不同版本的Linux系统,可能crontab手册内容有所出入,请以实际版本为准。

1
man crontab | more

注意事项

配置定时任务时,需要注意两个问题:

1: 在SHELL中设置了必要的环境变量;例如一个shell脚本手工执行OK,但是配置成后台作业执行时,获取不到ORACLE的环境变量,这是因为crontab环境变量问题,Crontab的环境默认情况下并不包含系统中当前用户的环境。所以,你需要在shell脚本中添加必要的环境变量的设置

2: 尽量所有的文件都采用完全路径方式,避免使用相对路径。

参考:

Linux crontab定时任务配置方法(详解)

Linux Crontab 定时任务

Linux crontab 命令

CentOS安装配置Crontab定时任务

Linux logrotate简介

Linux logrotate 命令用于管理记录文件。

使用 logrotate 指令,可让你轻松管理系统所产生的记录文件。它提供自动替换,压缩,删除和邮寄记录文件,每个记录文件都可被设置成每日,每周或每月处理,也能在文件太大时立即处理。例如,你可以设置 logrotate,让 /var/log/foo 日志文件每30天轮循,并删除超过6个月的日志。配置完后,logrotate 的运作完全自动化,不必进行任何进一步的人为干预。

logrotate 需要的 cron 任务应该在安装时就自动创建好了,下面代码以centos7.4为例:

1
2
3
4
5
6
7
8
9
cat /etc/cron.daily/logrotate
#!/bin/sh

/usr/sbin/logrotate -s /var/lib/logrotate/logrotate.status /etc/logrotate.conf
EXITVALUE=$?
if [ $EXITVALUE != 0 ]; then
/usr/bin/logger -t logrotate "ALERT exited abnormally with [$EXITVALUE]"
fi
exit 0

Linux系统自带的日志滚动工具 logrotate 由两部分组成:

一是命令行工具 logrotate;
二是后台服务 rsyslogd

使用 rsyslogd ,只需简单的配置即可实现日志滚动。
rsyslogd 的配置文件为 /etc/logrotate.conf,但一般不建议直接修改 logrotate.conf ,而是在目录 /etc/logrotate.d 下新增文件的方式。
logrotate.confinclude 所有 logrotate.d 目录下的文件,
语法是一致的,区别是 logrotate.conf 定义了默认的配置,而 logrotate.d 目录下为专有配置。

Redis日志设置

截至到 redis-5.0 版本,redis 仍然不会自动滚动日志文件,如果不处理则日志文件日积月累越来越大,最终将导致磁盘满告警,

使用命令查看磁盘使用情况:

1
ls -lh

下列为redis的配置示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# cat /etc/logrotate.d/redis
# 以下为 redis 文件的内容:
/usr/local/redis-cluster/log/redis-6379.log
/usr/local/redis-cluster/log/redis-6380.log
/usr/local/redis-cluster/log/redis-6381.log
{
monthly
rotate 5
minsize 100M
nocompress
dateext
missingok
notifempty
create 0664 root root
postrotate
/usr/bin/killall -HUP rsyslogd
endscript
}

注:postrotate/endscript 可以去掉,即:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# cat /etc/logrotate.d/redis
# 以下为 redis 文件的内容:
/usr/local/redis-cluster/log/redis-6379.log
/usr/local/redis-cluster/log/redis-6380.log
/usr/local/redis-cluster/log/redis-6381.log
{
monthly
rotate 5
minsize 100M
nocompress
dateext
missingok
notifempty
create 0664 root root
}

配置项说明:

可以使用 man logrotate 命令查看详情。

  • monthly: 日志文件将按月轮循。其它可用值为 dailyweekly 或者 yearly
  • rotate 指定日志文件备份数,一次将存储5个归档日志。对于第六个归档,时间最久的归档将被删除,如果值为0表示不备份
  • minsize 表示日志文件达到多大才滚动
  • nocompress 表示是否压缩备份的日志文件,取值:compressnocompress
  • delaycompress: 总是与 compress 选项一起用,delaycompress 选项指示 logrotate 不要将最近的归档压缩,压缩将在下一次轮循周期进行。这在你或任何软件仍然需要读取最新归档时很有用。
  • missingok 在日志轮循期间,任何错误将被忽略
  • notifempty 日志文件为空时,不进行轮转,默认值为 ifempty
  • create 以指定的权限创建全新的日志文件,同时logrotate也会重命名原始日志文件。logrotate 是以 root 运行的,如果目标日志文件非root运行,则这个一定要指定好。
  • postrotate/endscript: 在所有其它指令完成后,postrotateendscript 里面指定的命令将被执行。在这种情况下,rsyslogd 进程将立即再次读取其配置并继续运行。
  • dateext:就是切割后的日志文件以当前日期为格式结尾,如 xxx.log-20201016 这样,如果注释掉,切割出来是按数字递增,即前面说的 xxx.log-1这种格式。

注意,修改后需要重启下 rsyslogd。如果是 CentOS 可使用下列任意一种方式重启
(实际上 systemctl 新方式,而 service 实际也是使用 systemctl ):

1
2
service rsyslog restart 
systemctl restart rsyslog.service

实例

创建测试日志文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 创建文件
touch /var/log/log-file
head -c 50M < /dev/urandom > /var/log/log-file

# 编辑配置
vim /etc/logrotate.d/log-file

# 以下为内容
/var/log/log-file {
minsize 50M
rotate 5
create 644 root root
postrotate
/usr/bin/killall -HUP rsyslogd
endscript
}

手动运行

logrotate 可以在任何时候从命令行手动调用。

要调用为 /etc/lograte.d/ 下配置的所有日志调用 logrotate

logrotate /etc/logrotate.conf

要为某个特定的配置调用 logrotate

logrotate /etc/logrotate.d/log-file

logrotate参数说明

1
2
3
4
5
6
7
8
9
10
# -d 选项以预演方式运行logrotate
logrotate -d /etc/logrotate.d/log-file

# -f 强制logrotate轮循日志文件
# -v 参数提供了详细的输出。
logrotate -vf /etc/logrotate.d/log-file

# 输出到指定的文件
# 注:logrotate自身的日志通常存放于/var/lib/logrotate/status目录。
logrotate -vf –s /var/log/logrotate-status /etc/logrotate.d/log-file

参考:

使用Linux自带日志滚动工具logrotate滚动redis日志示例

Linux日志文件总管——logrotate

Linux logrotate命令

先用 chmod 让Shell脚本有可执行权限,Linux下面用命令如何运行Shell脚本的方法,有两种方法:

1
2
3
4
5
# 1, ./ 加上文件名 .sh
./test.sh

# 2,sh 加上 文件名.sh
sh test.sh

如果没有权限,需要先设置权限,命令如下:

1
2
3
4
5
6
7
8
# 添加执行权限
chmod + x testsh

# 转到指定文件的目录下
cd test

#执行文件
./test.sh

参考:

centos执行.sh文件

Shell 教程

什么是 Transparent Huge Pages?为提升性能,通过大内存页来替代传统的4K页,使用得管理虚拟地址数变少,加快从虚拟地址到物理地址的映射,以及摒弃内存页面的换入换出以提高内存的整体性能。内核 Kernel 将程序缓存内存中,每页内存以2M为单位。相应的系统进程为 khugepaged。

在Linux中,有两种方式使用 Huge Pages,一种是2.6内核引入的 HugeTLBFS,另一种是2.6.36内核引入的THP。HugeTLBFS 主要用于数据库,THP广泛应用于应用程序。

一般可以在 rc.local 或 /etc/default/grub 中对 Huge Pages 进行设置。

Linux下的大页分为两种类型:标准大页(Huge Pages)和透明大页(Transparent Huge Pages)。Huge Pages有时候也翻译成大页/标准大页/传统大页,它们都是Huge Pages的不同中文翻译名而已。目的是使用更大的内存页面(memory page size) 以适应越来越大的系统内存,让操作系统可以支持现代硬件架构的大页面容量功能。透明大页(Transparent Huge Pages)缩写为THP,这个是RHEL 6(其它分支版本SUSE Linux Enterprise Server 11, and Oracle Linux 6 with earlier releases of Oracle Linux Unbreakable Enterprise Kernel 2 (UEK2))开始引入的一个功能。具体可以参考官方文档。这两者的区别在于大页的分配机制,标准大页管理是预分配的方式,而透明大页管理则是动态分配的方式。

CentOS7 禁用Transparent Huge Pages

自CentOS6版本开始引入了Transparent Huge Pages(THP),从 CentOS7 版本开始,该特性默认就会启用。尽管THP的本意是为提升内存的性能,不过某些数据库厂商还是建议直接关闭THP(比如说 ORACLE、MariaDB、MongoDB 等),否则可能会导致性能出现下降。

首先检查THP的启用状态:

1
2
3
4
[root@localhost ~]# cat /sys/kernel/mm/transparent_hugepage/defrag
[always] madvise never
[root@localhost ~]# cat /sys/kernel/mm/transparent_hugepage/enabled
[always] madvise never

这个状态就说明都是启用的。

我们这个时候当然可以逐个修改上述两文件,来禁用THP,但要想一劳永逸的令其永久生效,还是参考下列的步骤。

编辑 rc.local 文件:

1
[root@localhost ~]# vim /etc/rc.local

增加下列内容:

1
2
3
4
5
6
if test -f /sys/kernel/mm/transparent_hugepage/enabled; then
echo never > /sys/kernel/mm/transparent_hugepage/enabled
fi
if test -f /sys/kernel/mm/transparent_hugepage/defrag; then
echo never > /sys/kernel/mm/transparent_hugepage/defrag
fi

保存退出,然后赋予 rc.local 文件执行权限:

1
[root@localhost ~]# chmod +x /etc/rc.local

最后重启系统,以后再检查THP应该就是被禁用了

1
2
3
4
[root@localhost ~]# cat /sys/kernel/mm/transparent_hugepage/enabled
always madvise [never]
[root@localhost ~]# cat /sys/kernel/mm/transparent_hugepage/defrag
always madvise [never]

参考:

Linux传统Huge Pages与Transparent Huge Pages再次学习总结

Huge pages (标准大页)和 Transparent Huge pages(透明大页)

CentOS7 禁用Transparent Huge Pages的实现方法

OOM简介

OOM,全称 Out-Of-Memory,是一种内存分配策略。

所谓overcommit就是操作系统分配给进程的总内存大小超过了实际可用的内存,对进程而言实为虚拟内存,一个进程占用的虚拟内存空间通常比物理空间要大,甚至可能大许多,这样做的原因是进程实际上使用的内存往往比申请的内存要少。比如有个进程申请了1G的内存,但实际上它只在一小段时间里加载了大量数据,需要使用较大的内存,而在运行过程的其他大部分时间里只用了100M的内存。这样其实有900多M的内存在大部分时间里是闲置的,完全可以分给其他进程,overcommit的机制就能充分利用这些闲置的内存。

内核参数 overcommit_memory,

可选值:0、1、2。
0, 表示内核将检查是否有足够的可用内存供应用进程使用;如果有足够的可用内存,内存申请允许;否则,内存申请失败,并把错误返回给应用进程。
1, 表示内核允许分配所有的物理内存,而不管当前的内存状态如何。
2, 表示内核允许分配超过所有物理内存和交换空间总和的内存

有三种方式修改内核参数,但要有root权限:

(1)编辑 /etc/sysctl.conf ,改 vm.overcommit_memory=1 ,然后 sysctl -p 使配置文件生效
(2)sysctl vm.overcommit_memory=1
(3)echo 1 > /proc/sys/vm/overcommit_memory

系统是否行使OOM,由 /proc/sys/vm/panic_on_oom 的值决定,当 /proc/sys/vm/panic_on_oom 取值为1时表示关闭OOM,取值0时表示启用OOM。

Linux对大部分申请内存的请求都回复”yes”,以便能跑更多更大的程序。因为申请内存后,并不会马上使用内存。
Linux内核为了提高内存的使用效率采用过度分配内存(over-commit memory)的办法,造成物理内存过度紧张进而触发OOM killer机制来杀死一些进程(用户态进程,不是内核线程)回收内存。

该机制会监控那些占用内存过大,尤其是瞬间很快消耗大量内存的进程,为了防止内存耗尽会把该进程杀掉。

Linux在内存分配路径上会对内存余量做检查:
(1)如果检查到内存不足,则触发OOM机制。
(2)OOM首先会对系统所有进程(出init和内核线程等特殊进程)进行打分,并选出最bad的进程;然后杀死该进程。
(3)同时会触发内核oom_reaper进行内存收割。
(4)同时内核还提供了sysfs接口系统OOM行为,以及进程OOM行为。

Linux下每个进程都有自己的OOM权重,在 /proc/<pid>/oom_adj 里面,范围是-17到+15,取值越高,越容易被杀掉。

如果将 /proc/sys/vm/oom_kill_allocating_task 的值设置为1,则OOM时直接KILL当前正在申请内存的进程,否则OOM根据进程的oom_adj和oom_score来决定。

/proc/xxx/oom_adj:表示进程被 OOM KILLER 杀死的权重,可读写,范围是-17~15。值越大被KILL的概率越高,当进程的oom_adj值为-17时,表示永远不会被OOM KILLER选中。

/proc/xxx/oom_score_adj,可读写,范围是-1000~1000。

什么是Overcommit?当已申请的内存(Committed_AS)大小超出CommitLimit值时即为Overcommit,执行命令 cat /proc/meminfo |grep CommitLimit 可查看CommitLimit的当前大小。

CommitLimit为系统当前可以申请的内存总大小,即内存分配上限,当 overcommit_memory 值为2时,其值等于:SwapTotal + MemTotal * overcommit_ratio

而Committed_AS,表示所有进程已申请的内存总和。命令 sar -r 输出中的 kbcommit 对应 /proc/meminfo 中的 Committed_AS ,而 %commit 值等于 Committed_AS/(MemTotal+SwapTotal)

如果是大内存机器,可以考虑适当调大 /proc/sys/vm/min_free_kbytes 的值,但不能太大了,不然容易频繁触发内存回收,min_free_kbytes 是内核保留空闲内存最小值,作用是保障必要时有足够内存使用。

参考:

理解LINUX的MEMORY OVERCOMMIT

Linux内存管理 (21)OOM

linux的vm.overcommit_memory的内存分配参数详解

Linux OOM一二三

如何理解Linux中的OOM(Out Of Memory Killer)机制?

overcommit-accounting

tcp的三次握手:

微信截图_20200804174353.png

1、client发送SYN到server,将状态修改为SYN_SEND,如果server收到请求,则将状态修改为SYN_RCVD,并把该请求放到syns queue队列中。
2、server回复SYN+ACK给client,如果client收到请求,则将状态修改为ESTABLISHED,并发送ACK给server。
3、server收到ACK,将状态修改为ESTABLISHED,并把该请求从 syns queue 中放到 accept queue

backlog参数

backlog其实是一个连接队列,在Linux内核2.2之前,backlog大小包括半连接状态和全连接状态两种队列大小。

  • 半连接状态为:服务器处于Listen状态时收到客户端SYN报文时放入半连接队列中,即 SYN queue(服务器端口状态为:SYN_RCVD)。
  • 全连接状态为:TCP的连接状态从服务器(SYN+ACK)响应客户端后,到客户端的ACK报文到达服务器之前,则一直保留在半连接状态中;当服务器接收到客户端的ACK报文后,该条目将从半连接队列搬到全连接队列尾部,即 accept queue (服务器端口状态为:ESTABLISHED)。

在Linux内核2.2之后,分离为两个backlog来分别限制半连接(SYN_RCVD状态)队列大小和全连接(ESTABLISHED状态)队列大小。

927655-20161215133843776-605308204.png

syns queue

SYN queue 用于保存半连接状态的请求,队列长度由 /proc/sys/net/ipv4/tcp_max_syn_backlog 指定,默认为1024。

需要在文件 /etc/sysctl.conf 中增加一行:

net.ipv4.tcp_max_syn_backlog = 262144

互联网常见的 TCP SYN FLOOD(拒绝服务攻击) 恶意DOS攻击方式就是建立大量的半连接状态的请求,然后丢弃,导致 syns queue 不能保存其它正常的请求。

accept queue

Accept queue 用于保存全连接状态的请求,队列长度由 /proc/sys/net/core/somaxconn 和使用 listen 函数时传入的参数,二者取最小值。默认为128。在Linux内核2.4.25之前,是写死在代码常量 SOMAXCONN ,在Linux内核2.4.25之后,在配置文件 /proc/sys/net/core/somaxconn 中直接修改,或者在 /etc/sysctl.conf 中配置 net.core.somaxconn = 32768

如果 accpet queue 队列满了,server 将发送一个 ECONNREFUSED 错误信息 Connection refuseclient

立即生效还可以使用命令:sysctl -w net.core.somaxconn=32768

要想永久生效,需要在文件 /etc/sysctl.conf 中增加一行:

net.core.somaxconn = 32768

或者使用命令:

echo "net.core.somaxconn = 32768" >> /etc/sysctl.conf,

然后执行命令 sysctl -p 以生效。

注:Redis配置项 tcp-backlog 的值不能超过somaxconn的大小。

ss命令来显示:

1
2
3
4
5
6
7
[root@localhost ~]# ss -l
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:http *:*
LISTEN 0 128 :::ssh :::*
LISTEN 0 128 *:ssh *:*
LISTEN 0 100 ::1:smtp :::*
LISTEN 0 100 127.0.0.1:smtp *:*

在LISTEN状态,其中 Send-Q 即为Accept queue的最大值,Recv-Q 则表示Accept queue中等待被服务器accept()。

客户端connect()返回不代表TCP连接建立成功,有可能此时 accept queue 已满,系统会直接丢弃后续ACK请求;客户端误以为连接已建立,开始调用等待至超时;服务器则等待ACK超时,会重传 SYN+ACK 给客户端,重传次数受限 net.ipv4.tcp_synack_retries ,默认为5,表示重发5次,每次等待30~40秒,即半连接默认时间大约为180秒,该参数可以在tcp被洪水攻击是临时启用这个参数。

查看SYN queue 溢出

1
2
[root@localhost ~]# netstat -s | grep LISTEN
102324 SYNs to LISTEN sockets dropped

  
查看Accept queue 溢出

1
2
[root@localhost ~]# netstat -s | grep TCPBacklogDrop
TCPBacklogDrop: 2334

参考:

TCP/IP协议中backlog参数

浅谈tcp socket的backlog参数

Linux TCP队列相关参数的总结

简介

sysctl命令被用于在内核运行时动态地修改内核的运行参数,可用的内核参数在目录/proc/sys中。它包含一些TCP/ip堆栈和虚拟内存系统的高级选项, 这可以让有经验的管理员提高引人注目的系统性能。用sysctl可以读取设置超过五百个系统变量。

参数:

1
2
3
4
5
6
7
-n:打印值时不打印关键字;
-e:忽略未知关键字错误;
-N:仅打印名称;
-w:当改变sysctl设置时使用此项;
-p:从配置文件“/etc/sysctl.conf”加载内核参数设置;
-a:打印当前所有可用的内核参数变量和值;
-A:以表格方式打印当前所有可用的内核参数变量和值。

实例

查看所有可读变量:

sysctl -a

1
2
3
4
5
6
[root@host-192-125-30-59 ~]# sysctl -a | grep file-max
fs.file-max = 6523120
sysctl: reading key "net.ipv6.conf.all.stable_secret"
sysctl: reading key "net.ipv6.conf.default.stable_secret"
sysctl: reading key "net.ipv6.conf.eth0.stable_secret"
sysctl: reading key "net.ipv6.conf.lo.stable_secret"

参考:

sysctl命令

pam简介

PAM:全称 Pluggable Authentication Modules,中文名 插入式认证模块。

**Linux-PAM (Linux可插入认证模块)**:是一套适用于Linux的身份验证共享库系统,它为系统中的应用程序或服务提供动态身份验证模块支持。在Linux中,PAM是可动态配置的,本地系统管理员可以自由选择应用程序如何对用户进行身份验证。PAM应用在许多程序与服务上,比如登录程序(login、su)的PAM身份验证(口令认证、限制登录),passwd强制密码,用户进程实时管理,向用户分配系统资源等。

PAM的主要特征是认证的性质是可动态配置的。PAM的核心部分是库(libpam)和PAM模块的集合,它们是位于文件夹 /lib/security/ 中的动态链接库(.so)文件,以及位于 /etc/pam.d/ 目录中(或者是 /etc/pam.conf 配置文件,centos6之后,没有这个文件了)的各个PAM模块配置文件。

使用如下命令判断程序是否使用了PAM:

1
2
3
[root@host-192-125-30-59 ~]# ldd /usr/bin/passwd | grep libpam
libpam.so.0 => /lib64/libpam.so.0 (0x00007fb53bd17000)
libpam_misc.so.0 => /lib64/libpam_misc.so.0 (0x00007fb53bb13000)

如看到有类似的输出,说明该程序使用了PAM,没有输出,则没有使用。

PAM的配置文件介绍

/etc/pam.d/ 目录包含应用程序的PAM配置文件。例如,login程序将其程序/服务名称定义为login,与之对应的PAM配置文件为 /etc/pam.d/login

PAM配置文件语法格式

每个PAM配置文件都包含一组指令,用于定义模块以及控制标志和参数。每条指令都有一个简单的语法,用于标识模块的目的(接口)和模块的配置设置,语法格式如下:

1
module_interface      control_flag      module_name  module_arguments

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[root@host-192-125-30-59 ~]# vim /etc/pam.d/system-auth-ac
#%PAM-1.0
# This file is auto-generated.
# User changes will be destroyed the next time authconfig is run.
auth required pam_env.so
auth required pam_faildelay.so delay=2000000
auth sufficient pam_unix.so nullok try_first_pass
auth requisite pam_succeed_if.so uid >= 1000 quiet_success
auth required pam_deny.so

account required pam_unix.so
account sufficient pam_localuser.so
account sufficient pam_succeed_if.so uid < 1000 quiet
account required pam_permit.so

password requisite pam_pwquality.so try_first_pass local_users_only retry=3 authtok_type=
password sufficient pam_unix.so sha512 shadow nullok try_first_pass use_authtok
password required pam_deny.so

session optional pam_keyinit.so revoke
session required pam_limits.so
-session optional pam_systemd.so
session [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid

如在/etc/pam.d/password-auth-ac配置文件中(CentOS),其中一行PAM模块接口定义如下
password-auth-ac.png

PAM的模块类型

PAM为认证任务提供四种类型可用的模块接口,它们分别提供不同的认证服务:

1
2
3
4
auth	- 认证模块接口,如验证用户身份、检查密码是否可以通过,并设置用户凭据
account - 账户模块接口,检查指定账户是否满足当前验证条件,如用户是否有权访问所请求的服务,检查账户是否到期
password - 密码模块接口,用于更改用户密码,以及强制使用强密码配置
session - 会话模块接口,用于管理和配置用户会话。会话在用户成功认证之后启动生效

单个PAM库模块可以提供给任何或所有模块接口使用。例如,pam_unix.so提供给四个模块接口使用。

PAM控制标志

所有的PAM模块被调用时都会返回成功或者失败的结果,每个PAM模块中由多个对应的控制标志决定结果是否通过或失败。每一个控制标志对应一个处理结果,PAM库将这些通过/失败的结果整合为一个整体的通过/失败结果,然后将结果返回给应用程序。模块可以按特定的顺序堆叠。控制标志是实现用户在对某一个特定的应用程序或服务身份验证的具体实现细节。该控制标志是PAM配置文件中的第二个字段,PAM控制标志如下:

1
2
3
4
5
required  - 模块结果必须成功才能继续认证,如果在此处测试失败,则继续测试引用在该模块接口的下一个模块,直到所有的模块测试完成,才将结果通知给用户。
requisite - 模块结果必须成功才能继续认证,如果在此处测试失败,则会立即将失败结果通知给用户。
sufficient - 模块结果如果测试失败,将被忽略。如果sufficient模块测试成功,并且之前的required模块没有发生故障,PAM会向应用程序返回通过的结果,不会再调用堆栈中其他模块。
optional - 该模块返回的通过/失败结果被忽略。当没有其他模块被引用时,标记为optional模块并且成功验证时该模块才是必须的。该模块被调用来执行一些操作,并不影响模块堆栈的结果。
include - 与其他控制标志不同,include与模块结果的处理方式无关。该标志用于直接引用其他PAM模块的配置参数

PAM配置方法

可以使用 man 命令查看配置,比如要查找某个程序支持PAM模块的配置,可以使用 man 加模块名(去掉.so)查找说明。

man pam_unix。(模块名可以在目录/lib/security/或/lib64/security/中找到。)

参考:

Linux安全策略配置-pam_tally2身份验证模块

linux中pam模块

深入 Linux PAM 体系结构