分类 Linux 下的文章

Docker学习笔记一

docker基本概念

  • images: 镜像,简单理解就是装系统的ISO镜像,images只是binary,是“死”的,加载起来后可以运行
  • container: 容器,由镜像创建的运行实例,就和普通的linux服务一样,可以创建、start、stop、删除。但是每个容器都是彼此独立的,互相不干扰

docker安装

  • 环境: CentOS 6.x
$ sudo yum install docker-io
  • 环境: CentOS 7.x
$ sudo yum install docker
  • 环境: CentOS 5.x

目前尚未发现yum安装,网上关于docker编译安装的资料也不多

- 阅读剩余部分 -

Linux特殊字符(M-BM-)

有时候linux的命令贴到OneNote里后,再copy出来run就不行了,原因是有特殊字符。

$ cat /tmp/run.sh
echo hello

$ cat -A /tmp/run.sh
echoM-BM- hello$

这个"M-BM-"就是不可见的特殊字符,怀疑是windows的软件整的,需要要替换了就行

$ sed 's/\xc2\xa0/ /g' -i /tmp/run.sh

$ cat -A /tmp/run.sh
echo hello$

理解Linux文件系统挂载参数noatime nodiratime

很多线上服务器为了提供文件系统IO性能,会在挂载文件系统的时候指定“noatime,nodiratime”参数,意味着当访问一个文件和目录的时候,access time都不会更新。但是如果未指定上面的参数,atime则会更新。那么具体差异在哪里?

未指定 noatime,nodiratime

$ touch test ; stat test ;
...
Access: 2015-04-04 00:37:23.507135507 +0800
Modify: 2015-04-04 00:37:23.507135507 +0800
Change: 2015-04-04 00:37:23.507135507 +0800

$ echo hello >> test ; stat test;
...
Access: 2015-04-04 00:37:23.507135507 +0800
Modify: 2015-04-04 00:37:38.018430637 +0800
Change: 2015-04-04 00:37:38.018430637 +0800

$ cat test ;stat test
...
Access: 2015-04-04 00:38:02.916135510 +0800
Modify: 2015-04-04 00:37:38.018430637 +0800
Change: 2015-04-04 00:37:38.018430637 +0800

可以看出未指定"noatime,nodiratime"的情况下

  1. read文件的时候会导致atime更新,不会导致mtime和ctime更新
  2. write文件只会导致mtime和ctime更新,不会导致atime更新。

指定 noatime,nodiratime

$touch test ; stat test ; 
...
Access: 2015-04-04 00:28:28.680135484 +0800
Modify: 2015-04-04 00:28:28.680135484 +0800
Change: 2015-04-04 00:28:28.680135484 +0800

$ sleep 10 ; echo hello >> test ; stat test;
...
Access: 2015-04-04 00:28:28.680135484 +0800
Modify: 2015-04-04 00:28:38.682727983 +0800
Change: 2015-04-04 00:28:38.682727983 +0800

$ cat test ;stat test
...
Access: 2015-04-04 00:28:28.680135484 +0800
Modify: 2015-04-04 00:28:38.682727983 +0800
Change: 2015-04-04 00:28:38.682727983 +0800

可以看出指定"noatime,nodiratime"的情况下

  1. read文件的时候不会导致atime、mtime、ctime改变
  2. write文件只会导致mtime和ctime更新,不会导致atime更新。

实际应用场景

在平日里经常有删除文件的需求,大概如下

删除过去N天内都未访问过的文件或者目录(删除N天前访问过的文件)

$ #注意这条命令很危险! 
$ find /home/fire/ -atime +N -exec rm -rf {} \;

假设 /home/fire 目录是一周之前创建的,那么对于这条命令有两个执行结果

$ #注意这条命令很危险! 
$ find /home/fire/ -atime +7 -exec rm -rf {} \;
  • 指定"noatime":find的时候发现 /home/fire 是7天之前创建的,立马就会删除整个目录。而且还会报错"find: /home/fire: No such file or directory",原因就是第一个rm -rf /home/fire 之后 find失败了。这种是很危险的!原因是会误删除文件。
  • 未指定"noatime":那就得看情况,如果/home/fire过去7天没有被访问过,那么就和情况一一样,直接删除。如果过去7天内,该目录有人访问过,atime肯定是7天之内,那么就会遍历下面的目录,依次按照之前逻辑。但是遍历过程会更改目录的atime。

看了上面的例子会发现find去删除目录的时候变得好复杂,而且一定要小心。所以find删除更适用于删除文件,不要删除目录。

删除N天内未被访问过的文件
$ find /home/fire/ -atime +N -type f -exec rm -f {} \;

Linux的overcommit配置

Linux对大部分申请内存的请求都回复"yes",以便能跑更多更大的程序。因为申请内存后,并不会马上使用内存。这种技术叫做Overcommit。

当内存不足时,会发生OOM killer(OOM=out-of-memory)。它会选择杀死一些进程(用户态进程,不是内核线程),以便释放内存。

Overcommit和下面两个vm的配置有关系。

vm.overcommit_ratio 
vm.overcommit_memory

- 阅读剩余部分 -

Linux时间转化(date和unix时间)笔记

时间相关参数列表

%H : 小时(00..23)
%I : 小时(01..12)
%k : 小时(0..23)
%l : 小时(1..12)
%M : 分钟(00..59)
%p : 显示本地 AM 或 PM
%r : 直接显示时间 (12 小时制,格式为 hh:mm:ss [AP]M)
%s : 从 1970 年 1 月 1 日 00:00:00 UTC 到目前为止的秒数
%S : 秒(00..61)
%T : 直接显示时间 (24 小时制)
%X : 相当于 %H:%M:%S
%Z : 显示时区 %a : 星期几 (Sun..Sat)
%A : 星期几 (Sunday..Saturday)
%b : 月份 (Jan..Dec)
%B : 月份 (January..December)
%c : 直接显示日期与时间
%d : 日 (01..31)
%D : 直接显示日期 (mm/dd/yy)
%h : 同 %b
%j : 一年中的第几天 (001..366)
%m : 月份 (01..12)
%U : 一年中的第几周 (00..53) (以 Sunday 为一周的第一天的情形)
%w : 一周中的第几天 (0..6)
%W : 一年中的第几周 (00..53) (以 Monday 为一周的第一天的情形)
%x : 直接显示日期 (mm/dd/yy)
%y : 年份的最后两位数字 (00.99)
%Y : 完整年份 (0000..9999)

- 阅读剩余部分 -

ssh利用key登录

ssh登录的时候,如果key不通,则会提示输入密码。

$ ssh -l firefoxbug www.firefoxbug.com
firefoxbug@www.firefoxbug.com's password:

当ssh key不通时候直接如何直接报错?ssh的时候可以指定BatchMode=yes

$ ssh -o BatchMode=yes -l firefoxbug www.firefoxbug.com
Permission denied (publickey,gssapi-with-mic,password).

Linux 作业控制

Linux 作业控制

作业控制指的是,在一个登录会话里,允许用户在不通进程组(或者jobs)之间的切换。

作业控制的概念

交互式shell最基础的功能是从用户终端读取命令,然后生成进程来执行这些命令。主要是通过fork和exec来结合实现。

进程组

一个单独的命令就能运行一个进程,但是往往是一条命令存在多个进程,比如管道的使用,往往就会引入多个进程。

这些来自于同一条命令的进程们被称作进程组,所谓进程组,有一个特性就是我们能够一次性对它们操作。比如,终端输入Ctrl+C,这时候会产生SIGINT信号,从而终止前端进程组内的所有进程。看下面例子

- 阅读剩余部分 -

tmux配置

参考 http://www.opstool.com/article/253

配置文件

$ vim ~/.tmux.conf

#保存在个人home目录下 .tmux.conf
#取消默认的设定键
unbind C-b
unbind &
unbind %
unbind w
unbind '"'
 
#Escape键
set -g prefix C-a
 
#解决bash ctrl a冲突问题
bind a send-prefix
 
#窗口切分快捷键
bind \ split-window -h
bind - split-window -v
bind K confirm-before -p "kill-window #W? (y/n)" kill-window
bind '"' choose-window
 
#Pane之间切换的快捷键
bind h select-pane -L
bind j select-pane -D
bind k select-pane -U
bind l select-pane -R
 
#Pane大小调整快捷键
bind < resize-pane -L 5
bind > resize-pane -R 5
bind _ resize-pane -D 5
bind + resize-pane -U 5
 
#设置window属性
setw -g window-status-current-bg red
setw -g window-status-current-fg white
setw -g window-status-current-attr bright
setw -g window-status-attr bright
setw -g window-status-format '#[fg=cyan,dim]#I#[fg=blue] #[default]#W#[fg=grey,dim]'
setw -g window-status-current-format '#[fg=cyan,dim]#I#[fg=blue] #[default]#W#[fg=grey,dim]'
 
#设置状态栏
set -g status-utf8 on
set -g status-left ""
set -g status-left-length 0
set -g status-interval 2
set -g status-fg white
set -g status-bg blue
set -g status-right "%Y/%m/%d %H:%M"
set -g default-terminal "screen"
 
#设置滚屏,屏幕历史长度
set -g history-limit 10000
set -g terminal-overrides 'xterm*:smcup@:rmcup@'
setw -g mode-keys vi
setw -g utf8 on
 
#其他设置
set -sg escape-time 0

常用快捷键

1. Ctrl+a  按 [ 进入 tmux屏幕拷贝模式
2. 然后按空格键开始复制
3. 使用类似vim的上下左右键方式进行选中
4. 按enter退出复制模式
5. Ctrl+a  按 ] 进行粘贴
6. Ctrl+a+c 新建窗口

会话控制

查看历史会话
$ tmux ls 
9: 3 windows (created Wed Aug  6 11:13:54 2014) [156x36]

切换到历史会话
$tmux att -d -t 9

Linux rsync删除大量小文件

如果某个目录下存在几十万个小文件,用普通的rm删除起来非常慢,这时候可以用rsync来删除,下面是两种方式删除的性能测试。

测试场景

在test下生成30万个文件,内容大都是十来个字节。

rm删除大量小文件

$ # 如果直接用rm -f test/*,rm会提示参数太多,报错
$ time rm -rf test
real    0m18.046s
user    0m0.077s
sys 0m3.291s

rsync删除大量小文件

$ time rsync --delete-before -a -H --progress --stats /tmp/test/ test/

real    0m35.437s
user    0m1.662s
sys 0m6.076s

选项说明:
–delete-before 接收者在传输之前进行删除操作
–progress 在传输时显示传输过程
-a 归档模式,表示以递归方式传输文件,并保持所有文件属性
-H 保持硬连接的文件
-v 详细输出模式
–stats 给出某些文件的传输状态

如果不显示传输过程,速度更快

$ time rsync --delete-before -a -H --stats /tmp/test/ test/
real    0m6.420s
user    0m0.546s
sys 0m3.678s

总结

在存在大量小文件的时候,选择rsync删除(不指定输出详细信息)效率确实比rm高很多。

深入理解yum工作原理

前言

在前面一篇rpm包制作描述了rpm的打包过程,这篇文章主要讲述yum的工作原理。

yum 运行原理

yum的工作需要两部分来合作,一部分是yum服务器,还有就是client的yum工具。下面分别介绍两部分工作原理。

  • yum服务器

    所有要发行的rpm包都放在yum服务器上以提供别人来下载,rpm包根据kernel的版本号,cpu的版本号分别编译发布。yum服务器只要提供简单的下载就可以了,ftp或者httpd的形式都可以。yum服务器有一个最重要的环节就是整理出每个rpm包的基本信息,包括rpm包对应的版本号,conf文件,binary信息,以及很关键的依赖信息。在yum服务器上提供了createrepo工具,用于把rpm包的基本概要信息做成一张"清单",这张"清单""就是描述每个rpm包的spec文件中信息。

  • yum client端

    client每次调用yum install或者search的时候,都会去解析/etc/yum.repos.d下面所有以.repo结尾的配置文件,这些配置文件指定了yum服务器的地址。yum会定期去"更新"yum服务器上的rpm包"清单",然后把"清单"下载保存到yum自己的cache里面,根据/etc/yum.conf里配置(默认是在/var/cache/yum下面),每次调用yum装包的时候都会去这个cache目录下去找"清单",根据"清单"里的rpm包描述从而来确定安装包的名字,版本号,所需要的依赖包等,然后再去yum服务器下载rpm包安装。(前提是不存在rpm包的cache)

- 阅读剩余部分 -

rpm包制作

rpm包命名规范

对于rpm包的命名符合如下规范。

%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}.rpm

NAME: rpm包名字
VERSION: rpm包版本号(主版本号.次版本号.测试号)
RELEASE: rpm包编译发布次数(第几次编译发布)
ARCH: cpu架构(比如i386和x86_64,i386兼容x86_64,noarch的代表一些列脚本)

比如nginx-1.4.0-24.x86.rpm,nginx-1.4.0-24.x86_64.rpm

实现目标

有一个test.py,去读取当前conf目录下的test.conf文件中的版本号,然后1秒打印一次日志到/tmp/test_rpm.log

---------test.py------------
#!/usr/bin/python

print "Hello World"
    
--------conf/test.conf------------
Version=0.1

再看下路径结构

.
|-- conf
|   `-- test.conf
`-- test.py

制作成一个rpm包,安装之后出现这样的目录结构

/usr/local/rpm_test
.
|-- conf
|   `-- test.conf
`-- test.py

基础环境

制作rpm包是通过rpmbuild来生成的。

安装rpmbuild工具
$ sudo yum install rpm-build

$ rpmbuild --version
RPM version 4.4.2.3

建立独立的打包目录
$ cat >${HOME}/.rpmmacros << EOF
%_topdir $HOME/rpmbuild
EOF
$ mkdir ${HOME}/rpmbuild/
$ cd ${HOME}/rpmbuild/
$ mkdir BUILD  RPMS  SOURCES  SPECS  SRPMS

1. 把要打包的配置文件放到 ${HOME}/rpmbuild/SOURCES/ 下面
2. 在${HOME}/rpmbuild/SPEC下面建立一个test.spec文件,建立好后目录如下
.
|-- BUILD
|-- RPMS
|-- SOURCES
|   |-- test.conf
|   `-- test.py
|-- SPECS
|   `-- test.spec
`-- SRPMS

编写spec文件

spec文件是打rpm包的关键环节,spec文件里指定了rpm包的基本信息,安装好后的环境

Name:         rpm_test
Version:      0.0.1
Release:      3
Buildarch:    noarch
Group:        tools
Summary:      rpm_test
License:      Commercial
BuildArch:     noarch
BuildRoot:    %{_buildrootdir}
Prefix:       /usr/local/rpm_test
AutoReqProv:  no

%define _build_name_fmt     %%{NAME}-%%{VERSION}-%%{RELEASE}-%%{ARCH}.rpm
#编译需要的依赖
#BuildRequires: gcc,make,gcc-c++,pcre-devel
#安装运行需要的依赖
Requires:     python >= 2.4.3

Source0:           test.py
Source1:           test.conf

#description 软件详细描述,可多行
%description
rpm_test by Wanghua

#解压源文件
%prep
#%setup -q

#build 开始编译软件,如make
%build

#install 开始安装软件,如make install
%install
rm -rf ${buildroot}

#建立目录
install -p -d -m 0755 %{buildroot}%{prefix}
install -p -d -m 0755 %{buildroot}%{prefix}/conf

#copy文件
install -p -m 0755 %{SOURCE0} %{buildroot}%{prefix}
install -p -m 0755 %{SOURCE1} %{buildroot}%{prefix}/conf

%files
%defattr(-,root,root,-)
%{prefix}/conf
%{prefix}/test.py

#%config(noreplace) %{prefix}/conf/test.conf

#封装rpm包后清空虚拟根目录
%clean
rm -rf %{buildroot}
 
#rpm安装前执行命令,$1==1其中1代表安装,0代表卸载
%pre
if [ $1==1 ]; then
   echo "Now start install rpm package."
fi
 
#rpm包安装后执行命令
%post
if [ $1==1 ]; then
   echo "/sbin/chkconfig --add rpm_test"
fi

#rpm包卸载前
%postun
rm -rf %{prefix}

#rpm包卸载后执行命令
%preun
if [ $1==0 ]; then
    echo "rpm pkg has been remove"
    echo "/sbin/chkconfig --del rpm_test"
fi

%changelog
* Tue Jul 17 2014 firefoxbug
+ rpm test

生成rpm包

$ rpmbuild -bb test.spec

.
|-- BUILD
|-- RPMS
|   `-- noarch
|       `-- rpm_test-0.1-20140716.noarch.rpm
|-- SOURCES
|   |-- test.conf
|   `-- test.py
|-- SPECS
|   `-- test.spec
`-- SRPMS

查看rpm包相关信息

查看安装信息(已经安装)
$ rpm -ql rpm_test
/usr/local/rpm_test/conf
/usr/local/rpm_test/conf/test.conf
/usr/local/rpm_test/test.py

查看rpm包
$rpm -qlp rpm_test-0.1-20140716.noarch.rpm
/usr/local/rpm_test/conf
/usr/local/rpm_test/conf/test.conf
/usr/local/rpm_test/test.py

查看rpm包安装前后执行的脚本,其实就是spec文件的几个部分

$ rpm -qpl --scripts rpm_test-0.1-20140716.noarch.rpm
preinstall scriptlet (using /bin/sh):
if [ $1==1 ]; then
   echo "Now start install rpm package."
fi

#rpm包安装后执行命令
postinstall scriptlet (using /bin/sh):
if [ $1==1 ]; then
   echo "/sbin/chkconfig --add rpm_test"
fi

#rpm包卸载前
preuninstall scriptlet (using /bin/sh):
if [ $1==0 ]; then
    echo "rpm pkg has been remove"
    echo "/sbin/chkconfig --del rpm_test"
fi
postuninstall scriptlet (using /bin/sh):
rm -rf /usr/local/rpm_test

#rpm包卸载后执行命令
/usr/local/rpm_test/conf
/usr/local/rpm_test/conf/test.conf
/usr/local/rpm_test/test.py

rpm包指定格式输出

$ rpm -qa --queryformat  "%{NAME}_|-%{VERSION}_|-%{RELEASE}_|-%{ARCH}\n"
python-simplejson_|-2.0.3_|-3.el5_|-x86_64

根据文件查询所在的rpmbao

$rpm -qf /path/nginx.conf

参考文档

rpm包制作 http://my.oschina.net/sylee/blog/167640

RPM包制作原理 http://my.oschina.net/guol/blog/182310

《Linux System and Performance Monitoring》CPU篇

前言: 原文《Linux System and Performance Monitoring》,本文尝试翻译文章中的CPU篇,并且省略了一些地方,也在一些地方加了自己的理解。

转载请注明出处: http://www.firefoxbug.com/?p=2760

Introducing the CPU

The utilization of a CPU is largely dependent on what resource is attempting to access it. The kernel has a scheduler that is responsible for scheduling two kinds of resources: threads (single or multi) and interrupts. The scheduler gives different priorities to the different resources. The following list outlines the priorities from highest to lowest:

  • Interrupts – Devices tell the kernel that they are done processing. For example, a NIC delivers a packet or a hard drive provides an IO request
  • Kernel (System) Processes – All kernel processing is handled at this level of priority.
  • User Processes – This space is often referred to as “userland”. All software applications run in the user space. This space has the lowest priority in the kernel scheduling mechanism.

In order to understand how the kernel manages these different resources, a few key concepts need to be introduced. The following sections introduce context switches, run queues, and utilization.

- 阅读剩余部分 -

Nginx Pugre返回404

之前一直都是认为purge返回404的原因就是因为所请求的资源并没有被cache,今天在测试过程中无意发现这点认识有错误。

基础环境

  • 确保编译Nginx的时候添加了proxy_cache和purge模块
  • 测试域名: www.cdnhub.org
  • 测试URL: http://www.cdnhub.org/1.txt
  • 资源路径: echo "firefoxbug" > /var/www/cdnhub/1.txt
  • Cache文件安装域名存放,在/home/cache下面
  • 具体查看Nginx配置文件

- 阅读剩余部分 -

通过Nginx配置文件抵御攻击

前言

大家好,我们是OpenCDN团队的Twwy。这次我们来讲讲如何通过简单的配置文件来实现nginx防御攻击的效果。

其实很多时候,各种防攻击的思路我们都明白,比如限制IP啊,过滤攻击字符串啊,识别攻击指纹啦。可是要如何去实现它呢?用守护脚本吗?用PHP在外面包一层过滤?还是直接加防火墙吗?这些都是防御手段。不过本文将要介绍的是直接通过nginx的普通模块和配置文件的组合来达到一定的防御效果。

验证浏览器行为

- 阅读剩余部分 -

针对ddos攻击实用命令

查看连接数汇总

# netstat -n|awk '/^tcp/{++S[$NF]}END{for (key in S) print key,S[key]}'
LAST_ACK 10
SYN_RECV 15
ESTABLISHED 462
FIN_WAIT1 2
FIN_WAIT2 1
TIME_WAIT 989

### 查看ESTABLISHED连接数

# netstat -na | grep ESTABLISHED  | awk '{print$5}' | awk -F : '{print$1}' | sort | uniq -c | sort -rn

### 查看TIME_WAIT连接数

# netstat -na | grep TIME_WAIT  | awk '{print$5}' | awk -F : '{print$1}' | sort | uniq -c | sort -rn

### TIME_WAIT连接数过高

#### TIME_WAIT原因:

TCP/IP协议设计中主动关闭的一方在发送最后一个 ack 后就会进入 TIME_WAIT 状态 停留2MSL(max segment lifetime)时间

#### 解决

vim /etc/sysctl.conf

net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1 开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。
net.ipv4.tcp_fin_timeout = 30 修改系統默认的 TIMEOUT 时间

注意:改变以上系统配置可能会引发未知的TCP错误,建议不要修改。

### iptables限制某个IP访问80

iptables -A INPUT -p tcp -d 192.168.1.1 --dport 80 -j DROP

增加新域名

因为想把firefoxbug.net换成firefoxbug.com,就是之前的PR转不过来,于是网上看了下seo的,做了下面几件事。 1. 先用301跳转,把老的域名跳转到新的域名。注意不要用302跳转,因为存在URL劫持的问题可能不会被google收录。 2. 在数据库里把wordpress旧的登录信息修改成新的

UPDATE wp_options SET option_value = replace(option_value, 'http://www.firefoxbug.net', 'http://www.firefoxbug.com') WHERE option_name = 'home' OR option_name ='siteurl' ;
UPDATE wp_posts SET post_content = replace( post_content, 'http://www.firefoxbug.net' , 'http://www.firefoxbug.com') ;
UPDATE wp_posts SET guid = replace( guid, 'http://www.firefoxbug.net' , 'http://www.firefoxbug.com') ;
UPDATE wp_comments SET comment_author_url = REPLACE( comment_author_url, 'http://www.firefoxbug.net', 'http://www.firefoxbug.com');

enjoy http://www.firefoxbug.com/

LinuxIO模型概述

前言

一个socket进程进行一次read可以分成两个阶段,等待数据是否准备好,以及数据从内核copy到用户空间。 我们举个例子,肚子饿了要去小吃街吃拉面,在我们正式开始吃面之前需要1.先等拉面师傅做好面,2.然后把做好的面放到我们的桌子上。

- 阅读剩余部分 -

Hadoop Volume 配置

volume的配置就是在 hdfs-site.xml 下

<property>
    <name>dfs.datanode.data.dir</name>
    <value>/sda1,/sda/disk1</value>
</property>

我今早是新加了一个volume,就是(所有机器都是)

drwx------ 4 hadoop hadoop  4096 Apr  2 13:33 /sda1
drwx------ 4 admin admin  4096 Apr  2 13:33 /sda/disk1

- 阅读剩余部分 -