memcached 监控工具mctop 安装

mctop 与 top 相似,主要用于监视 Memcache 的流量,包括 key 的调用次数、对象存储大小、每秒的请求数、以及消耗的网络带宽等。

源代码:https://github.com/etsy/mctop

1)安装:

 
[root@memcache2 mctop]# yum install libpcap-devel ruby-devel rubygems git
[root@memcache2 mctop]# gem install ruby-pcap -v '0.7.8'
[root@memcache2 mctop]# gem install bundle 
[root@memcache2 mctop]# gem install rake

[root@memcache2 mctop]# git clone git://github.com/etsy/mctop.git

[root@memcache2 mctop]# cd mctop/
[root@memcache2 mctop]# bundle install
[root@memcache2 mctop]# rake install

2)运行

 
[root@memcache2 mctop]# mctop -h
Usage: mctop [options]
    -i, --interface=NIC              Network interface to sniff (required)
    -p, --port=PORT                  Network port to sniff on (default 11211)
    -d, --discard=THRESH             Discard keys with request/sec rate below THRESH
    -r, --refresh=MS                 Refresh the stats display every MS milliseconds
    -h, --help                       Show usage info

[root@memcache2 mctop]# mctop -i bond0 -p 11211

大致是这个样子:

xinetd出现svn per_source_limit from=的问题

今天机房网络出现问题,好了后发现svn一直连不上。查看日志发现有如下信息:

Aug 16 15:03:53 svnsh xinetd[19280]: EXIT: svn status=0 pid=29949 duration=1(sec)
Aug 16 15:04:27 svnsh xinetd[19280]: FAIL: svn per_source_limit from=112.64.23.235

网上查了一下,per_source_limit from=是xinetd的一个机制:

per_source

Takes an integer or “UNLIMITED” as an argument. This specifies the maximum instances of this service per source IP address. This can also be specified in the defaults section.

instances

determines the number of servers that can be simultaneously active for a service (the default is no limit). The value of this attribute can be either a number or UNLIMITED which means that there is no limit.

改成下面这样就好了,增加instances及instances:
(更多…)

rpmbuild报error: Installed (but unpackaged) file(s) found的解决办法

我在打包时出错:

Processing files: php-debuginfo-5.3.10-1.x86_64
Checking for unpackaged file(s): /usr/lib/rpm/check-files /root/rpmbuild/BUILDROOT/php-5.3.10-1.x86_64
error: Installed (but unpackaged) file(s) found:
   /.channels/.alias/pear.txt
   /.channels/.alias/pecl.txt
   /.channels/.alias/phpdocs.txt
   /.channels/__uri.reg
   /.channels/doc.php.net.reg
   /.channels/pear.php.net.reg
   /.channels/pecl.php.net.reg
   /.depdb
   /.depdblock
   /.filemap
   /.lock

RPM build errors:
    Installed (but unpackaged) file(s) found:
   /.channels/.alias/pear.txt
   /.channels/.alias/pecl.txt
   /.channels/.alias/phpdocs.txt
   /.channels/__uri.reg
   /.channels/doc.php.net.reg
   /.channels/pear.php.net.reg
   /.channels/pecl.php.net.reg
   /.depdb
   /.depdblock
   /.filemap
   /.lock

网上查询,解决办法有:

1. 

在/usr/lib/rpm/macros文件中有一个定义:

%_unpackaged_files_terminate_build 1

把1改为0只警告

2. 

make install后删除这些文件:

rm -rf %{buildroot}
make INSTALL_ROOT=%{buildroot} install

rm -rf %{buildroot}/.channels/.alias/pear.txt %{buildroot}/.channels/.alias/pecl.txt %{buildroot}/.channels/__uri.reg %{buildroot}/.channels/pear.php.net.reg %{buildroot}/.channels/pecl.php.net.reg %{buildroot}/.depdb %{buildroot}/.depdblock %{buildroot}/.filemap %{buildroot}/.lock 

3.

把这些文件加进去

%files

%dir %{_prefix}/.channels

%dir %{_prefix}/.channels/.alias/

%{_prefix}/.channels/.alias/pear.txt

rpmbuild在centos 5与centos 6用法的异同(转)

之前是在centos5上对软件进行rpm打包,今天需要在centos 6上打包,发现File not found: /root/rpmbuild/BUILDROOT/…的错误,看是centos 6中的rpmbuild topdir已经改变,为了能兼容centos 5的spec文件,需要对topdir进行修改:

打开/usr/lib/rpm/macros文件:

%_topdir                %{getenv:HOME}/rpmbuild

更改为:

%_topdir                %{_usrsrc}/redhat

另外还需要定义buildroot

在spec文件中的make install后面加上DESTDIR=%{buildroot},即:

make install DESTDIR=%{buildroot}

DESTDIR是Makefile文件中定义的一个安装路径的变量,根据实际情况修改,比如mysqlnginx的是DESTDIR,而php的是INSTALL_ROOT。

转载请注明《文章来源:http://www.centos.bz/2012/06/file-not-found-root-rpmbuild-buildroot/

linux的ulimit各种限制之深入分析

这是一篇非常好的文章,对ulimit的各个限制参数讲得非常透彻。原文链接:http://home.lupaworld.com/home-space-uid-56821-do-blog-id-232810.html

一般可以通过ulimit命令或编辑/etc/security/limits.conf重新加载的方式使之生效

通过ulimit比较直接,但只在当前的session有效,limits.conf中可以根据用户和限制项使用户在下次登录中生效.

对于limits.conf的设定是通过pam_limits.so的加载生效的,比如/etc/pam.d/sshd,这样通过ssh登录时会加载limit.
又或者在/etc/pam.d/login加载生效.

下面将对各种限制进行分析

core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 20 a
file size               (blocks, -f) unlimited a
pending signals                 (-i) 16382
max locked memory       (kbytes, -l) 64 a
max memory size         (kbytes, -m) unlimited a
open files                      (-n) 1024 a
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) unlimited
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

一)限制进程产生的文件大小(file size)

先来说说ulimit的硬限制和软限制
硬限制用-H参数,软限制用-S参数.
ulimit -a看到的是软限制,通过ulimit -a -H可以看到硬限制.
如果ulimit不限定使用-H或-S,此时它会同时把两类限制都改掉的.
软限制可以限制用户/组对资源的使用,硬限制的作用是控制软限制.
超级用户和普通用户都可以扩大硬限制,但超级用户可以缩小硬限制,普通用户则不能缩小硬限制.
硬限制设定后,设定软限制时只能是小于或等于硬限制.

下面的测试应用于硬限制和软限制.

1)软限制不能超过硬限制
在超级用户下,同时修改硬/软限制,使当前会话只能建100KB的文件
ulimit -f 100

查看当前创建文件大小的硬限制为100KB
ulimit -H -f
100

此时限制当前会话的软限制为1000KB,出现不能修改的报错
ulimit -S -f 1000
-bash: ulimit: file size: cannot modify limit: Invalid argument

2)硬限制不能小于软限制
在超级用户下,用户查看当前的软限制,此时为unlmiited
ulimit -S -f
unlimited

此时修改当前会话创建文件大小的硬限制为1000KB,出现不能修改的报错,说明硬限制不能小于软限制
ulimit -H -f 1000
-bash: ulimit: file size: cannot modify limit: Invalid argument

如果我们把创建文件大小的软限制改为900KB,此后就可以修改它的硬限制了
ulimit -S -f 900
ulimit -H -f 1000

3)普通用户只能缩小硬限制,超级用户可以扩大硬限制

用普通用户进入系统
su – test

查看创建文件大小的硬限制
ulimit -H -f
unlimited

此时可以缩小该硬限制
ulimit -H -f 1000

但不能扩大该硬限制
ulimit -H -f 10000

4)硬限制控制软限制,软限制来限制用户对资源的使用

用软限制限制创建文件的大小为1000KB
ulimit -S -f 1000

用硬限制限制创建文件的大小为2000KB
ulimit -H -f 2000

创建3MB大小的文件
dd if=/dev/zero of=/tmp/test bs=3M count=1
File size limit exceeded

查看/tmp/test的大小为1000KB,说明软限制对资源的控制是起决定性作用的.
ls -lh /tmp/test
-rw-r–r– 1 root root 1000K 2010-10-15 23:04 /tmp/test

file size单位是KB.

二)关于进程优先级的限制(scheduling priority)
这里的优先级指NICE值
这个值只对普通用户起作用,对超级用户不起作用,这个问题是由于CAP_SYS_NICE造成的.
例如调整普通用户可以使用的nice值为-10到20之间.
硬限制nice的限制为-15到20之间.
ulimit -H -e 35

软限制nice的限制为-10到20之间
ulimit -S -e 30

用nice命令,使执行ls的nice值为-10
nice -n -10 ls /tmp
ssh-BossiP2810  ssh-KITFTp2620  ssh-vIQDXV3333

用nice命令,使执行ls的nice值为-11,此时超过了ulimit对nice的软限制,出现了异常.
nice -n -11 ls /tmp
nice: cannot set niceness: Permission denied

三)内存锁定值的限制(max locked memory)
这个值只对普通用户起作用,对超级用户不起作用,这个问题是由于CAP_IPC_LOCK造成的.
linux对内存是分页管理的,这意味着有不需要时,在物理内存的数据会被换到交换区或磁盘上.
有需要时会被交换到物理内存,而将数据锁定到物理内存可以避免数据的换入/换出.
采用锁定内存有两个理由:
1)由于程序设计上需要,比如oracle等软件,就需要将数据锁定到物理内存.
2)主要是安全上的需要,比如用户名和密码等等,被交换到swap或磁盘,有泄密的可能,所以一直将其锁定到物理内存.

锁定内存的动作由mlock()函数来完成
mlock的原型如下:
int mlock(const void *addr,size_t len);

测试程序如下:
#include <stdio.h>
#include <sys/mman.h>

int main(int argc, char* argv[])
{
        int array[2048];

        if (mlock((const void *)array, sizeof(array)) == -1) {
                perror("mlock: ");
                return -1;
        }

        printf("success to lock stack mem at: %p, len=%zdn",
                        array, sizeof(array));

        if (munlock((const void *)array, sizeof(array)) == -1) {
                perror("munlock: ");
                return -1;
        }

        printf("success to unlock stack mem at: %p, len=%zdn",
                        array, sizeof(array));

        return 0;
}

gcc mlock_test.c -o mlock_test

上面这个程序,锁定2KB的数据到物理内存中,我们调整ulimit的max locked memory.
ulimit -H -l 4
ulimit -S -l 1
./mlock_test
mlock: : Cannot allocate memory

我们放大max locked memory的限制到4KB,可以执行上面的程序了.
ulimit -S -l 4
./mlock_test
success to lock stack mem at: 0x7fff1f039500, len=2048
success to unlock stack mem at: 0x7fff1f039500, len=2048

注意:如果调整到3KB也不能执行上面的程序,原因是除了这段代码外,我们还会用其它动态链接库.


四)进程打开文件的限制(open files)

这个值针对所有用户,表示可以在进程中打开的文件数.

例如我们将open files的值改为3
ulimit -n 3

此时打开/etc/passwd文件时失败了.
cat /etc/passwd
-bash: start_pipeline: pgrp pipe: Too many open files
-bash: /bin/cat: Too many open files

五)信号可以被挂起的最大数(pending signals)

这个值针对所有用户,表示可以被挂起/阻塞的最大信号数量

我们用以下的程序进行测试,源程序如下:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

volatile int done = 0;

void handler (int sig)
{
  const char *str = "handled…n";
  write (1, str, strlen(str));
  done = 1;
}

void child(void)
{
  int i;
  for (i = 0; i < 3; i++){
    kill(getppid(), SIGRTMIN);
    printf("child – BANG!n");
  }
  exit (0);
}

int main (int argc, char *argv[])
{
  signal (SIGRTMIN, handler);
  sigset_t newset, oldset;
 
  sigfillset(&newset);
  sigprocmask(SIG_BLOCK, &newset, &oldset);
 
  pid_t pid = fork();
  if (pid == 0)
  child();
 
  printf("parent sleeping n");
 
  int r = sleep(3);
 
  printf("woke up! r=%dn", r);
 
  sigprocmask(SIG_SETMASK, &oldset, NULL);
 
  while (!done){
  };
 
  printf("exitingn");
  exit(0);
}

编译源程序:
gcc test.c -o test

执行程序test,这时子程序发送了三次SIGRTMIN信号,父程序在过3秒后,接收并处理该信号.
./test
parent sleeping
child – BANG!
child – BANG!
child – BANG!
woke up! r=0
handled…
handled…
handled…
exiting

注意:这里有采用的是发送实时信号(SIGRTMIN),如:kill(getppid(), SIGRTMIN);
如果不是实时信号,则只能接收一次.

如果我们将pending signals值改为2,这里将只能保证挂起两个信号,第三个信号将被忽略.如下:
ulimit -i 2
./test
parent sleeping
child – BANG!
child – BANG!
child – BANG!
woke up! r=0
handled…
handled…
exiting

六)可以创建使用POSIX消息队列的最大值,单位为bytes.(POSIX message queues)

我们用下面的程序对POSIX消息队列的限制进行测试,如下:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <mqueue.h>
#include <sys/stat.h>
#include <sys/wait.h>

struct message{
 char mtext[128];
};

int send_msg(int qid, int pri, const char text[])
{
 int r = mq_send(qid, text, strlen(text) + 1,pri);
 if (r == -1){
  perror("mq_send");
 }
 return r;
}

void producer(mqd_t qid)
{
 send_msg(qid, 1, "This is my first message.");
 send_msg(qid, 1, "This is my second message.");

 send_msg(qid, 3, "No more messages.");
}

void consumer(mqd_t qid)
{
 struct mq_attr mattr;
 do{
  u_int pri;
  struct message msg;
  ssize_t len;

  len = mq_receive(qid, (char *)&msg, sizeof(msg), &pri);
  if (len == -1){
   perror("mq_receive");
   break;
  }
  printf("got pri %d ‘%s’ len=%dn", pri, msg.mtext, len);

  int r = mq_getattr(qid, &mattr);
  if (r == -1){
   perror("mq_getattr");
   break;
  }
 }while(mattr.mq_curmsgs);
}

int
main (int argc, char *argv[])
{
 struct mq_attr mattr = {
  .mq_maxmsg = 10,
  .mq_msgsize = sizeof(struct message)
 };

 mqd_t mqid = mq_open("/myq",
    O_CREAT|O_RDWR,
    S_IREAD|S_IWRITE,
    &mattr);
 if (mqid == (mqd_t) -1){
  perror("mq_open");
  exit (1);
 }

 pid_t pid = fork();
 if (pid == 0){
  producer(mqid);
  mq_close(mqid);
  exit(0);
 }
 else
 {
  int status;
  wait(&status);
  consumer(mqid);
  mq_close(mqid);
 }
 mq_unlink("/myq");
 return 0;
}

编译:
gcc test.c -o test

限制POSIX消息队列的最大值为1000个字节
ulimit -q 1000

这里我们执行test程序
./test
mq_open: Cannot allocate memory

程序报告无法分配内存.

用strace来跟踪test的运行过程,在下面一条语句时报错.
mq_open("myq", O_RDWR|O_CREAT, 0600, {mq_maxmsg=10, mq_msgsize=128}) = -1 ENOMEM (Cannot allocate memory)

{mq_maxmsg=10, mq_msgsize=128}即128*10=1280个字节,说明已经超过了1000个字节的POSIX消息队列限制.

我们将POSIX消息队列的最大值调整为1360时,程序可以运行.
ulimit -q 1360
./test
got pri 3 ‘No more messages.’ len=18
got pri 1 ‘This is my first message.’ len=26
got pri 1 ‘This is my second message.’ len=27

七)程序占用CPU的时间,单位是秒(cpu time)

我们用下面的代码对程序占用CPU时间的限制进行测试

源程序如下:
# include <stdio.h>
# include <math.h>

int main (void)

{
  double pi=M_PI;
  double pisqrt;
  long i;

  while(1){
    pisqrt=sqrt(pi);
  }
  return 0;
}

编译:
gcc test.c -o test -lm

运行程序test,程序会一直循环下去,只有通过CTRL+C中断.
./test
^C

用ulimit将程序占用CPU的时间改为2秒,再运行程序.
ulimit -t 2
./test
Killed

程序最后被kill掉了.

八)限制程序实时优先级的范围,只针对普通用户.(real-time priority)

我们用下面的代码对程序实时优先级的范围进行测试

源程序如下:
# include <stdio.h>
int main (void)

{
  int i;
  for (i=0;i<6;i++)
  {
    printf ("%dn",i);
    sleep(1);
  }
  return 0;
}

编译:
gcc test.c -o test

切换到普通用户进行测试
su – ckhitler

用实时优先级20运行test程序
chrt -f 20 ./test
chrt: failed to set pid 0’s policy: Operation not permitted

我们用root将ulimit的实时优先级调整为20.再进行测试.
su – root
ulimit -r 20

切换到普通用户,用实时优先级20运行程序,可以运行这个程序了.
su – ckhitler
chrt -r 20 ./test
0
1
2
3
4
5

以实时优先级50运行程序,还是报错,说明ulimit的限制起了作用.
chrt -r 50 ./test
chrt: failed to set pid 0’s policy: Operation not permitted

九)限制程序可以fork的进程数,只对普通用户有效(max user processes)

我们用下面的代码对程序的fork进程数的范围进行测试

源程序如下:
#include <unistd.h>
#include <stdio.h>
int main(void)
{
  pid_t pid;
  int count=0;
  while (count<3){
    pid=fork();
    count++;
    printf("count= %dn",count);
  }
  return 0;
}

编译:
gcc test.c -o test
count= 1
count= 2
count= 3
count= 2
count= 3
count= 1
count= 3
count= 2
count= 3
count= 3
count= 3
count= 2
count= 3
count= 3

程序fork的进程数成倍的增加,这里是14个进程的输出.除自身外,其它13个进程都是test程序fork出来的.
我们将fork的限定到12,如下:
ulimit -u 12
再次执行test程序,这里只有12个进程的输出.
./test
count= 1
count= 2
count= 3
count= 1
count= 2
count= 3
count= 2
count= 3
count= 3
count= 2
count= 3
count= 3
count= 3

十)限制core文件的大小(core file size)

我们用下面的代码对程序生成core的大小进行测试

源代码:
#include <stdio.h>

static void sub(void);

int main(void)
{
     sub();
     return 0;
}

static void sub(void)
{
     int *p = NULL;
     printf("%d", *p);
}

编译:
gcc -g test.c -o test

运行程序test,出现段错误.
./test
Segmentation fault (core dumped)

如果在当前目录下没有core文件,我们应该调整ulimit对core的大小进行限制,如果core文件大小在这里指定为0,将不会产生core文件.
这里设定core文件大小为10个blocks.注:一个blocks在这里为1024个字节.

ulimit -c 10
再次运行这个程序
./test
Segmentation fault (core dumped)

查看core文件的大小
ls -lh core
-rw——- 1 root root 12K 2011-03-08 13:54 core

我们设定10个blocks应该是10*1024也不是10KB,为什么它是12KB呢,因为它的递增是4KB.
如果调整到14个blocks,我们将最大产生16KB的core文件.

十一)限制进程使用数据段的大小(data seg size)

一般来说这个限制会影响程序调用brk(系统调用)和sbrk(库函数)
调用malloc时,如果发现vm不够了就会用brk去内核申请.

限制可以使用最大为1KB的数据段

ulimit -d 1

用norff打开/etc/passwd文件
nroff /etc/passwd
Segmentation fault

可以用strace来跟踪程序的运行.
strace nroff /etc/passwd

打印出如下的结果,证明程序在分配内存时不够用时,调用brk申请新的内存,而由于ulimit的限制,导致申请失败.
munmap(0x7fc2abf00000, 104420)          = 0
rt_sigprocmask(SIG_BLOCK, NULL, [], 8)  = 0
open("/dev/tty", O_RDWR|O_NONBLOCK)     = 3
close(3)                                = 0
brk(0)                                  = 0xf5b000
brk(0xf5c000)                           = 0xf5b000
brk(0xf5c000)                           = 0xf5b000
brk(0xf5c000)                           = 0xf5b000
— SIGSEGV (Segmentation fault) @ 0 (0) —
+++ killed by SIGSEGV +++
Segmentation fault

我们这里用一个测试程序对data segment的限制进行测试.
源程序如下:
#include <stdio.h>
int main()
{

    int start,end;
    start = sbrk(0);
    (char *)malloc(32*1024);
    end = sbrk(0);
    printf("hello I used %d vmemoryn",end – start);
    return 0;
}

gcc test.c -o test
 ./test
hello I used 0 vmemory

通过ulimit将限制改为170KB
再次运行程序
./test
hello I used 167936 vmemory

十二)限制进程使用堆栈段的大小

我们用ulimit将堆栈段的大小调整为16,即16*1024.
ulimit -s 16

再运行命令:
ls -l /etc/
Segmentation fault (core dumped)

这时用strace跟踪命令的运行过程
strace ls -l /etc/

发现它调用getrlimit,这里的限制是16*1024,不够程序运行时用到的堆栈.
getrlimit(RLIMIT_STACK, {rlim_cur=16*1024, rlim_max=16*1024}) = 0

注:在2.6.32系统上ls -l /etc/并不会出现堆栈不够用的情况,这时可以用expect来触发这个问题.

如:
expect
Tcl_Init failed: out of stack space (infinite loop?)

十三)限制进程使用虚拟内存的大小

我们用ulimit将虚拟内存调整为8192KB
ulimit -v 8192

运行ls
ls
ls: error while loading shared libraries: libc.so.6: failed to map segment from shared object: Cannot allocate memory
ls在加载libc.so.6动态库的时候报了错,提示内存不足.

用strace跟踪ls的运行过程,看到下面的输出,说明在做mmap映射出内存时,出现内存不够用.
mmap(NULL, 3680296, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = -1 ENOMEM (Cannot allocate memory)
close(3)                                = 0
writev(2, [{"ls", 2}, {": ", 2}, {"error while loading shared libra"…, 36}, {": ", 2}, {"libc.so.6", 9}, {": ", 2}, {"failed to map segment from share"…, 40}, {": ", 2}, {"Cannot allocate memory", 22}, {"n", 1}], 10ls: error while loading shared libraries: libc.so.6: failed to map segment from shared object: Cannot allocate memory


十四)剩下的三种ulimit限制说明(file locks/max memory size/pipe size)

文件锁的限制只在2.4内核之前有用.
驻留内存的限制在很多系统里也没有作用.
管道的缓存不能改变,只能是8*512(bytes),也就是4096个字节.

centos 5 增加永久静态路由

手动添加路由的方式为:

route add -net 172.16.6.0 netmask 255.255.255.0 gw 172.16.2.25

route add -net是centos下的添加静态路由网络的方式,netmask是网络段的子网掩,gw表示下一跳的地址,其实就是指172.16.6.0此网段的路由通过172.16.2.25出去,这只是临时的效果,如果服务器重启则失败,如何能让其永久生效呢?其实可能将其写进文件中,如下:

vim /etc/sysconifg/network-scripts/route-eth0
127.16.6.0/24 via 172.16.2.25

服务器重启也不需要担心了,它会一直生效的

Centos下查看路由表的方式蛮多的,netstat -rn或route -n均可;linux下的相关资料也比较多,我这里也不作重点说明了.

rpm包安装时如何更新安装路径?

如果rpm包已经做好,但在安装的时候想修改默认路径,则可以:

rpm -ivh –prefix=/opt/usr xxx.rpm
又或者同时修改多个路径:

rpm -ivh –relocate=/usr=/opt/usr –relocate=/etc=/usr/etc xxx.rpm


查看一个未安装的rpm包中包含那些文件:

rpm -qlp ****.rpm 

rpm -ivh [install_options] package
以下的options是可完成:
        –prefix <path>;
               This   sets   the   installation   prefix to <path>; for
               relocatable packages.

        –relocate <oldpath>;=<newpath>;
               For relocatable packages, translates the files that
               would be put in <oldpath>; to <newpath>;.

        –badreloc
               To   be   used   in   conjunction with –relocate, this
               forces the relocation even   if   the   package   isn’t
               relocatable.

        –noorder
               Don’t reorder the packages for an install. The list
               of packages would normally be reordered to   satisfy
               dependancies.

mysql over ssh 访问

先来假设一个场景,在机房有几台服务器,分别是:

mysql:192.168.1.10

web:192.168.1.20

test:192.168.1.30

有如下限制:

1) test可以ssh到web,不能ssh到mysql

2) web不能ssh到mysql

3) web可以访问mysql

4) test不能访问mysql

5) mysql用户没有show databses权限,也就是用不了phpmyadmin

6) 在公司只能ssh到test

而现在你在公司,除了先ssh到test,再从test ssh到web,用命令行访问mysql,还有什么办法?

答案可能只有mysql over ssh tunnel了。

需要打两次洞,test打一个到mysql的,通过web代理;还有就是从公司到test的。

配置步骤:

1)先让test能无密码(使用证书)ssh到web

在test上:

生成一个公私key:

# ssh-keygen -t dsa

一直回车,不要输密码

把公key 复制到web上

scp ~/.ssh/*.pub test@192.168.1.20:~/

在web上:

cd /home/test

cat id_dsa.pub >> .ssh/authorized_keys
chmod 644 .ssh/authorized_keys

在test上测试,看ssh test@192.168.1.20是不是不用密码就能连过去了。

2) 在test上建立tunnel

# ssh -L3308:192.168.1.10:3306 -p 22 -N -t -x test@192.168.1.20

现在应该可以在test上面用mysql -uuser -p -h127.0.0.1 -P 3308访问数据库了。

3)在secureCRT上开一个tunnel

编辑连接到test主机的属性:

这样就建立了一个从你的机器到test服务器3308的tunnel。

现在你访问本机的3308端口就相当于访问192.168.1.10的3306端口,也就是访问mysql数据库。

4) 用MySQL-Front连接数据库

打开MySQL-Front,新建一个连接,主机为127.0.0.1,端口为3308:

用iptables的raw表解决ip_conntrack: table full, dropping packet的问题

1)  什么是raw表?做什么用的?

iptables有5个链:PREROUTING,INPUT,FORWARD,OUTPUT,POSTROUTING,4个表:filter,nat,mangle,raw.

4个表的优先级由高到低的顺序为:raw–>mangle–>nat–>filter

举例来说:如果PRROUTING链上,即有mangle表,也有nat表,那么先由mangle处理,然后由nat表处理

RAW表只使用在PREROUTING链和OUTPUT链上,因为优先级最高,从而可以对收到的数据包在连接跟踪前进行处理。一但用户使用了RAW表,在某个链上,RAW表处理完后,将跳过NAT表和 ip_conntrack处理,即不再做地址转换和数据包的链接跟踪处理了.

RAW表可以应用在那些不需要做nat的情况下,以提高性能。如大量访问的web服务器,可以让80端口不再让iptables做数据包的链接跟踪处理,以提高用户的访问速度。

2)  iptables的数据包的流程是怎样的?

(流程介绍来源:http://selboo.com.cn/post/721/)
一个数据包到达时,是怎么依次穿过各个链和表的(图)。

基本步骤如下:
1. 数据包到达网络接口,比如 eth0。
2. 进入 raw 表的 PREROUTING 链,这个链的作用是赶在连接跟踪之前处理数据包。
3. 如果进行了连接跟踪,在此处理。
4. 进入 mangle 表的 PREROUTING 链,在此可以修改数据包,比如 TOS 等。
5. 进入 nat 表的 PREROUTING 链,可以在此做DNAT,但不要做过滤。
6. 决定路由,看是交给本地主机还是转发给其它主机。

到了这里我们就得分两种不同的情况进行讨论了,一种情况就是数据包要转发给其它主机,这时候它会依次经过:
7. 进入 mangle 表的 FORWARD 链,这里也比较特殊,这是在第一次路由决定之后,在进行最后的路由决定之前,我们仍然可以对数据包进行某些修改。
8. 进入 filter 表的 FORWARD 链,在这里我们可以对所有转发的数据包进行过滤。需要注意的是:经过这里的数据包是转发的,方向是双向的。
9. 进入 mangle 表的 POSTROUTING 链,到这里已经做完了所有的路由决定,但数据包仍然在本地主机,我们还可以进行某些修改。
10. 进入 nat 表的 POSTROUTING 链,在这里一般都是用来做 SNAT ,不要在这里进行过滤。
11. 进入出去的网络接口。完毕。

另一种情况是,数据包就是发给本地主机的,那么它会依次穿过:
7. 进入 mangle 表的 INPUT 链,这里是在路由之后,交由本地主机之前,我们也可以进行一些相应的修改。
8. 进入 filter 表的 INPUT 链,在这里我们可以对流入的所有数据包进行过滤,无论它来自哪个网络接口。
9. 交给本地主机的应用程序进行处理。
10. 处理完毕后进行路由决定,看该往那里发出。
11. 进入 raw 表的 OUTPUT 链,这里是在连接跟踪处理本地的数据包之前。
12. 连接跟踪对本地的数据包进行处理。
13. 进入 mangle 表的 OUTPUT 链,在这里我们可以修改数据包,但不要做过滤。
14. 进入 nat 表的 OUTPUT 链,可以对防火墙自己发出的数据做 NAT 。
15. 再次进行路由决定。
16. 进入 filter 表的 OUTPUT 链,可以对本地出去的数据包进行过滤。
17. 进入 mangle 表的 POSTROUTING 链,同上一种情况的第9步。注意,这里不光对经过防火墙的数据包进行处理,还对防火墙自己产生的数据包进行处理。
18. 进入 nat 表的 POSTROUTING 链,同上一种情况的第10步。
19. 进入出去的网络接口。完毕。

3)  iptables raw表的使用

增加raw表,在其他表处理之前,-j NOTRACK跳过其它表处理
状态除了以前的四个还增加了一个UNTRACKED

例如:
可以使用 “NOTRACK” target 允许规则指定80端口的包不进入链接跟踪/NAT子系统

iptables -t raw -A PREROUTING -d 1.2.3.4 -p tcp –dport 80 -j NOTRACK
iptables -t raw -A PREROUTING -s 1.2.3.4 -p tcp –sport 80 -j NOTRACK
iptables -A FORWARD -m state –state UNTRACKED -j ACCEPT

4) 解决ip_conntrack: table full, dropping packet的问题

在启用了iptables web服务器上,流量高的时候经常会出现下面的错误:

ip_conntrack: table full, dropping packet

这个问题的原因是由于web服务器收到了大量的连接,在启用了iptables的情况下,iptables会把所有的连接都做链接跟踪处理,这样iptables就会有一个链接跟踪表,当这个表满的时候,就会出现上面的错误。

iptables的链接跟踪表最大容量为/proc/sys/net/ipv4/ip_conntrack_max,链接碰到各种状态的超时后就会从表中删除。

所以解決方法一般有两个:

(1) 加大 ip_conntrack_max 值

vi /etc/sysctl.conf

net.ipv4.ip_conntrack_max = 393216
net.ipv4.netfilter.ip_conntrack_max = 393216

(2): 降低 ip_conntrack timeout时间

vi /etc/sysctl.conf

net.ipv4.netfilter.ip_conntrack_tcp_timeout_established = 300
net.ipv4.netfilter.ip_conntrack_tcp_timeout_time_wait = 120
net.ipv4.netfilter.ip_conntrack_tcp_timeout_close_wait = 60
net.ipv4.netfilter.ip_conntrack_tcp_timeout_fin_wait = 120

上面两种方法打个比喻就是烧水水开的时候,换一个大锅。一般情况下都可以解决问题,但是在极端情况下,还是不够用,怎么办?

这样就得反其道而行,用釜底抽薪的办法。iptables的raw表是不做数据包的链接跟踪处理的,我们就把那些连接量非常大的链接加入到iptables raw表。

如一台web服务器可以这样:

iptables -t raw -A PREROUTING -d 1.2.3.4 -p tcp –dport 80 -j NOTRACK
iptables -A FORWARD -m state –state UNTRACKED -j ACCEPT

5)  iptables raw表的效果测试

我们在一台web server上做测试,先不使用raw表,观察链接跟踪表(/proc/net/ip_conntrack)的大小:

先看下iptables配置:
cat /etc/sysconfig/iptables

# Generated by iptables-save v1.3.5 on Wed Aug 18 10:10:52 2010
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [104076:12500201]
:RH-Firewall-1-INPUT – [0:0]
-A INPUT -j RH-Firewall-1-INPUT
-A FORWARD -j RH-Firewall-1-INPUT
-A RH-Firewall-1-INPUT -i lo -j ACCEPT
-A RH-Firewall-1-INPUT -p icmp -m icmp –icmp-type any -j ACCEPT
-A RH-Firewall-1-INPUT -p esp -j ACCEPT
-A RH-Firewall-1-INPUT -p ah -j ACCEPT
-A RH-Firewall-1-INPUT -d 224.0.0.251 -p udp -m udp –dport 5353 -j ACCEPT
-A RH-Firewall-1-INPUT -p udp -m udp –dport 631 -j ACCEPT
-A RH-Firewall-1-INPUT -p tcp -m tcp –dport 631 -j ACCEPT
-A RH-Firewall-1-INPUT -m state –state RELATED,ESTABLISHED -j ACCEPT
-A RH-Firewall-1-INPUT -p tcp -m state –state NEW -m tcp –dport 22 -j ACCEPT
-A RH-Firewall-1-INPUT -p tcp -m state –state NEW -m tcp –dport 80 -j ACCEPT
-A RH-Firewall-1-INPUT -j REJECT –reject-with icmp-host-prohibited
COMMIT
# Completed on Wed Aug 18 10:10:52 2010

在另一台机器上用ab测试:

ab -c 1000 -n 5000 http://192.168.20.26/index.html

在web server上查看链接跟踪表(/proc/net/ip_conntrack)的大小:

[root@mongo html]# wc -l /proc/net/ip_conntrack
5153 /proc/net/ip_conntrack

可以看到跟踪表内有5153个链接,再大一些的压力可能就要报ip_conntrack: table full, dropping packet的错误了。

下面我们启用raw表:

先更新iptables:

[root@mongo html]# cat /etc/sysconfig/iptables
# Generated by iptables-save v1.3.5 on Wed Aug 18 10:10:52 2010
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [104076:12500201]
:RH-Firewall-1-INPUT – [0:0]
-A INPUT -j RH-Firewall-1-INPUT
-A FORWARD -j RH-Firewall-1-INPUT
-A RH-Firewall-1-INPUT -i lo -j ACCEPT
-A RH-Firewall-1-INPUT -p icmp -m icmp –icmp-type any -j ACCEPT
-A RH-Firewall-1-INPUT -p esp -j ACCEPT
-A RH-Firewall-1-INPUT -p ah -j ACCEPT
-A RH-Firewall-1-INPUT -d 224.0.0.251 -p udp -m udp –dport 5353 -j ACCEPT
-A RH-Firewall-1-INPUT -p udp -m udp –dport 631 -j ACCEPT
-A RH-Firewall-1-INPUT -p tcp -m tcp –dport 631 -j ACCEPT
-A RH-Firewall-1-INPUT -m state –state RELATED,ESTABLISHED,UNTRACKED -j ACCEPT
-A RH-Firewall-1-INPUT -p tcp -m state –state NEW -m tcp –dport 22 -j ACCEPT
-A RH-Firewall-1-INPUT -p tcp -m state –state NEW -m tcp –dport 80 -j ACCEPT
-A RH-Firewall-1-INPUT -j REJECT –reject-with icmp-host-prohibited
COMMIT
# Completed on Wed Aug 18 10:10:52 2010
# Generated by iptables-save v1.3.5 on Wed Aug 18 10:10:52 2010
*raw
:PREROUTING ACCEPT [116163:9327716]
:OUTPUT ACCEPT [104076:12500201]
-A PREROUTING -p tcp -m tcp –dport 80 -j NOTRACK
-A OUTPUT -p tcp -m tcp –sport 80 -j NOTRACK
COMMIT
# Completed on Wed Aug 18 10:10:52 2010

红色部分是新增的。

重启iptables:

service iptables restart

可以用iptables命令查看是否启用成功了:

[root@mongo html]# iptables -t raw -L -n
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination        
NOTRACK    tcp  –  0.0.0.0/0            0.0.0.0/0           tcp dpt:80

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination        
NOTRACK    tcp  –  0.0.0.0/0            0.0.0.0/0           tcp spt:80

然后再用ab测试:

ab -c 1000 -n 5000 http://192.168.20.26/index.html

查看链接跟踪表(/proc/net/ip_conntrack)的大小:

[root@mongo html]# wc -l /proc/net/ip_conntrack
1 /proc/net/ip_conntrack

跟踪表内只跟踪了一个链接了。

[root@mongo html]# cat /proc/net/ip_conntrack 
tcp      6 431999 ESTABLISHED src=192.168.20.26 dst=192.168.20.10 sport=22 dport=50088 packets=85 bytes=10200 src=192.168.20.10 dst=192.168.20.26 sport=50088 dport=22 packets=92 bytes=6832 [ASSURED] mark=0 secmark=0 use=1

可以看到iptables已经不跟踪进出端口为80的链接了。测试结果表明用iptables的raw表可以完美解决ip_conntrack: table full, dropping packet的问题。

服务器报警,出现 blocked for more than 120 seconds.

前几天服务器发生了一次报警,显示系统负载过高,Nagios监控发生超时。等我连上去看的时候,已经收到服务器恢复正常,报警解除的短信了。

看了下日志,有以下信息:

Jul 16 10:14:47 web3 nrpe[18939]: Error: Could not complete SSL handshake. 5
Jul 16 12:12:07 web3 rpc.statd[3007]: Received SM_UNMON request from web3.shinezone.com for 192.168.1.2 while not monitoring any hosts.
Jul 16 12:14:11 web3 kernel: INFO: task nfsd:3269 blocked for more than 120 seconds.
Jul 16 12:14:11 web3 kernel: "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
Jul 16 12:14:11 web3 kernel: nfsd          D ffff81023dc3fb88     0  3269      1          3270  3268 (L-TLB)
Jul 16 12:14:11 web3 kernel:  ffff8104ac50dc40 0000000000000046 ffff8104ac50dc50 ffffffff80062ff8
Jul 16 12:14:11 web3 kernel:  0000000000000000 000000000000000a ffff8104ac91d820 ffff81032cf41820
Jul 16 12:14:11 web3 kernel:  0011e5ad2e3f154c 00000000000003fe ffff8104ac91da08 0000000200002f1d
Jul 16 12:14:11 web3 kernel: Call Trace:
Jul 16 12:14:11 web3 kernel:  [<ffffffff80062ff8>] thread_return+0x62/0xfe
Jul 16 12:14:11 web3 kernel:  [<ffffffff88036d8a>] :jbd:log_wait_commit+0xa3/0xf5
Jul 16 12:14:11 web3 kernel:  [<ffffffff800a0abe>] autoremove_wake_function+0x0/0x2e
Jul 16 12:14:11 web3 kernel:  [<ffffffff80097dab>] process_timeout+0x0/0x5
Jul 16 12:14:11 web3 kernel:  [<ffffffff8803178a>] :jbd:journal_stop+0x1cf/0x1ff
Jul 16 12:14:13 web3 nrpe[20013]: Error: Could not complete SSL handshake. 5
Jul 16 12:17:34 web3 nrpe[20026]: Error: Could not complete SSL handshake. 5
Jul 16 12:18:12 web3 kernel:  [<ffffffff8002fbf8>] __writeback_single_inode+0x1e9/0x328
Jul 16 12:18:12 web3 kernel:  [<ffffffff800f2dcf>] write_inode_now+0x77/0xbf
Jul 16 12:18:12 web3 kernel:  [<ffffffff884554fa>] :nfsd:nfsd_setattr+0x3f9/0x426
Jul 16 12:18:12 web3 kernel:  [<ffffffff8845b798>] :nfsd:nfsd3_proc_setattr+0x98/0xa4
Jul 16 12:18:12 web3 kernel:  [<ffffffff884511db>] :nfsd:nfsd_dispatch+0xd8/0x1d6
Jul 16 12:18:12 web3 kernel:  [<ffffffff883d1651>] :sunrpc:svc_process+0x454/0x71b
Jul 16 12:18:13 web3 kernel:  [<ffffffff80064644>] __down_read+0x12/0x92
Jul 16 12:18:13 web3 kernel:  [<ffffffff884515a1>] :nfsd:nfsd+0x0/0x2cb
Jul 16 12:18:13 web3 kernel:  [<ffffffff88451746>] :nfsd:nfsd+0x1a5/0x2cb
Jul 16 12:18:13 web3 kernel:  [<ffffffff8005dfb1>] child_rip+0xa/0x11
Jul 16 12:18:13 web3 kernel:  [<ffffffff884515a1>] :nfsd:nfsd+0x0/0x2cb
Jul 16 12:18:13 web3 kernel:  [<ffffffff884515a1>] :nfsd:nfsd+0x0/0x2cb
Jul 16 12:18:13 web3 kernel:  [<ffffffff8005dfa7>] child_rip+0x0/0x11
Jul 16 12:18:13 web3 kernel:
Jul 16 12:18:13 web3 kernel: INFO: task php-cgi:24520 blocked for more than 120 seconds.
Jul 16 12:18:13 web3 kernel: "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
Jul 16 12:18:13 web3 kernel: php-cgi       D ffff8103da547ac0     0 24520  24516         24521 24519 (NOTLB)
Jul 16 12:18:13 web3 kernel:  ffff8102e056dd28 0000000000000086 0000000000004040 00000000000001ff
Jul 16 12:18:13 web3 kernel:  ffff8102e056dee8 000000000000000a ffff81023ed32040 ffff81020b7a07e0
Jul 16 12:18:13 web3 kernel:  0011e5a8d1911bbe 00000000000056f8 ffff81023ed32228 000000068003055b
Jul 16 12:18:13 web3 kernel: Call Trace:
Jul 16 12:18:13 web3 kernel:  [<ffffffff80063c6f>] __mutex_lock_slowpath+0x60/0x9b
Jul 16 12:18:13 web3 kernel:  [<ffffffff80063cb9>] .text.lock.mutex+0xf/0x14
Jul 16 12:18:13 web3 kernel:  [<ffffffff800216ff>] generic_file_aio_write+0x4e/0xc1
Jul 16 12:18:13 web3 kernel:  [<ffffffff8804c1b6>] :ext3:ext3_file_write+0x16/0x91
Jul 16 12:18:13 web3 kernel:  [<ffffffff80018237>] do_sync_write+0xc7/0x104
Jul 16 12:18:13 web3 kernel:  [<ffffffff8002b952>] sys_recvfrom+0xd4/0x130
Jul 16 12:18:13 web3 kernel:  [<ffffffff800a0abe>] autoremove_wake_function+0x0/0x2e
Jul 16 12:18:13 web3 kernel:  [<ffffffff8000c5fe>] _atomic_dec_and_lock+0x39/0x57
Jul 16 12:18:13 web3 kernel:  [<ffffffff8000d3cb>] dput+0x3d/0x114
Jul 16 12:18:14 web3 kernel:  [<ffffffff80016a1a>] vfs_write+0xce/0x174
Jul 16 12:18:14 web3 kernel:  [<ffffffff800172e7>] sys_write+0x45/0x6e
Jul 16 12:18:14 web3 kernel:  [<ffffffff8005d116>] system_call+0x7e/0x83

INFO: task nfsd:3269 blocked for more than 120 seconds.
INFO: task php-cgi:24520 blocked for more than 120 seconds.

这句的意思是nfsd和php-cgi这两个进程出现了超过120秒的阻塞现象。初步怀疑是机房的网络出现了短暂中断或者磁盘写入出现问题造成的,只是日志又正常写进去了,网络的原因可能性比较大。有待后续观察…..