当前位置:  操作系统/服务器>linux
本页文章导读:
    ▪linux 可执行文件与写操作的同步问题(文件读写操作产生的锁机制)       当一个可执行文件已经为write而open时,此时的可执行文件是不允许被执行的。反过来,一个文件正在执行时,它也是不允许同时被write模式而open的。这个约束很好理解,因为文件执行和文件.........
    ▪linux系统获取硬盘使用信息       1、df命令   Linux下可以用df命令获取硬盘的使用情况,通过man可以获取df命令的详细情况。df命令经常用的参数为:   a:显示全部的档案系统和各分割区的磁盘使用情形   i:显示i -nod.........
    ▪nginx 502 Bad Gateway 错误解决办法       一些运行在Nginx上的网站有时候会出现“502 Bad Gateway”错误,有些时候甚至频繁的出现。以下是小编搜集整理的一些Nginx 502错误的排查方法,供参考:   Nginx 502错误的原因比较多,是因为.........

[1]linux 可执行文件与写操作的同步问题(文件读写操作产生的锁机制)
    来源: 互联网  发布时间: 2013-12-24
当一个可执行文件已经为write而open时,此时的可执行文件是不允许被执行的。反过来,一个文件正在执行时,它也是不允许同时被write模式而open的。这个约束很好理解,因为文件执行和文件被写应该需要同步保护,因此内核会保证这种同步。那么内核是如何实现该机制的呢?
Inode结点中包含一个数据项,叫做i_writecount,很明显是用于记录文件被写的个数的,用于同步的,其类型也是atomic_t. 内核中有两个我们需要了解的函数,与write操作有关,分别是:

代码如下:

int get_write_access(struct inode * inode)
{
    spin_lock(&inode->i_lock);
    if (atomic_read(&inode->i_writecount) < 0) {
                spin_unlock(&inode->i_lock);
        return -ETXTBSY;
    }
    atomic_inc(&inode->i_writecount);
        spin_unlock(&inode->i_lock);
    return 0;
}

int deny_write_access(struct file * file)
{
    struct inode *inode = file->f_path.dentry->d_inode;
        spin_lock(&inode->i_lock);
    if (atomic_read(&inode->i_writecount) > 0) {//如果文件被打开了,返回失败
                spin_unlock(&inode->i_lock);
        return -ETXTBSY;
    }
        atomic_dec(&inode->i_writecount);
    spin_unlock(&inode->i_lock);
}

这两个函数都很简单,get_write_acess作用就和名称一致,同样deny_write_access也是。如果一个文件被执行了,要保证它在执行的过程中不能被写,那么在开始执行前应该调用deny_write_access 来关闭写的权限。那就来检查execve系统调用有没有这么做。
Sys_execve中调用do_execve,然后又调用函数open_exec,看一下open_exec的代码:

代码如下:

struct file *open_exec(const char *name)
{
    struct file *file;
    int err;
        file = do_filp_open(AT_FDCWD, name,
                O_LARGEFILE | O_RDONLY | FMODE_EXEC, 0,
                MAY_EXEC | MAY_OPEN);

        if (IS_ERR(file))
        goto out;
        err = -EACCES;

    if (!S_ISREG(file->f_path.dentry->d_inode->i_mode))
        goto exit;

        if (file->f_path.mnt->mnt_flags & MNT_NOEXEC)
        goto exit;

        fsnotify_open(file->f_path.dentry);
    err = deny_write_access(file);//调用
       if (err)
        goto exit;

       out:
    return file;

       exit:
    fput(file);
    return ERR_PTR(err);
}

明显看到了deny_write_access的调用,和预想的完全一致。在open的调用里,应该有get_write_access的调用。在open调用相关的__dentry_open函数中就包含了对该函数的调用。

代码如下:

if (f->f_mode & FMODE_WRITE) {
    error = __get_file_write_access(inode, mnt);
    if (error)
            goto cleanup_file;
    if (!special_file(inode->i_mode))
      file_take_write(f);
}

其中__get_file_write_access(inode, mnt)封装了get_write_access.
那么内核又是如何保证一个正在被写的文件是不允许被执行的呢?这个同样也很简单,当一个文件已经为write而open时,它对应的inode的i_writecount会变成1,因此在执行execve时同样会调用deny_write_access 中读取到i_writecount>0之后就会返回失败,因此execve也就会失败返回。
这里是写文件与i_writecount相关的场景:
写打开一个文件时,在函数dentry_open中:
代码如下:

if (f->f_mode & FMODE_WRITE) {
    error = get_write_access(inode);
    if (error)
    goto cleanup_file;
}

当然在文件关闭时,会将i_writecount--;关闭时会执行代码:
代码如下:

if (file->f_mode & FMODE_WRITE)
    put_write_access(inode);

put_write_access 代码很简单:
代码如下:

static inline void put_write_access(struct inode * inode)
{
    atomic_dec(&inode->i_writecount);
}

于是乎自己写了个简单的代码,一个空循环,文件在执行的时候,在bash中,echo 111 >>可执行文件,结果预期之中,返回失败,并提示信息 text file busy.
那么该机制是否同样适用于映射机制呢,在执行可执行文件时,会mmap一些关联的动态链接库,这些动态链接库是否被mmap之后就不允许被写以及正在写时不允许mmap呢?这个是需要考虑的,因为它关系到安全的问题。因为库文件也是可执行的代码,被篡改同样会引起安全问题。
Mmap在调用mmap_region的函数里,有一个相关的检查:

代码如下:

if (vm_flags & VM_DENYWRITE) {         
        error = deny_write_access(file);
    if (error)
        goto free_vma;
    correct_wcount = 1;
}

其中,mmap调用中的flags参数会被正确的赋值给vm_flags,对应关系是MAP_DENYWRIRE被设置了,那么VM_DENYWRITE就对应的也被设置。下面写了个简单的代码,做一下测试:
代码如下:

#include <stdio.h>
#include <sys/mman.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
        int fd;
    void *src = NULL;
    fd = open("test.txt",O_RDONLY);
    if (fd != 0)
        {
        if ((src = mmap(0,5,PROT_READ|PROT_EXEC  ,MAP_PRIVATE|        MAP_DENYWRITE,fd,0))== MAP_FAILED)
                {
            printf("MMAP error\n");
            printf("%s\n",strerror(errno));
                }else{
            printf("%x\n",src);
        }
    }

        FILE * fd_t = fopen("test.txt","w");
    if( !fd_t)
    {
                printf("open for write error\n");
        printf("%s\n",strerror(errno));
        return 0;
    }

        if (fwrite("0000",sizeof(char),4,fd_t) != 4)
    {
        printf("fwrite error \n");
    }

     
        fclose(fd_t);
    close(fd);
    return 1;
}

最后的test.txt被写成了”0000”,很奇怪,貌似MAP_DENTWRITE不起作用了。于是man mmap查看,发现:

  MAP_DENYWRITE

  This  flag  is ignored.  (Long ago, it signaled that attempts to write to the underlying file should fail with ETXTBUSY. But this was a source of denial-of-service attacks.)

原来这个标识在用户层已经不起作用了啊,而且还说明了原因,容易引起拒绝式服务攻击。攻击者恶意的将某些系统程序要写的文件以MAP_DENYWRITE模式映射,会导致正常程序写文件失败。不过VM_DENYWRITE在内核里还是有使用的,在mmap中还是有对deny_write_access的调用, 但是对它的调用已经不是由mmap中的flag参数的MAP_DENYWRITE驱动的了。
那与可执行文件相关的动态链接库文件就悲剧了,大家都知道动态链接库使用的也是mmap,这也导致动态链接库在运行时可以被更改。其实我这就是为了确认这点。这也导致我需要自己写同步控制代码了。我们可以使用inode中的i_security以及file结构的f_secutiry变量来写自己的同步逻辑,就是麻烦了不少,还要写内核模块,哎,工作量又增加了啊。安全问题是个麻烦的问题...


    
[2]linux系统获取硬盘使用信息
    来源: 互联网  发布时间: 2013-12-24

1、df命令

  Linux下可以用df命令获取硬盘的使用情况,通过man可以获取df命令的详细情况。df命令经常用的参数为:

  a:显示全部的档案系统和各分割区的磁盘使用情形
  i:显示i -nodes的使用量
  k:大小用k来表示 (默认值)
  t:显示某一个档案系统的所有分割区磁盘使用量
  x:显示不是某一个档案系统的所有分割区磁盘使用量
  T:显示每个分割区所属的档案系统名称
  常用命令:df -hi

举例截图如下所示



2、du命令

  du命令用来查询档案或目录的磁盘使用空间,通过man获取du命令的详细介绍。常用的命令参数如下:
  a:显示全部目录和其次目录下的每个档案所占的磁盘空间
  b:大小用bytes来表示 (默认值为k bytes)
  c:最后再加上总计 (默认值)
  s:只显示各档案大小的总合 (summarize)
  x:只计算同属同一个档案系统的档案
  L:计算所有的档案大小
  常用命令:du -ah

举例操作如下图所示:



3、statfs结构及函数

  之前在看APUE时候,在第四章文件和目录中,讲到了获取文件信息的stat结构,通过stat结构可以获文件的大小,创建时间,修改时间,用户id,组id等等。man上stat结构及操作函数如下图所示:



今天主要总结学习一下获取硬盘信息的statfs结构,通过statfs结构的信息计算出路径所在的磁盘使用情况。man上关于statfs介绍如下所示:



statfs结构的中文意思如下所示:

代码如下:

struct statfs
  {
      long f_type; /* 文件系统类型*/
      long f_bsize; /* 经过优化的传输块大小*/
      long f_blocks; /* 文件系统数据块总数*/
   long f_bfree; /* 可用块数*/
   long f_bavail; /* 非超级用户可获取的块数*/
   long f_files; /* 文件结点总数*/
   long f_ffree; /* 可用文件结点数*/
   fsid_t f_fsid; /* 文件系统标识*/
   long f_namelen; /* 文件名的最大长度*/
 };



statfs结构中可用空间块数有两种f_bfree和 f_bavail,前者是硬盘所有剩余空间,后者为非root用户剩余空间,ext3文件系统给root用户分有5%的独享空间,所以这里是不同的地方。这里要强调的是每块的大小一般是4K。因此,要实现与df结果一致的就得在获得块数上乘以4,这样已用、可用、总块数就可以实现。
测试程序如下所示:

代码如下:

#include <stdio.h>
#include <sys/statfs.h>
#include <sys/vfs.h>
#include <errno.h>

int main(int argc, char *argv[])
{
    struct statfs disk_info;
    char *path = "/home/";
    int ret = 0;
    if (argc == 2)
    {
      path = argv[1];
    }
    if (ret == statfs(path, &disk_info) == -1)
    {
      fprintf(stderr, "Failed to get file disk infomation,\
          errno:%u, reason:%s\n", errno, strerror(errno));
      return -1;
    }
    long long total_size = disk_info.f_blocks * disk_info.f_bsize;
    long long available_size = disk_info.f_bavail * disk_info.f_bsize;
    long long free_size = disk_info.f_bfree * disk_info.f_bsize;
    //输出每个块的长度,linux下内存块为4KB
    printf("block size: %ld bytes\n", disk_info.f_bsize);
    //输出块个数
    printf("total data blocks: %ld \n", disk_info.f_blocks);
    //输出path所在磁盘的大小
    printf("total file disk size: %d MB\n",total_size >> 20);
    //输出非root用户可以用的磁盘空间大小
    printf("avaiable size: %d MB\n",available_size >> 20);
    //输出硬盘的所有剩余空间
    printf("free size: %d MB\n",free_size >> 20);
    //输出磁盘上文件节点个数
    printf("total file nodes: %ld\n", disk_info.f_files);
    //输出可用文件节点个数
    printf("free file nodes: %ld\n", disk_info.f_ffree);
    //输出文件名最大长度
    printf("maxinum length of file name: %ld\n", disk_info.f_namelen);
    return 0;
}


测试结果如下所示:


    
[3]nginx 502 Bad Gateway 错误解决办法
    来源: 互联网  发布时间: 2013-12-24

一些运行在Nginx上的网站有时候会出现“502 Bad Gateway”错误,有些时候甚至频繁的出现。以下是小编搜集整理的一些Nginx 502错误的排查方法,供参考:

  Nginx 502错误的原因比较多,是因为在代理模式下后端服务器出现问题引起的。这些错误一般都不是nginx本身的问题,一定要从后端找原因!但nginx把这些出错都揽在自己身上了,着实让nginx的推广者备受置疑,毕竟从字眼上理解,bad gateway?不就是bad nginx吗?让不了解的人看到,会直接把责任推在nginx身上,希望nginx下一个版本会把出错提示写稍微友好一些,至少不会是现在简单的一句 502 Bad Gateway,另外还不忘附上自己的大名。

Nginx 502的触发条件

  502错误最通常的出现情况就是后端主机当机。在upstream配置里有这么一项配置:proxy_next_upstream,这个配置指定了 nginx在从一个后端主机取数据遇到何种错误时会转到下一个后端主机,里头写上的就是会出现502的所有情况拉,默认是error timeout。error就是当机、断线之类的,timeout就是读取堵塞超时,比较容易理解。我一般是全写上的:

proxy_next_upstream error timeout invalid_header http_500 http_503;  不过现在可能我要去掉http_500这一项了,http_500指定后端返回500错误时会转一个主机,后端的jsp出错的话,本来会打印一堆 stacktrace的错误信息,现在被502取代了。但公司的程序员可不这么认为,他们认定是nginx出现了错误,我实在没空跟他们解释502的原理 了……

503错误就可以保留,因为后端通常是apache resin,如果apache死机就是error,但resin死机,仅仅是503,所以还是有必要保留的。

解决办法

遇到502问题,可以优先考虑按照以下两个步骤去解决。

1、查看当前的PHP FastCGI进程数是否够用:

代码如下:

netstat -anpo | grep "php-cgi" | wc -l

如果实际使用的“FastCGI进程数”接近预设的“FastCGI进程数”,那么,说明“FastCGI进程数”不够用,需要增大。

2、部分PHP程序的执行时间超过了Nginx的等待时间,可以适当增加nginx.conf配置文件中FastCGI的timeout时间,例如:

代码如下:

 http  {
  fastcgi_connect_timeout 300;
  fastcgi_send_timeout 300;
  fastcgi_read_timeout 300;
  ......
  }
  ......

php.ini中memory_limit设低了会出错,修改了php.ini的memory_limit为64M,重启nginx,发现好了,原来是PHP的内存不足了。

  如果这样修改了还解决不了问题,可以参考下面这些方案:

一、max-children和max-requests

  一台服务器上运行着nginx php(fpm) xcache,访问量日均 300W pv左右。

  最近经常会出现这样的情况:php页面打开很慢,cpu使用率突然降至很低,系统负载突然升至很高,查看网卡的流量,也会发现突然降到了很低。这种情况只持续数秒钟就恢复了。

  检查php-fpm的日志文件发现了一些线索。

代码如下:

Sep 30 08:32:23.289973 [NOTICE] fpm_unix_init_main(), line 271: getrlimit(nofile): max:51200, cur:51200  Sep 30 08:32:23.290212 [NOTICE] fpm_sockets_init_main(), line 371: using inherited socket fd=10, “127.0.0.1:9000″  Sep 30 08:32:23.290342 [NOTICE] fpm_event_init_main(), line 109: libevent: using epoll  Sep 30 08:32:23.296426 [NOTICE] fpm_init(), line 47: fpm is running, pid 30587 

在这几句的前面,是1000多行的关闭children和开启children的日志。

  原来,php-fpm有一个参数 max_requests,该参数指明了,每个children最多处理多少个请求后便会被关闭,默认的设置是500。因为php是把请求轮询给每个 children,在大流量下,每个childre到达max_requests所用的时间都差不多,这样就造成所有的children基本上在同一时间 被关闭。

  在这期间,nginx无法将php文件转交给php-fpm处理,所以cpu会降至很低(不用处理php,更不用执行sql),而负载会升至很高(关闭和开启children、nginx等待php-fpm),网卡流量也降至很低(nginx无法生成数据传输给客户端)

  解决问题很简单,增加children的数量,并且将 max_requests 设置未 0 或者一个比较大的值:

  打开 /usr/local/php/etc/php-fpm.conf调大以下两个参数(根据服务器实际情况,过大也不行)

代码如下:

<value name="max_children">5120</value>
<value name="max_requests">600</value>  

然后重启php-fpm。

二、增加缓冲区容量大小

  将nginx的error log打开,发现“pstream sent too big header while reading response header from upstream”这样的错误提示。查阅了一下资料,大意是nginx缓冲区有一个bug造成的,我们网站的页面消耗占用缓冲区可能过大。参考老外写的修 改办法增加了缓冲区容量大小设置,502问题彻底解决。后来系统管理员又对参数做了调整只保留了2个设置参数:client head buffer,fastcgi buffer size。

三、request_terminate_timeout

  如果主要是在一些post或者数据库操作的时候出现502这种情况,而不是在静态页面操作中常见,那么可以查看一下php-fpm.conf设置中的一项:

request_terminate_timeout

这个值是max_execution_time,就是fast-cgi的执行脚本时间。

0s

0s为关闭,就是无限执行下去。(当时装的时候没仔细看就改了一个数字)问题解决了,执行很长时间也不会出错了。优化fastcgi中,还可以改改这个值5s 看看效果。

php-cgi进程数不够用、php执行时间长、或者是php-cgi进程死掉,都会出现502错误。

Nginx 502 Bad Gateway错误的解决办法2

今天,我的VPS频繁提示Nginx 502 Bad Gateway错误了,重启了VPS解决之后又出现,很烦。有点想不通,前两天网站达到了1290的访问量都没有出什么问题,怎么这次就出现了502 Bad Gateway?郁闷啊!!!在搜索了很久,终于找到了不少相关的答案,希望修改之后不会再出现这个错误了。唉,既然在网上找了那么久的答案,那当然得把有用的东西记录下,免得我下次再去谷歌~

由于我是采用了LNMP一键安装包 ,出了问题肯定要先到官方论坛去搜索下了,真好,官方有个这样的置顶帖,大家先瞧瞧。

LNMP一键安装包官方的:

第一种原因:目前lnmp一键安装包比较多的问题就是502 Bad Gateway,大部分情况下原因是在安装php前,脚本中某些lib包可能没有安装上,造成php没有编译安装成功。
解决办法:可以尝试根据lnmp一键安装包中的脚本手动安装一下,看看是什么错误导致的。

第二种原因:

在php.ini里,eaccelerator配置项一定要放在Zend Optimizer配置之前,否则也可能引起502 Bad Gateway

第三种原因:

在安装好使用过程中出现502问题,一般是因为默认php-cgi进程是5个,可能因为phpcgi进程不够用而造成502,需要修改/usr/local/php/etc/php-fpm.conf 将其中的max_children值适当增加。

第四种原因:

php执行超时,修改/usr/local/php/etc/php.ini 将max_execution_time 改为300

第五种原因:

磁盘空间不足,如mysql日志占用大量空间

第六种原因:

查看php-cgi进程是否在运行

也有网友给出了另外的解决办法:

Nginx 502 Bad Gateway的含义是请求的PHP-CGI已经执行,但是由于某种原因(一般是读取资源的问题)没有执行完毕而导致PHP-CGI进程终止,一般来说Nginx 502 Bad Gateway和php-fpm.conf的设置有关。

php-fpm.conf有两个至关重要的参数,一个是max_children,另一个是request_terminate_timeout,但是这个值不是通用的,而是需要自己计算的。
在安装好使用过程中出现502问题,一般是因为默认php-cgi进程是5个,可能因为phpcgi进程不够用而造成502,需要修改/usr/local/php/etc/php-fpm.conf 将其中的max_children值适当增加。

计算的方式如下:

如果你的服务器性能足够好,且宽带资源足够充足,PHP脚本没有系循环或BUG的话你可以直接将 request_terminate_timeout设置成0s。0s的含义是让PHP-CGI一直执行下去而没有时间限制。而如果你做不到这一点,也就 是说你的PHP-CGI可能出现某个BUG,或者你的宽带不够充足或者其他的原因导致你的PHP-CGI假死那么就建议你给 request_terminate_timeout赋一个值,这个值可以根据服务器的性能进行设定。一般来说性能越好你可以设置越高,20分钟-30分 钟都可以。
而max_children这个值又是怎么计算出来的呢?这个值原则上是越大越好,php-cgi的进程多了就会处理的很快,排队的请求就会很少。 设置max_children也需要根据服务器的性能进行设定,一般来说一台服务器正常情况下每一个php-cgi所耗费的内存在20M左右。

按照官方的答案,排查了相关的可能,并结合了网友的答案,得出了下面的解决办法。

1、查看php fastcgi的进程数(max_children值)

代码:netstat -anpo | grep “php-cgi” | wc -l

5(假如显示5)

2、查看当前进程

代码:top
观察fastcgi进程数,假如使用的进程数等于或高于5个,说明需要增加(根据你机器实际状况而定)

3、调整/usr/local/php/etc/php-fpm.conf 的相关设置

<value name=”max_children”>10</value>
<value name=”request_terminate_timeout”>60s</value>
max_children最多10个进程,按照每个进程20MB内存,最多200MB。
request_terminate_timeout执行的时间为60秒,也就是1分钟。


    
最新技术文章:
▪linux系统中的列出敏感用户的脚本代码
▪a10 config backup for aXAPI
▪一键备份gitolite服务器的Shell脚本
▪nagios 分发文件实现代码
▪阿里云云服务器Linux系统更新yum源Shell脚本
▪一个监控LINUX目录和文件变化的Shell脚本分享
▪Linux下实现SSH免密码登录和实现秘钥的管理、...
▪Shell正则表达式之grep、sed、awk实操笔记
▪3个备份系统文件并邮件发送的Shell脚本分享
▪CentOS 6.3下给PHP添加mssql扩展模块教程
▪监控网站是否可以正常打开的Shell脚本分享
▪shell脚本编程之if语句学习笔记
▪shell脚本编程之循环语句学习笔记
▪shell脚本编程之case语句学习笔记
▪Shell脚本实现的阳历转农历代码分享
▪Shell脚本实现复制文件到多台服务器的代码分...
▪Shell脚本实现批量下载网络图片代码分享
▪Shell脚本实现检测文件是否被修改过代码分享
▪Shell脚本数组用法小结
▪Shell脚本批量重命名文件后缀的3种实现
▪C语言实现的ls命令源码分享
▪Linux下查找后门程序 CentOS 查后门程序的shell脚...
▪Shell 函数参数
▪linux shell 自定义函数方法(定义、返回值、变...
▪Shell实现判断进程是否存在并重新启动脚本分...
▪Shell脚本break和continue命令简明教程
▪Shell脚本函数定义和函数参数
▪让代码整洁、过程清晰的BASH Shell编程技巧
▪shell常用重定向实例讲解
▪awk中RS、ORS、FS、OFS的区别和联系小结
 


站内导航:


特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

©2012-2021,,E-mail:www_#163.com(请将#改为@)

浙ICP备11055608号-3