mysql – 启动错误InnoDB: mmap(137363456 bytes) failed; errno 12

上午mysql出现了问题,很纠结,最后找到了原因,原因是内存不够用;

190925  9:25:01 [Note] Plugin ‘FEDERATED’ is disabled.
190925  9:25:01 InnoDB: The InnoDB memory heap is disabled
190925  9:25:01 InnoDB: Mutexes and rw_locks use GCC atomic builtins
190925  9:25:01 InnoDB: Compressed tables use zlib 1.2.7
190925  9:25:01 InnoDB: Using Linux native AIO
190925  9:25:01 InnoDB: Initializing buffer pool, size = 1.0G
InnoDB: mmap(1098907648 bytes) failed; errno 12
190925  9:25:01 InnoDB: Completed initialization of buffer pool
190925  9:25:01 InnoDB: Fatal error: cannot allocate memory for the buffer pool
190925  9:25:01 [ERROR] Plugin ‘InnoDB’ init function returned error.
190925  9:25:01 [ERROR] Plugin ‘InnoDB’ registration as a STORAGE ENGINE failed.
190925  9:25:01 [ERROR] Unknown/unsupported storage engine: InnoDB
190925  9:25:01 [ERROR] Aborting

190925  9:25:01 [Note] /usr/local/mysql/bin/mysqld: Shutdown complete

查看内存显示  
[root@AY1305070924544 /]# free -m
             total       used       free     shared    buffers     cached
Mem:           995        928         66          0          6         19
-/+ buffers/cache:        903         91
Swap:            0          0          0

重启错误提示 

[root@AY1305070924544 /]# /etc/init.d/mysqld start
Starting MySQL. ERROR! The server quit without updating PID file (/var/mysql/data/AY1305070924544.pid).
[root@AY1305070924544 /]# /etc/init.d/mysqld restart
 ERROR! MySQL server PID file could not be found!
Starting MySQL. ERROR! The server quit without updating PID file (/var/mysql/data/AY1305070924544.pid).

这个其实日志里面说的很明白就是 mysql要占用内存的时候 物理内存不够用导致的 所有 vim /etc/my.cnf
[inonodb]
innodb_buffer_pool_size=64MB  把这个数值改小 高版本的默认是128mb  版本的默认是8Mb

MySQL 5.6 如何给ibdata1瘦身

前不久刚给ibdata1瘦身,发篇文章总结下。

ibdata1是MySQL使用InnoDB引擎时所产生的文件,其一般存储数据、索引、结构、缓冲数据、共享数据和重做日志等。因为ibdata1只增不减,长期操作数据库,可能会使其越来越大,而浪费空间。

加上使用InnoDB引擎时,没有添加innodb_file_per_table参数也是导致ibdata1过大的原因。

但InnoDB只增不减,也导致给ibdata1瘦身是件比较麻烦的事。

最大的我见过的是40多G的ibdata1文件,实际数据库差不多是20多G,在做了优化后,ibdata1缩小至20多G,所以说减肥还是有必要的。

首先,先略微说下innodb_file_per_table参数,使用该参数可使得InnoDB引擎转变为独立表空间模式(默认为共享表空间),也就是每个数据库的每个表都会生成一个数据空间,就像MyISAM引擎一样。

 
独立表空间优点就是每个表有独立空间,数据和索引都会存在自已的表空间中,可以实现单表在不同的数据库中移动。重要的是空间可以回收,而且不管日常怎么操作,表空间的碎片不会太严重的影响性能,优化表的速度也快,表文件出现问题不会大动干戈,只要修复对应表即可。缺点是单表占用的空间比共享表空间方式稍大,共享表空间在Insert操作上有一些优势。

所以没增加innodb_file_per_table参数的同学,建议还是加上吧。因为增加innodb_file_per_table参数,与我们后续给ibdata1瘦身并无冲突,而且对以后也只有好处。

说了这么多废话,言归正传。谈谈怎么给ibdata1瘦身,唯一的方法是就是备份整个数据库,然后删掉ibdata1和ib_logfile*,再恢复数据库,以此达到瘦身目的。当然了,操作数据库肯定是有风险的,而且也需要生产环境允许MySQL暂停写或访问。

简单的总结就是以下这几点:

1.在/etc/my.cnf中添加“innodb_force_recovery=4”使InnoDB成为只读表,这其实应该说是第一个坑。另外确定“innodb_data_file_path”参数限定的初始ibdata1大小在合理范围,一般稍大于现有数据大小。
2.启动MySQL,使用我给的工具备份除了mysql、information_schema和performance_schema的整个数据库。为以后顺利恢复数据做准备。
3.删除除了mysql、information_schema和performance_schema的整个数据库,这3个排除在外的其实也删不掉。
4.停止MySQL,删除ibdata1和ib_logfile*文件。
5.删除数据库目录中的mysql目录的innodb_index_stats.*、innodb_table_stats.*、slave_master_info.*、slave_relay_log_info.*、slave_worker_info.*文件,这5个是InnoDB的基础表(状态表),这是MySQL 5.6的坑,删除ibdata1后不会自动重建这5个表,而且如果不删除这些旧文件,还不可创建或重建新的。
6.在/etc/my.cnf把“innodb_force_recovery=4”去除。
7.启动MySQL,将第2步备份的数据库还原,然后用从MySQL 5.6导出来的InnoDB基础表备份还原回去重建(第5步删掉的)。
8.搞定,重启下MySQL,确保没有错误,没有异常。

必要的工具,在文末的Github地址下载。

下面详细说说每个步骤,首先是设置InnoDB为只读表,这还是比较必要的。可确保你的数据完整性、安全性。为何是坑呢,因为我遇到过没这样设置,导致后续恢复备份时,数据有异常。

具体操作,在/etc/my.cnf中添加“innodb_force_recovery=4”


[mysqld]

innodb_force_recovery = 4

如此便可,innodb_file_per_table也是在[mysqld]下添加。

innodb_force_recovery的值可以设置为1-6,大的数字包含其前面所有数字的影响。

1. (SRV_FORCE_IGNORE_CORRUPT):忽略检查到的corrupt页。
2. (SRV_FORCE_NO_BACKGROUND):阻止主线程的运行,如主线程需要执行full purge操作,会导致crash。
3. (SRV_FORCE_NO_TRX_UNDO):不执行事务回滚操作。
4. (SRV_FORCE_NO_IBUF_MERGE):不执行插入缓冲的合并操作。
5. (SRV_FORCE_NO_UNDO_LOG_SCAN):不查看重做日志,InnoDB存储引擎会将未提交的事务视为已提交。
6. (SRV_FORCE_NO_LOG_REDO):不执行前滚的操作。

接着呢,启动MySQL,备份整个数据库,一般我们会用

mysqldump –lock-all-tables –all-databases > all-dbs.sql
来完整备份数据库。但这样的话,就包含了mysql、information_schema和performance_schema这3个数据库,而在后续还原数据库,带着这3个数据库可能会出错(我有几次遇到过)。

所以我提供了shell脚本工具mysql_dump_all_db.sh,因为怕大家不像我是免密码操作MySQL的,在使用工具前,请先修改脚本中的MySQL帐号和密码,然后再通过

sh mysql_dump_all_db.sh
执行备份操作,备份好的文件,会存放在脚本运行所在目录。

这个工具默认排除mysql、information_schema和performance_schema这3个数据库,如果你有其他想排除的,可以直接修改脚本,增加其他想要排除的数据库。

完了之后呢,删除所有数据库,可以通过phpMyadmin或直接在shell操作MySQL删除,在shell下删除,可以在/tmp/DatabasesToDump.txt查看到所有数据库,由“mysql_dump_all_db.sh”生成。我一般在phpMyadmin删除,简单,不怕错。如你所见,mysql、information_schema和performance_schema这3个数据库是删不掉的,所以要排除,免得麻烦。

 
搞定后,就可以停止MySQL了。删除数据库目录的ibdata1和ib_logfile*文件,一般是在/usr/local/mysql/data,看你怎么配置的了。

接着,在该目录下的mysql目录(/usr/local/mysql/data/mysql)中,把innodb_index_stats.*、innodb_table_stats.*、slave_master_info.*、slave_relay_log_info.*、slave_worker_info.*共计10个文件删除,这些文件已经无用了,而且占着茅坑不拉屎。MySQL 5.6很煞笔的不会重建这5个表,如果你不删除他们,待会将无法重建或恢复这5个表,接着log一直在报错,死循环。所以要把这5个表的10个文件干掉。所以这个是个坑。

在/etc/my.cnf把“innodb_force_recovery=4”去除后,就可以启动MySQL了,这时候ibdata1和ib_logfile*文件会重建。噢,上帝,胜利在望,不要激动,让我们继续吧。

把刚才备份的所有数据库还原,用从MySQL 5.6导出来的InnoDB基础表备份还原回去重建。

我在后面的Github地址有提供,从全新 MySQL 5.6导出的,名字为“mysql_innodb_basic_tables.sql”的备份文件,通过它可以重建刚才删掉的5个InnoDB基础表。

还原数据库文件非常简单,不过我还是略微写下,照顾下小白,在shell下:

mysql < all-dbs.sql
mysql < mysql_innodb_basic_tables.sql
这样就OK了,如没有免密码操作权限,请自行添加-u和-p参数。

好的,做完这些,重启下MySQL,确保没有错误即可。这样就完成了对ibdata1的瘦身。

以上操作环境为:CentOS 6.6 x64、MySQL 5.6.25。

工具存放在Github中(原谅我的渣英文),见: https://github.com/kn007/Reduce-Shrink-Purge-the-ibdata1-file-in-MySQL

写这篇文章就是为了大家少走一点弯路,也把自己遇到的坑说一下。算是个总结,也是给后人的一些经验。原则上不提供技术支持,有问题请自行解决。另外毕竟是数据库,瘦身有风险,操作需谨慎。

xfs文件删除没有释放,系统重启还是没有释放

XFS文件系统管理常用命令记录

xfs_fsr /dev/vda1 单用户模式后,用碎片整理好恢复正常。

常用命令说明

mkfs.xfs
创建xfs文件系统
xfs_admin
调整XFS文件系统各种参数
xfs_copy
并行地拷贝XFS文件系统的内容到一个或多个目标系统中
xfs_db
调试或检测XFS文件系统
xfs_check
检测XFS文件系统完整性
xfs_bmap
查看一个文件的块映射
xfs_repair
尝试修复受损的XFS文件系统
xfs_fsr
碎片整理
xfs_quota
管理XFS文件系统的磁盘配额
xfs_metadump
导出XFS文件系统的元数据
xfs_growfs
扩展XFS文件系统大小
xfs_freeze
暂停/恢复XFS文件系统

创建XFS文件系统

使用 mkfs.xfs 可以将存储设备格式化为XFS格式

dd if=/dev/zero of=~/xfs.img bs=1M count=4096
mkfs.xfs ~/xfs.img

meta-data=/home/lujun9972/xfs.img isize=512    agcount=4, agsize=262144 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=1        finobt=1, sparse=1, rmapbt=0
         =                       reflink=0
data     =                       bsize=4096   blocks=1048576, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0, ftype=1
log      =internal log           bsize=4096   blocks=2560, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0

但若原存储已经被格式化过,则 mkfs.xfs 会拒绝再次格式化

mkfs.xfs ~/xfs.img 2>&1 ||exit 0

mkfs.xfs: /home/lujun9972/xfs.img appears to contain an existing filesystem (xfs).
mkfs.xfs: Use the -f option to force overwrite.

这个时候需要用 -f 选项表示强行格式化

mkfs.xfs -f ~/xfs.img

meta-data=/home/lujun9972/xfs.img isize=512    agcount=4, agsize=262144 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=1        finobt=1, sparse=1, rmapbt=0
         =                       reflink=0
data     =                       bsize=4096   blocks=1048576, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0, ftype=1
log      =internal log           bsize=4096   blocks=2560, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0

设置block大小

block是文件系统存储的最小单位,较大的block可以增加文件系统和单个文件的大小上限并加快大文件的读写速度,但是会浪费较多空间。而太小的block则相反。

我们可以在格式化时指定block的大小,XFS的大小最小为512字节,最大为64KB,默认为4K

在格式化时使用 -b size=block大小 来指定区块大小

mkfs.xfs -f -b size=1k ~/xfs.img

meta-data=/home/lujun9972/xfs.img isize=512    agcount=4, agsize=1048576 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=1        finobt=1, sparse=1, rmapbt=0
         =                       reflink=0
data     =                       bsize=1024   blocks=4194304, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0, ftype=1
log      =internal log           bsize=1024   blocks=10240, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0

这里大小单位可以是”k”表示kb,或者”s”表示扇区数,一个扇区默认为512字节,但可以通过 -s 选项改变。

XFS允许目录使用比文件系统block更大的block,方法是使用 -n size=block大小

mkfs.xfs -f -b size=1k -n size=4k ~/xfs.img

meta-data=/home/lujun9972/xfs.img isize=512    agcount=4, agsize=1048576 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=1        finobt=1, sparse=1, rmapbt=0
         =                       reflink=0
data     =                       bsize=1024   blocks=4194304, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0, ftype=1
log      =internal log           bsize=1024   blocks=10240, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0

日志大小

格式化XFS时,mkfs.xfs会根据文件系统的大小自动分配日志的大小。 日志大小介于512KB到128MB之间,但可以通过 -l size=日志大小 来设置,其中日志的单位可以是:

s
扇区
b
block
k
KB
m
MB
g
GB
t
TB
p
PB
e
EB
mkfs.xfs -f -l size=64m ~/xfs.img

meta-data=/home/lujun9972/xfs.img isize=512    agcount=4, agsize=262144 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=1        finobt=1, sparse=1, rmapbt=0
         =                       reflink=0
data     =                       bsize=4096   blocks=1048576, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0, ftype=1
log      =internal log           bsize=4096   blocks=16384, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0

设置文件系统标签

Label或者说Volume Name可以用来说明文件系统的用途,可以通过 -L 标签 来设置

mkfs.xfs -f -L TEST ~/xfs.img

meta-data=/home/lujun9972/xfs.img isize=512    agcount=4, agsize=262144 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=1        finobt=1, sparse=1, rmapbt=0
         =                       reflink=0
data     =                       bsize=4096   blocks=1048576, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0, ftype=1
log      =internal log           bsize=4096   blocks=2560, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0

我们可以使用 xfs_admin 来查看当前的label

xfs_admin -l ~/xfs.img

label = "TEST"

挂载XFS文件系统

在挂载时,可以使用一些性能增强的选项来发掘XFS文件系统的性能

sudo mount -t xfs ~lujun9972/xfs.img /mnt -o noatime,nodiratime

其他常见的 -o 选项包括:

allocsize
延时分配时,预分配缓冲区的大小
discard / nodiscard
块设备是否自动回收空间
largeio
大块分配
nolargeio
尽量小块分配
noatime
读取文件时不更新访问时间
nodiratime
不更新目录的访问时间
norecovery
挂载时不运行日志恢复
logbufs
内存中的日志缓冲区数量
logbsize
内存中每个日志缓存区的大小

调整XFS文件系统参数

使用 xfs_admin 来调整XFS文件系统参数

卷标管理

设置卷标

xfs_admin -L "another_volume" ~/xfs.img

writing all SBs
xfs_admin: truncating label length from 14 to 12
new label = "another_volu"

查看卷标

xfs_admin -l ~/xfs.img

label = "another_volu"

UUID管理

传统上Linux在/etc/fstab中直接使用设备名称指定要挂载的存储设备。 然而设备名称会因为BIOS或硬件的改变而改变,引起混乱,因此现在Linux改用UUID来指定要挂载的存储设备。

查看指定设备的UUID

xfs_admin -u ~/xfs.img

UUID = aceeca47-82a0-47ce-a2e6-704569ebcbd4

设置设备的UUID

xfs_admin -U 12345678-9012-3456-7890-123456789012 ~/xfs.img

Clearing log and setting UUID
writing all SBs
new UUID = 12345678-9012-3456-7890-123456789012

你也可以给 -U 参数传递 generate 表示随机生成新的UUID

xfs_admin -U generate ~/xfs.img

Clearing log and setting UUID
writing all SBs
new UUID = 9618fe39-638d-41b0-9863-5b3b8daa9801

清除文件系统的UUID

xfs_admin -U nil ~/xfs.img

Clearing log and setting UUID
writing all SBs
new UUID = 00000000-0000-0000-0000-000000000000

扩展XFS文件系统的大小

XFS文件系统只能扩大,不能减少大小

扩容指定容量

sudo xfs_growfs -D 20G /mnt

扩展全部未用容量

sudo xfs_growfs -d /mnt

暂停/恢复XFS文件系统

xfs_freeze 命令可以停止对文件系统的访问并创建一个静态的磁盘镜像。

暂停XFS文件系统

sudo xfs_freeze -f /mnt

这个时候任何对文件系统的操作都会被挂起

恢复XFS文件系统

sudo xfs_freeze -u /mnt

修复XFS文件系统

sudo umount /mnt
xfs_repair ~lujun9972/xfs.img

碎片管理

查看碎片情况

xfs_db -c frag -r ~/xfs.img

actual 0, ideal 0, fragmentation factor 0.00%
Note, this number is largely meaningless.
Files on this filesystem average -nan extents per file

整理碎片

xfs_fsr ~/xfs.img

执行yum报 undefined symbol: CRYPTO_set_locking_callback 错误

源码安装了curl之后, 导致yum执行时报如下错误:

/usr/lib64/python2.6/site-packages/pycurl.so: undefined symbol: CRYPTO_set_locking_callback

是因为yum动态库使用了新安装libcurl库导致的。使用ldd查看动态库依赖关系:

ldd /usr/lib64/python2.6/site-packages/pycurl.so

可以发现libcurl.so.4 指向了新安装的libcurl。 

查找系统旧有的libcurl

find / -name “libcurl*”

/usr/lib64/libcurl.so.4 -> libcurl.so.4.1.1

/usr/local/lib/libcurl.so.4 -> libcurl.so.4.4.0

 

有两种方法解决:

1. 直接将/usr/local/lib/libcurl.so.4 软连接到旧有libcurl中

    rm  /usr/local/lib/libcurl.so.4

    ln -s /usr/lib64/libcurl.so.4.1.1 /usr/local/lib/libcurl.so.4

 

2. 设置LD_LIBRARY_PATH,  将旧有的libcurl路径放置在前面

export LD_LIBRARY_PATH=/usr/lib64:$LD_LIBRARY_PATH

Redis服务器设置密码后,使用/etc/init.d/redis restart出现(error) NOAUTH Authentication required.

Redis服务器设置密码后,使用/etc/init.d/redis restart出现(error) NOAUTH Authentication required.

#/etc/init.d/redis restart

Stopping …

OK
(error) NOAUTH Authentication required.
Waiting for Redis to shutdown …
Waiting for Redis to shutdown …
Waiting for Redis to shutdown …
Waiting for Redis to shutdown …
Waiting for Redis to shutdown …
Waiting for Redis to shutdown …
Waiting for Redis to shutdown …
Waiting for Redis to shutdown …
出现这样的错误信息,redis 这时是没有停止服务的。

可以使用ps -ef | grep redis  查进程号 然后kill 掉,如果在deamon下还需要去删除pid文件,有点繁琐。

解决办法:

用redis-cli 密码登陆(redis-cli -a  password)就OK了。

再用ps -ef | grep redis 可以看到redis进程已经正常退出。

修改redis服务脚本,加入如下所示的红色授权信息即可:

vi /etc/init.d/redis
$CLIEXEC -a “password” -p $REDISPORT shutdown

sqlite3数据库命令及数据库导入导出

1.  sqlite3 dbName.sqlite3  加载数据库,不存载就创建

2.  .help  帮助详解

    

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
sqlite> .help
.backup ?DBFILE      Backup DB (default "main") to FILE
.bail ON|OFF           Stop after hitting an error.  Default OFF
.databases             List names and files of attached databases
.dump ?TABLE? ...      Dump the database in an SQL text format
                         If TABLE specified, only dump tables matching
                         LIKE pattern TABLE.
.echo ON|OFF           Turn command echo on or off
.exit                  Exit this program
.explain ?ON|OFF?      Turn output mode suitable for EXPLAIN on or off.
                         With no args, it turns EXPLAIN on.
.header(s) ON|OFF      Turn display of headers on or off
.help                  Show this message
.import FILE TABLE     Import data from FILE into TABLE
.indices ?TABLE?       Show names of all indices
                         If TABLE specified, only show indices for tables
                         matching LIKE pattern TABLE.
.load FILE ?ENTRY?     Load an extension library
.log FILE|off          Turn logging on or off.  FILE can be stderr/stdout
.mode MODE ?TABLE?     Set output mode where MODE is one of:
                         csv      Comma-separated values
                         column   Left-aligned columns.  (See .width)
                         html     HTML <table> code
                         insert   SQL insert statements for TABLE
                         line     One value per line
                         list     Values delimited by .separator string
                         tabs     Tab-separated values
                         tcl      TCL list elements
.nullvalue STRING      Print STRING in place of NULL values
.output FILENAME       Send output to FILENAME
.output stdout         Send output to the screen
.prompt MAIN CONTINUE  Replace the standard prompts
.quit                  Exit this program
.read FILENAME         Execute SQL in FILENAME
.restore ?DBFILE     Restore content of DB (default "main") from FILE
.schema ?TABLE?        Show the CREATE statements
                         If TABLE specified, only show tables matching
                         LIKE pattern TABLE.
.separator STRING      Change separator used by output mode and .import
.show                  Show the current values for various settings
.stats ON|OFF          Turn stats on or off
.tables ?TABLE?        List names of tables
                         If TABLE specified, only list tables matching
                         LIKE pattern TABLE.
.timeout MS            Try opening locked tables for MS milliseconds
.width NUM1 NUM2 ...   Set column widths for "column" mode
.timer ON|OFF          Turn the CPU timer measurement on or off

3. 应用截图

加载

root@ubuntu:~/workspace/SVN_AUTH/db# sqlite3 development.sqlite3
SQLite version 3.7.2
Enter ".help" for instructions
Enter SQL statements terminated with a ";"

显示数据库

1
2
3
4
sqlite> .databases
seq  name             file                                                     
---  ---------------  ----------------------------------------------------------
0    main             /root/workspace/SVN_AUTH/db/development.sqlite3          

显示表

sqlite> .tables
applies            logs               repositories       users           
deps               permits            schema_migrations

显示表的内容

sqlite> .head on  #显示表头
sqlite> select * from users;
id|name|brief|group|dep_id|created_at|updated_at
1|3B-7-1-16  刘文民|liuwm|superadmin||2011-08-08 08:11:37.283136|2011-08-08 08:11:37.283136
3|3D-1-01  贾延平|jiayp|admin||2011-08-08 08:19:51.745947|2011-08-08 08:19:51.745947
4|3B-7-1-11 杜宏伟|duhw|||2011-08-08 08:33:51.496746|2011-08-08 08:33:51.496746
5|3B-2-14  苑辰|yuanc-a|emplooyee||2011-08-08 08:52:03.229173|2011-08-08 08:52:03.229173
6|3B-2-16  周四维|zhousw|||2011-08-08 08:54:21.134175|2011-08-08 08:54:21.134175
7|3B-2-12  施晟|shis|||2011-08-08 08:56:01.234077|2011-08-08 08:56:01.234077

显示创建表的脚本(不跟参数显示所有的)


sqlite的数据导入 导出

数据导入的来源可以是其他应用程序的输出,也可以是指定的文本文件,这里采用指定的文本文件。



   1. 首先,确定导入的数据源,这里是待导入的,按固定格式的文本文件。

   2. 然后,依照导入的文件格式,确定想导入的目标数据表,这个数据表如果没有,可以依照待导入的文本文件格式,创建一个相对应的数据表。

   3. 最后,执行.import命令,将文本文件中数据导入数据表中。





1. 数据源



   在/home/ywx/yu/sqlite/下,创建一个名为data.txt的文本文件,并输入以下数据,数据之间采用逗号隔开

  1. id,name,age,address,hobby

  2. 1,tom,24,beijing,football
  3. 2,liu,27,heibei,fotball
  4. 3,jim,26,shandong,football
  5. 4,han,28,beijing,football
  6. 5,meng,25,beijing,tennis

 

2. 目标数据表

    这里创建一张目标数据表,通过分析文本格式,这里需要3个字段,分别是id,name,age。但在数据类型选择时存在一个问题,id和age在文本文件中是按字符型存储的,而其实际在数据表中,最好要表示成整型,因此这里要涉及到一个字符型数据类型向整型数据类型转换的问题。

    在创建表时,将id和age的类型定义为整型,进行强制转换,如果在数据导入时,发现转换失败,可以将id和age类型改为文本型。



  1. ywx@ywx:~/yu/sqlite$ sqlite3 test.db

  2. SQLite version 3.7.7.1 20110628 17:39:05
  3. Enter “.help” for instructions
  4. Enter SQL statements terminated with a “;”
  5. sqlite> create table data_txt_table(id char(10),name char(10),age char(10),address varchar(15),hobby varchar (15));
  6. sqlite>



3. 导入命令



  1. sqlite> .separator “,” 

  2. sqlite> .import data.txt data_txt_table
  3. sqlite> select * from data_txt_table;
  4. id,name,age,address,hobby
  5. 1,tom,24,beijing,football
  6. 2,liu,27,heibei,fotball
  7. 3,jim,26,shandong,football
  8. 4,han,28,beijing,football
  9. 5,meng,25,beijing,tennis
  10. sqlite>



   这里需要注意一点,在数据导入之前,先要根据数据的具体分的格式,设置数据导入的间隔符,例如在文本数据中采用的是‘,’来间隔数据,因此应先调用.seperator 设置‘,’ 为间隔符。





2. 查看命令

  

  .schema 命令来查看指定的数据表的结构

  1. sqlite> .schema data_txt_table

  2. CREATE TABLE data_txt_table(id char(10),name char(10),age char(10),address varchar(15),hobby varchar (15));
  3. sqlite>



2. .tables 命令用来查看当前数据库的所有数据表



  1. sqlite> .tables

  2. data_txt_table
  3. sqlite>



3. databases 命令用来查看当前所有数据库



  1. sqlite> .databases

  2. seq name file 
  3.   
  4. 0 main /home/ywx/yu/sqlite/test.db 
  5. 1 temp





3. 数据导出



   数据导出也是一个常用到的操作,可以将指定表中的数据导出成SQL脚本,供其他数据库使用,还可以将指定的数据表中的数据完整定位到标准输出,也可以将指定数据库中的数据完整的导入到另一个指定数据库等,



1. 导出成指定的SQL脚本

   将sqlite中指定的数据表以SQL创建脚本的形式导出,具体命令



  1. ywx@ywx:~/yu/sqlite$ sqlite3 test.db

  2. SQLite version 3.7.7.1 20110628 17:39:05
  3. Enter “.help” for instructions
  4. Enter SQL statements terminated with a “;”
  5. sqlite> .output data.sql
  6. sqlite> .dump
  7. sqlite>

 

  1. ywx@ywx:~/yu/sqlite$ ll

  2. 总计 16
  3. drwxrxrx 2 ywx ywx 4096 20110813 23:15 ./
  4. drwxrxrx 7 ywx ywx 4096 20110813 20:53 ../
  5. rwrr 1 ywx ywx 602 20110813 23:17 data.sql
  6. rwrr 1 ywx ywx 2048 20110813 22:44 test.db



2. 数据库导出



  1. data.sql test.db

  2. ywx@ywx:~/yu/sqlite$ sqlite3 test.db “.dump” | sqlite3 test2.db
  3. ywx@ywx:~/yu/sqlite$ ll
  4. 总计 20
  5. drwxrxrx 2 ywx ywx 4096 20110813 23:20 ./
  6. drwxrxrx 7 ywx ywx 4096 20110813 20:53 ../
  7. rwrr 1 ywx ywx 602 20110813 23:17 data.sql
  8. rwrr 1 ywx ywx 2048 20110813 23:20 test2.db
  9. rwrr 1 ywx ywx 2048 20110813 22:44 test.db



3. 其他格式,如:htm格式输出



  1. ywx@ywx:~/yu/sqlite$ sqlite3 html test.db “select * from data_txt_table” > liu.htm

  2. ywx@ywx:~/yu/sqlite$ ls
  3. data.sql liu.htm test2.db test.db
  4. http://blog.chinaunix.net/uid-22666248-id-2182334.html

使用 Nginx 实现灰度发布

灰度发布是指在黑与白之间,能够平滑过渡的一种发布方式。AB test就是一种灰度发布方式,让一部分用户继续用A,一部分用户开始用B,如果用户对B没有什么反对意见,那么逐步扩大范围,把所有用户都迁移到B上面来。

灰度发布可以保证整体系统的稳定,在初始灰度的时候就可以发现、调整问题,以保证其影响度。

灰度发布常见一般有三种方式:

  • Nginx+LUA方式
  • 根据Cookie实现灰度发布
  • 根据来路IP实现灰度发布

本文主要将讲解根据Cookie和来路IP这两种方式实现简单的灰度发布,Nginx+LUA这种方式涉及内容太多就不再本文展开了。

A/B测试流程

Nginx根据Cookie实现灰度发布

根据Cookie查询Cookie键为version的值,如果该Cookie值为V1则转发到hilinux_01,为V2则转发到hilinux_02。Cookie值都不匹配的情况下默认走hilinux_01所对应的服务器。

两台服务器分别定义为:

1 2 
hilinux_01  192.168.1.100:8080 hilinux_02  192.168.1.200:8080 
  • 用if指令实现
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 33 34 35 
upstream hilinux_01 {  server 192.168.1.100:8080 max_fails=1 fail_timeout=60; }  upstream hilinux_02 {  server 192.168.1.200:8080 max_fails=1 fail_timeout=60; }  upstream default {  server 192.168.1.100:8080 max_fails=1 fail_timeout=60; }  server {  listen 80;  server_name  www.hi-linux.com;  access_log  logs/www.hi-linux.com.log  main;   #match cookie  set $group "default";  if ($http_cookie ~* "version=V1"){  set $group hilinux_01;  }   if ($http_cookie ~* "version=V2"){  set $group hilinux_02;  }   location / {   proxy_pass http://$group;  proxy_set_header   Host             $host;  proxy_set_header   X-Real-IP        $remote_addr;  proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;  index  index.html index.htm;  }  } 
  • 用map指令实现

在Nginx里面配置一个映射,$COOKIE_version可以解析出Cookie里面的version字段。$group是一个变量,{}里面是映射规则。

如果一个version为V1的用户来访问,$group就等于hilinux_01。在server里面使用就会代理到http://hilinux_01上。version为V2的用户来访问,$group就等于hilinux_02。在server里面使用就会代理到http://hilinux_02上。Cookie值都不匹配的情况下默认走hilinux_01所对应的服务器。

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 
upstream hilinux_01 {  server 192.168.1.100:8080 max_fails=1 fail_timeout=60; }  upstream hilinux_02 {  server 192.168.1.200:8080 max_fails=1 fail_timeout=60; }  upstream default {  server 192.168.1.100:8080 max_fails=1 fail_timeout=60; }   map $COOKIE_version $group { ~*V1$ hilinux_01; ~*V2$ hilinux_02; default default; }  server {  listen 80;  server_name  www.hi-linux.com;  access_log  logs/www.hi-linux.com.log  main;   location / {   proxy_pass http://$group;  proxy_set_header   Host             $host;  proxy_set_header   X-Real-IP        $remote_addr;  proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;  index  index.html index.htm;  }  } 

Nginx根据来路IP实现灰度发布

如果是内部IP,则反向代理到hilinux_02(预发布环境);如果不是则反向代理到hilinux_01(生产环境)。

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 
upstream hilinux_01 {  server 192.168.1.100:8080 max_fails=1 fail_timeout=60; }  upstream hilinux_02 {  server 192.168.1.200:8080 max_fails=1 fail_timeout=60; }  upstream default {  server 192.168.1.100:8080 max_fails=1 fail_timeout=60; }  server {  listen 80;  server_name  www.hi-linux.com;  access_log  logs/www.hi-linux.com.log  main;    set $group default;  if ($remote_addr ~ "211.118.119.11") {  set $group hilinux_02;  }  location / {   proxy_pass http://$group;  proxy_set_header   Host             $host;  proxy_set_header   X-Real-IP        $remote_addr;  proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;  index  index.html index.htm;  } } 

如果你只有单台服务器,可以根据不同的IP设置不同的网站根目录来达到相同的目的。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 
server {  listen 80;  server_name  www.hi-linux.com;  access_log  logs/www.hi-linux.com.log  main;   set $rootdir "/var/www/html";  if ($remote_addr ~ "211.118.119.11") {  set $rootdir "/var/www/test";  }   location / {  root $rootdir;  } } 

到此最基本的实现灰度发布方法就讲解完了,如果要做更细粒度灰度发布可参考ABTestingGateway项目。

ABTestingGateway是新浪开源的一个动态路由系统。ABTestingGateway是一个可以动态设置分流策略的灰度发布系统,工作在7层,基于nginx和ngx-lua开发,使用redis作为分流策略数据库,可以实现动态调度功能。

ABTestingGateway:https://github.com/CNSRE/ABTestingGateway

https://www.hi-linux.com/posts/34319.html

linux系统收到SYN但不回SYN+ACK问题排查

wKioL1mKiFzyAHTYAAZzy5AQiS4317.jpg

二,排查

1,发现系统没有任何负载

2,网卡也没有丢包

3,iptables策略也都没问题

4,系统的SYN_RECV连接很少,也没超限

5,系统的文件描述符等资源也都没问题

6,messages和dmesg中没有任何提示或者错误信息

7,通过netstat命令查看系统上协议统计信息,发现很多请求由于时间戳的问题被rejected

# netstat -s |grep reject
    2181 passive connections rejected because of time stamp
    34 packets rejects in established connections because of timestamp

三,通过google来协助

发现有同样的人遇见这个问题:

是通过调整sysctl -w net.ipv4.tcp_timestamps=0或者sysctl -w net.ipv4.tcp_tw_recycle=0来解决这个问题,于是我就顺藤摸瓜继续查。

而在查询这两个参数的过程中,发现问题原因如下:

发现是 Linux tcp_tw_recycle/tcp_timestamps设置导致的问题。 因为在linux kernel源码中发现tcp_tw_recycle/tcp_timestamps都开启的条件下,60s内同一源ip主机的socket connect请求中的timestamp必须是递增的。经过测试,我这边centos6系统(kernel 2.6.32)和centos7系统(kernel 3.10.0)都有这问题。

    源码函数:kernel 2.6.32 tcp_v4_conn_request(),该函数是tcp层三次握手syn包的处理函数(服务端);
    源码片段:
       if (tmp_opt.saw_tstamp &&
            tcp_death_row.sysctl_tw_recycle &&
            (dst = inet_csk_route_req(sk, req)) != NULL &&
            (peer = rt_get_peer((struct rtable *)dst)) != NULL &&
            peer->v4daddr == saddr) {
            if (get_seconds() < peer->tcp_ts_stamp + TCP_PAWS_MSL &&
                (s32)(peer->tcp_ts – req->ts_recent) >
                            TCP_PAWS_WINDOW) {
                NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSPASSIVEREJECTED);
                goto drop_and_release;
            }
        }
        
        tmp_opt.saw_tstamp:该socket支持tcp_timestamp
        sysctl_tw_recycle:本机系统开启tcp_tw_recycle选项
        TCP_PAWS_MSL:60s,该条件判断表示该源ip的上次tcp通讯发生在60s内
        TCP_PAWS_WINDOW:1,该条件判断表示该源ip的上次tcp通讯的timestamp 大于 本次tcp

总结:

我这边和其它同事通过公司出口(NAT网关只有1个ip地址)访问问题server,由于timestamp时间为系统启动到当前的时间,故我和其它同事的timestamp肯定不相同;根据上述SYN包处理源码,在tcp_tw_recycle和tcp_timestamps同时开启的条件下,timestamp大的主机访问serverN成功,而timestmap小的主机访问失败。并且,我在办公网找了两台机器可100%重现这个问题。

解决:

# echo “0” > /proc/sys/net/ipv4/tcp_tw_recycle

四,扩展

1,net.ipv4.tcp_timestamps

tcp_timestamps的本质是记录数据包的发送时间。基本的步骤如下:

发送方在发送数据时,将一个timestamp(表示发送时间)放在包里面

接收方在收到数据包后,在对应的ACK包中将收到的timestamp返回给发送方(echo back)

发送发收到ACK包后,用当前时刻now – ACK包中的timestamp就能得到准确的RTT

当然实际运用中要考虑到RTT的波动,因此有了后续的(Round-Trip Time Measurement)RTTM机制。

TCP Timestamps Option (TSopt)具体设计如下

Kind: 8             // 标记唯一的选项类型,比如window scale是3
Length: 10 bytes    // 标记Timestamps选项的字节数
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
| Kind=8 | Length=10 | TS Value (TSval) | TS ECho Reply (TSecr) |
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
   1          1             4                       4
timestamps一个双向的选项,当一方不开启时,两方都将停用timestamps。比如client端发送的SYN包中带有timestamp选项,但server端并没有开启该选项。则回复的SYN-ACK将不带timestamp选项,同时client后续回复的ACK也不会带有timestamp选项。当然,如果client发送的SYN包中就不带timestamp,双向都将停用timestamp。

tcp数据包中timestamps的value是系统开机时间到现在时间的(毫秒级)时间戳。

参数:

0:停用

1:启用(系统默认值)

2,net.ipv4.tcp_tw_recycle

TCP规范中规定的处于TIME_WAIT的TCP连接必须等待2MSL时间。但在linux中,如果开启了tcp_tw_recycle,TIME_WAIT的TCP连接就不会等待2MSL时间(而是rto或者60s),从而达到快速重用(回收)处于TIME_WAIT状态的tcp连接的目的。这就可能导致连接收到之前连接的数据。为此,linux在打开tcp_tw_recycle的情况下,会记录下TIME_WAIT连接的对端(peer)信息,包括IP地址、时间戳等。这样,当内核收到同一个IP的SYN包时,就会去比较时间戳,检查SYN包的时间戳是否滞后,如果滞后,就将其丢掉(认为是旧连接的数据)。这在绝大部分情况下是没有问题的,但是对于我们实际的client-server的服务,访问我们服务的用户一般都位于NAT之后,如果NAT之后有多个用户访问同一个服务,就有可能因为时间戳滞后的连接被丢掉。

参数:

0:停用(系统默认值)

1:启用

参考:

https://serverfault.com/questions/235965/why-would-a-server-not-send-a-syn-ack-packet-in-response-to-a-syn-packet

http://hustcat.github.io/tcp_tw_recycle-and-tcp_timestamp/

linux free 查询可用内存

free工具用来查看系统可用内存:

/opt/app/tdev1$free
             total       used       free     shared    buffers     cached
Mem:       8175320    6159248    2016072          0     310208    5243680
-/+ buffers/cache:     605360    7569960
Swap:      6881272      16196    6865076

解释一下Linux上free命令的输出。

下面是free的运行结果,一共有4行。为了方便说明,我加上了列号。这样可以把free的输出看成一个二维数组FO(Free Output)。例如:

FO[2][1] = 24677460 FO[3][2] = 10321516 1 2 3 4 5 6 1 total used free shared buffers cached 2 Mem: 24677460 23276064 1401396 0 870540 12084008 3 -/+ buffers/cache: 10321516 14355944 4 Swap: 25151484 224188 24927296 

free的输出一共有四行,第四行为交换区的信息,分别是交换的总量(total),使用量(used)和有多少空闲的交换区(free),这个比较清楚,不说太多。

free输出地第二行和第三行是比较让人迷惑的。这两行都是说明内存使用情况的。第一列是总量(total),第二列是使用量(used),第三列是可用量(free)。

第一行的输出时从操作系统(OS)来看的。也就是说,从OS的角度来看,计算机上一共有:

24677460KB(缺省时free的单位为KB)物理内存,即FO[2][1]; 在这些物理内存中有23276064KB(即FO[2][2])被使用了; 还用1401396KB(即FO[2][3])是可用的;

这里得到第一个等式:

FO[2][1] = FO[2][2] + FO[2][3]

FO[2][4]表示被几个进程共享的内存的,现在已经deprecated,其值总是0(当然在一些系统上也可能不是0,主要取决于free命令是怎么实现的)。

FO[2][5]表示被OS buffer住的内存。FO[2][6]表示被OS cache的内存。在有些时候buffer和cache这两个词经常混用。不过在一些比较低层的软件里是要区分这两个词的,看老外的洋文:

A buffer is something that has yet to be "written" to disk. A cache is something that has been "read" from the disk and stored for later use. 

也就是说buffer是用于存放要输出到disk(块设备)的数据的,而cache是存放从disk上读出的数据。这二者是为了提高IO性能的,并由OS管理。

Linux和其他成熟的操作系统(例如windows),为了提高IO read的性能,总是要多cache一些数据,这也就是为什么FO[2][6](cached memory)比较大,而FO[2][3]比较小的原因。我们可以做一个简单的测试:

释放掉被系统cache占用的数据:

echo 3>/proc/sys/vm/drop_caches 

  1. 读一个大文件,并记录时间;
  2. 关闭该文件;
  3. 重读这个大文件,并记录时间;

第二次读应该比第一次快很多。原来我做过一个BerkeleyDB的读操作,大概要读5G的文件,几千万条记录。在我的环境上,第二次读比第一次大概可以快9倍左右。

free输出的第二行是从一个应用程序的角度看系统内存的使用情况。

  • 对于FO[3][2],即-buffers/cache,表示一个应用程序认为系统被用掉多少内存;
  • 对于FO[3][3],即+buffers/cache,表示一个应用程序认为系统还有多少内存;

因为被系统cache和buffer占用的内存可以被快速回收,所以通常FO[3][3]比FO[2][3]会大很多。

这里还用两个等式:

FO[3][2] = FO[2][2] - FO[2][5] - FO[2][6] FO[3][3] = FO[2][3] + FO[2][5] + FO[2][6] 

这二者都不难理解。

free命令由procps.*.rpm提供(在Redhat系列的OS上)。free命令的所有输出值都是从/proc/meminfo中读出的。

在系统上可能有meminfo(2)这个函数,它就是为了解析/proc/meminfo的。procps这个包自己实现了meminfo()这个函数。可以下载一个procps的tar包看看具体实现,现在最新版式3.2.8。

文章出处:

http://www.cnblogs.com/coldplayerest/archive/2010/02/20/1669949.html

free命令可以显示Linux系统中空闲的、已用的物理内存及swap内存,及被内核使用的buffer。在Linux系统监控的工具中,free命令是最经常使用的命令之一。

1.命令格式:

free [参数]

2.命令功能:

free 命令显示系统使用和空闲的内存情况,包括物理内存、交互区内存(swap)和内核缓冲区内存。共享内存将被忽略

3.命令参数:

-b  以Byte为单位显示内存使用情况。 

-k  以KB为单位显示内存使用情况。 

-m  以MB为单位显示内存使用情况。

-g   以GB为单位显示内存使用情况。 

-o  不显示缓冲区调节列。 

-s<间隔秒数>  持续观察内存使用状况。 

-t  显示内存总和列。 

-V  显示版本信息。 

4.使用实例:

实例1:显示内存使用情况

命令:

free

free -g

free –m

输出:

[root@SF1150 service]# free

             total       used       free     shared    buffers     cached

Mem:      32940112   30841684    2098428          0    4545340   11363424

-/+ buffers/cache:   14932920   18007192

Swap:     32764556    1944984   30819572

[root@SF1150 service]# free -g

             total       used       free     shared    buffers     cached

Mem:            31         29          2          0          4         10

-/+ buffers/cache:         14         17

Swap:           31          1         29

[root@SF1150 service]# free -m

             total       used       free     shared    buffers     cached

Mem:         32168      30119       2048          0       4438      11097

-/+ buffers/cache:      14583      17584

Swap:        31996       1899      30097

说明:

下面是对这些数值的解释:

total:总计物理内存的大小。

used:已使用多大。

free:可用有多少。

Shared:多个进程共享的内存总额。

Buffers/cached:磁盘缓存的大小。

第三行(-/+ buffers/cached):

used:已使用多大。

free:可用有多少。

第四行是交换分区SWAP的,也就是我们通常所说的虚拟内存。

区别:第二行(mem)的used/free与第三行(-/+ buffers/cache) used/free的区别。 这两个的区别在于使用的角度来看,第一行是从OS的角度来看,因为对于OS,buffers/cached 都是属于被使用,所以他的可用内存是2098428KB,已用内存是30841684KB,其中包括,内核(OS)使用+Application(X, oracle,etc)使用的+buffers+cached.

第三行所指的是从应用程序角度来看,对于应用程序来说,buffers/cached 是等于可用的,因为buffer/cached是为了提高文件读取的性能,当应用程序需在用到内存的时候,buffer/cached会很快地被回收。

所以从应用程序的角度来说,可用内存=系统free memory+buffers+cached。

如本机情况的可用内存为:

18007156=2098428KB+4545340KB+11363424KB

接下来解释什么时候内存会被交换,以及按什么方交换。 

当可用内存少于额定值的时候,就会开会进行交换.如何看额定值: 

命令:

cat /proc/meminfo 

输出:

[root@SF1150 service]# cat /proc/meminfo

MemTotal:     32940112 kB

MemFree:       2096700 kB

Buffers:       4545340 kB

Cached:       11364056 kB

SwapCached:    1896080 kB

Active:       22739776 kB

Inactive:      7427836 kB

HighTotal:           kB

HighFree:            kB

LowTotal:     32940112 kB

LowFree:       2096700 kB

SwapTotal:    32764556 kB

SwapFree:     30819572 kB

Dirty:             164 kB

Writeback:           kB

AnonPages:    14153592 kB

Mapped:          20748 kB

Slab:           590232 kB

PageTables:      34200 kB

NFS_Unstable:        kB

Bounce:              kB

CommitLimit:  49234612 kB

Committed_AS: 23247544 kB

VmallocTotal: 34359738367 kB

VmallocUsed:    278840 kB

VmallocChunk: 34359459371 kB

HugePages_Total:     0HugePages_Free:      0HugePages_Rsvd:      0Hugepagesize:     2048 kB

交换将通过三个途径来减少系统中使用的物理页面的个数:  

1.减少缓冲与页面cache的大小, 

2.将系统V类型的内存页面交换出去,  

3.换出或者丢弃页面。(Application 占用的内存页,也就是物理内存不足)。 

事实上,少量地使用swap是不是影响到系统性能的。

那buffers和cached都是缓存,两者有什么区别呢?

为了提高磁盘存取效率, Linux做了一些精心的设计, 除了对dentry进行缓存(用于VFS,加速文件路径名到inode的转换), 还采取了两种主要Cache方式:Buffer Cache和Page Cache。前者针对磁盘块的读写,后者针对文件inode的读写。这些Cache有效缩短了 I/O系统调用(比如read,write,getdents)的时间。

磁盘的操作有逻辑级(文件系统)和物理级(磁盘块),这两种Cache就是分别缓存逻辑和物理级数据的。

Page cache实际上是针对文件系统的,是文件的缓存,在文件层面上的数据会缓存到page cache。文件的逻辑层需要映射到实际的物理磁盘,这种映射关系由文件系统来完成。当page cache的数据需要刷新时,page cache中的数据交给buffer cache,因为Buffer Cache就是缓存磁盘块的。但是这种处理在2.6版本的内核之后就变的很简单了,没有真正意义上的cache操作。

Buffer cache是针对磁盘块的缓存,也就是在没有文件系统的情况下,直接对磁盘进行操作的数据会缓存到buffer cache中,例如,文件系统的元数据都会缓存到buffer cache中。

简单说来,page cache用来缓存文件数据,buffer cache用来缓存磁盘数据。在有文件系统的情况下,对文件操作,那么数据会缓存到page cache,如果直接采用dd等工具对磁盘进行读写,那么数据会缓存到buffer cache。

所以我们看linux,只要不用swap的交换空间,就不用担心自己的内存太少.如果常常swap用很多,可能你就要考虑加物理内存了.这也是linux看内存是否够用的标准.

如果是应用服务器的话,一般只看第二行,+buffers/cache,即对应用程序来说free的内存太少了,也是该考虑优化程序或加内存了。

实例2:以总和的形式显示内存的使用信息

命令:

  free -t 

输出:

[root@SF1150 service]#  free -t 

             total       used       free     shared    buffers     cached

Mem:      32940112   30845024    2095088          0    4545340   11364324

-/+ buffers/cache:   14935360   18004752Swap:     32764556    1944984   30819572Total:    65704668   32790008   32914660[root@SF1150 service]#

说明:

实例3:周期性的查询内存使用信息

命令:

free -s 10

输出:

[root@SF1150 service]#  free -s 10

             total       used       free     shared    buffers     cached

Mem:      32940112   30844528    2095584          0    4545340   11364380

-/+ buffers/cache:   14934808   18005304Swap:     32764556    1944984   30819572

             total       used       free     shared    buffers     cached

Mem:      32940112   30843932    2096180          0    4545340   11364388

-/+ buffers/cache:   14934204   18005908Swap:     32764556    1944984   30819572

说明:

每10s 执行一次命令

https://www.cnblogs.com/peida/archive/2012/12/25/2831814.html