使用lsof处理空间释放问题

曾经在生产上遇到过一个df 和 du出现的结果不一致的问题,为了排查到底是那儿占用的空间,大家可以用losf试试看

lsof |grep deleted 

应该会得到如下类似的结果

找到其中占用空间较大的进程,然后你可以使用kill 命令来释放文件句柄从而释放空间

发表在 好文推荐 | 标签为 | 19 条评论

再次强调在php中调用exec执行命令的注意事项

这两天在配置GO项目的hook.经过几次折腾,发现就是一个很小的注意事项。

要在shell中增加

export GOPATH=/alidata/gopath

要不,GO build 很有可能会失败的.

另外,为了避免以后再遇到这种问题,凡是exec,system等类似的方法,都应该在命令之后通过“ 2>&1”  将错误信息也输出到标准输出中,方便调试命令,发现问题!

发表在 好文推荐, 网站开发 | 标签为 , | 18 条评论

用supervisor来管理守护进程

supervisor是python写的将非daemon的程序生成daemon的程序来管理.

在阿里云centos下安装以及配置如下

yum -y update
yum -y install python-setuptools
easy_install supervisor
touch  /etc/supervisord.conf

supervisord.conf配置文件内容如下:

[unix_http_server]
file = /var/run/supervisord.sock
chmod = 0777
chown= root:root

[inet_http_server]
# Web管理界面设定
port=0.0.0.0:9001
username = test
password = 123456

[supervisorctl]
; 必须和'unix_http_server'里面的设定匹配
serverurl = unix:///var/run/supervisord.sock

[supervisord]
logfile=/var/log/supervisord/supervisord.log ; (main log file;default $CWD/supervisord.log)
logfile_maxbytes=50MB       ; (max main logfile bytes b4 rotation;default 50MB)
logfile_backups=10          ; (num of main logfile rotation backups;default 10)
loglevel=info               ; (log level;default info; others: debug,warn,trace)
pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid)
nodaemon=false              ; (start in foreground if true;default false)
minfds=1024                 ; (min. avail startup file descriptors;default 1024)
minprocs=200                ; (min. avail process descriptors;default 200)
user=root                 ; (default is current user, required if root)
childlogdir=/var/log/supervisord/            ; ('AUTO' child log dir, default $TEMP)

[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface


[program:test]
command=/usr/local/test/test
autostart = true
startsecs = 5
user = root
redirect_stderr = true
stdout_logfile = /usr/local/test/test.log

配置完毕,启动supervisord

supervisord -c /etc/supervisord.conf

supervisorctl使用说明

supervisorctl stop test 停止test进程
supervisorctl start test 启动test进程
supervisorctl restart test  重启test进程
supervisorctl stop all,停止全部进程,注:start、restart、stop都不会载入最新的配置文件

好了,就这样吧!

发表在 好文推荐, 网站架构 | 标签为 | 19 条评论

Go加密md5的封装

常用方法md5加密封装:

package main
  
import (
    "fmt"
    "crypto/md5"
    "encoding/hex"
)

func My_md5(str string)(string){
    h := md5.New()
    h.Write([]byte(str))
    sum := h.Sum(nil)
    return hex.EncodeToString(sum)
}  
func main() {
    fmt.Println(My_md5("123456"))
}

发表在 好文推荐, 网站开发 | 标签为 | 21 条评论

Golang时间格式化–略显奇葩

一般来说,时间格式是每个语言必备的基础功能。大部份采用”%Y-%m-%d %H:%M:%S”这样的方式来格式化。而Go语言的方式则略显奇葩,采用的是”2006-01-02 15:04:05″

package main
  
import (
    "fmt"
	"time"
)
  
func main() {
	
	//获取当前时间戳
	fmt.Println(time.Now().Unix())
	
	//时间戳转换为字符串
   	t := time.Unix(1362984425, 0)
	nt := t.Format("2006-01-02 15:04:05")
	fmt.Println(nt)
	
	//字符串转换为时间戳--第一个参数是格式,第二个是要转换的时间字符串
	tm, _ := time.Parse("2006-01-02 15:04:05", "2013-03-11 14:47:05")
	fmt.Println(tm.Unix())
	
   
}

如果大家感觉不容易记的话,可以这样记123456.

2006是go语言在google内部谋划的日子,后面依次是1、2、3、4、5的顺序表示

发表在 好文推荐, 网站开发 | 标签为 | 17 条评论

php操作mongodb3.0以上的注意事项

mongodb3.0与PHP操作的注意事项:

1:一定要先创建好相应的库和对应权限的账号。操作如下:

use test
db.createUser({user: "test",pwd: "test123456",roles: [{ role: "readWrite", db: "test" }]})

2:然后测试确认是否用mongodb3.0的客户端是否可以连接上。命令如下:

mongo  --host 127.0.0.1 -u test -p --authenticationDatabase test --port 3717

3:用PHP连接,请确保mongo的扩展是1.6.12以上.代码如下:

<?php
date_default_timezone_set('Etc/GMT-8');
$connection = new MongoClient("mongodb://test:test123456@127.0.0.1:3717/test");
$db = $connection->test;//切换到操作的库
$collection = $db->test;//切换到表
for ( $i = 0; $i < 100; $i++ )
{
    $collection->insert( array( 'username' => $i, "userpwd" => time().rand(111,999),'time' => date('Y-m-d H:i:s') ) );
}

基本这样就可以保证终端和PHP程序来操作数据库!

发表在 网站开发 | 21 条评论

利用openresty来记录请求响应日志–方便调试程序

    一般来说,nginx的日志只能记录请求相关信息和响应时间,要想将响应信息记录下来,只能在程序中扩展功能,而这次,我们通过openresty来记录响应内容,这样的好处是不影响业务功能,又增加了日志,方便查看问题!

    首先在nginx.conf中配置如下关键信息

log_format log2 '$remote_addr - - $time_local - - $request_method - -  $request_uri - - $status - - $request_time - - "$request_body" - - "$resp_body"';
log_escape_non_ascii off;

 

  日志分别记录的是

 请求IP
 请求时间
 请求方法
 请求url
 响应状态吗
 执行时间
 post内容
 响应内容

 然后在需要配置日志的server中配置如下关键信息

set $resp_body "";
lua_need_request_body on;
body_filter_by_lua_file  lua/log_by.lua;
access_log  /usr/local/openresty/test/logs/access_test.log  log2;

log_by.lua文件内容如下

local chunk, eof = ngx.arg[1], ngx.arg[2]
local buffered = ngx.ctx.buffered
if not buffered then
    buffered = {}
    ngx.ctx.buffered = buffered
end
if  chunk ~= "" then
    buffered[#buffered + 1] = chunk
    ngx.arg[1] = nil
end
if eof then
    local whole = table.concat(buffered)
    ngx.ctx.buffered = nil
    ngx.arg[1] = whole
    ngx.var.resp_body = ngx.arg[1]
end

一般,这样的情况下,记录日志的功能就配置好了,但由于我们的后端是PHP,接口输出的json中文会乱码显示,非常的不方便!因此我们又简单写了个分析日志工具来更方便的查看日志,PHP代码如下:
 

#!/usr/bin/php
<?php
error_reporting(0);
function encode_json($str) {
    return urldecode(json_encode(url_encode($str)));
}

function url_encode($str) {
    if(is_array($str)) {
        foreach($str as $key=>$value) {
            $str[urlencode($key)] = url_encode($value);
        }
    } else {
        $str = urlencode($str);
    }

    return $str;
}
$need_list = array("\\x22","\\x0A","\\x09","\\x5Cu");
$replace_list = array('"',"\n","\t","\u");
$handle = popen("tail -f /usr/local/openresty/test/logs/access_test.log 2>&1", 'r');
while(!feof($handle)) {
     $line_str = fgets($handle);
     $line_arr = explode("- -", $line_str);
     echo trim($line_arr[0])."\r\n";
     echo trim($line_arr[1])."\r\n";
     echo trim($line_arr[2])."\r\n";
     echo trim($line_arr[3])."\r\n";
     echo trim($line_arr[4])."\r\n";
     echo trim($line_arr[5])."\r\n";
     $request = trim($line_arr[6]);
     $request = str_replace($need_list,$replace_list,$request);
     echo urldecode($request)."\r\n";
     $res = trim($line_arr[7]);
     $res = str_replace($need_list,$replace_list,$res);
     $res = trim($res,'"');
     echo encode_json(json_decode($res,true))."\r\n\r\n";

}
pclose($handle);

这样当接口出现问题的时候,可以方便的查看当时的请求内容和响应内容,更容易的查找问题,最后附上查看日志截图!

发表在 网站开发 | 标签为 , , , | 21 条评论

limits.conf设置错误导致Linux系统无法ssh登陆

昨天晚上遇到服务器重启后,ssh无法连接上的问题,折腾了一个多小时也没找到问题,这其间通过不断尝试还原备份的几次镜像也无法成功。

最后,竟然发现是一个小小的配置引起的,以后重启服务器要慎重。

/etc/security/limits.conf
* soft nofile 65535
* hard nofile 65535

参数值不宜过大,总结如下:

nofile是有一个上限的,不能超过(/proc/sys/fs/nr_open,默认1048576)的值.如果超过,很可能重启之后无法ssh远程连接

可参考相关文章:

Linux—进程句柄限制总结

怎样增大 Linux 系统的 open file(s) 上限

构建C1000K的服务器(1) – 基础

发表在 好文推荐, 福利分享 | 17 条评论

openresty–redis–srcache缓存的应用

先简单介绍下使用的模块

srcache-nginx-module 是nginx下的一个缓存模块,可参见官方文档 https://github.com/openresty/srcache-nginx-module

lua-resty-redis 是openresty下操作redis的模块,可参见官方文档 https://github.com/openresty/lua-resty-redis

先简单说下我要做的事情

对于CDN,大家都非常熟悉,一般用于静态资源,将真实的响应缓存在离用户最近的节点上。而我想做的就是利用srcache和redis将真实的内容缓存在redis中,这样可以大大减轻真实后端服务的压力,提高访问性能!

openresty主配置文件如下:

server {

        resolver 10.202.72.118 10.202.72.116;
        
        location  /cache/content {
                internal;
                content_by_lua_file lua/content.lua;
        }

        location  /cache/failover {
                internal;
                content_by_lua_file lua/failover.lua;
        }
        
        #用于清除缓存
        location ~ /clearcache(/.*) {
                content_by_lua_file lua/clear_cache.lua;
        }
        
        #无缓存的PHP程序
        location ~ /nocache(.*) {
                fastcgi_pass  127.0.0.1:9000;
                fastcgi_param PATH_INFO $fastcgi_path_info;
                fastcgi_split_path_info ^(.+\.php)(.*)$;
                fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
                include fastcgi.conf;
        }
        
        location ~ .*\.(php|php5)?$
        {
                srcache_ignore_content_encoding on;

                set $cache_key "";
                set $cache_expire "";
                set $cache_fetch_skip 1;
                set $cache_store_skip 1;

                rewrite_by_lua_file lua/rewrite.lua;

                srcache_fetch_skip $cache_fetch_skip;
                srcache_store_skip $cache_store_skip;

                srcache_fetch GET /cache/content key=$cache_key;
                srcache_store PUT /cache/content key=$cache_key&expire=$cache_expire;

                add_header X-SRCache-Fetch-Status $srcache_fetch_status;
                add_header X-SRCache-Store-Status $srcache_store_status;

                #add_header srcache_fetch_skip $cache_fetch_skip;
                #add_header srcache_store_skip $cache_store_skip;


                fastcgi_pass  127.0.0.1:9000;
                fastcgi_param PATH_INFO $fastcgi_path_info;
                fastcgi_split_path_info ^(.+\.php)(.*)$;
                fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
                include fastcgi.conf;

                client_max_body_size    800m;
                client_body_buffer_size 128k;

                fastcgi_connect_timeout 3600;
                fastcgi_send_timeout 3600;
                fastcgi_read_timeout 3600;
                fastcgi_buffer_size 1024k;
                fastcgi_buffers 32 1024k;
                fastcgi_busy_buffers_size 2048k;
                fastcgi_temp_file_write_size 2048k;
        }

        location / {
                try_files $uri $uri/ /index.php$is_args$args;
        }
}

 

rewrite.lua文件内容如下

local cache_url_list= {
                        {
                        ["url"] ="/cache1.php",
                        ["expire"] ="3600",
                        },
                        {
                        ["url"] ="/cache2.php",
                        ["expire"] ="600",
                        },
                      }

local request_uri_without_args = ngx.re.sub(ngx.var.request_uri, "\\?.*", "")
for i, v in ipairs(cache_url_list) do
        if v["url"] == request_uri_without_args then
                local key = {ngx.var.request_method, " ",ngx.var.scheme, "://",ngx.var.host, request_uri_without_args,}
                local args = ngx.req.get_uri_args()
                query = ngx.encode_args(args)
                if query ~= "" then
                        key[#key + 1] = "?"
                        key[#key + 1] = query
                end
                key = table.concat(key)
                key = ngx.md5(key)
                ngx.var.cache_key = key
                ngx.var.cache_expire = v["expire"]
                ngx.var.cache_fetch_skip = 0
                ngx.var.cache_store_skip = 0
                break
        end
end

content.lua文件内容如下:

local redis = require "resty.redis"
local red = redis:new()
red:set_timeout(1000)
local ok, err = red:connect("192.168.1.123", 6379)
if not ok then
        ngx.log(ngx.ERR, err)
        return
end
local count,err = red:get_reused_times()
if 0 == count then
    ok, err = red:auth("123456")
    if not ok then
        ngx.log(ngx.ERR, err)
        return
    end
elseif err then
    ngx.log(ngx.ERR, err)
    return
end
red:select(14)
local method = ngx.req.get_method()
if method == "GET" then
    local key = ngx.var.arg_key
    local res, flags, err = red:get(key)
    if err then
        ngx.log(ngx.ERR, err)
        ngx.exit(ngx.HTTP_SERVICE_UNAVAILABLE)
    end
    if res == nil and flags == nil and err == nil then
        ngx.exit(ngx.HTTP_NOT_FOUND)
    end
    ngx.print(res)
elseif method == "PUT" then
    local value = ngx.req.get_body_data()
    local expire = ngx.var.arg_expire or 60
    local key = ngx.var.arg_key
    local ok, err = red:set(key, value)
    if not ok then
        ngx.log(ngx.ERR, err)
        ngx.log(ngx.ERR,key..value)
        ngx.exit(ngx.HTTP_SERVICE_UNAVAILABLE)
    end
    red:expire(key,expire)
else
    ngx.exit(ngx.HTTP_NOT_ALLOWED)
end
local ok, err = red:set_keepalive(10000, 100)
    if not ok then
        ngx.log(ngx.ERR, err)
    return
end

failover.lua文件内容如下

ngx.header.content_type = 'text/html;charset=utf-8';
ngx.say("cache error")

clear_cache.lua文件内容如下
 

ngx.header.content_type = 'text/html;charset=utf-8'
local redis = require "resty.redis"
local red = redis:new()
red:set_timeout(1000)
local ok, err = red:connect("192.168.1.123", 6379)
if not ok then
        ngx.say(err)
        return
end
local count,err = red:get_reused_times()
if 0 == count then
    ok, err = red:auth("123456")
    if not ok then
        ngx.say(err)
        return
    end
elseif err then
    ngx.say( err)
    return
end
red:select(14)
local request_uri_without_args = ngx.re.sub(ngx.var.request_uri, "\\?.*", "")
request_uri_without_args = ngx.re.gsub(request_uri_without_args,"/clearcache","")
local key = {ngx.var.request_method, " ",ngx.var.scheme, "://",ngx.var.host, request_uri_without_args,}
local args = ngx.req.get_uri_args()
local query = ngx.encode_args(args)
if query ~= "" then
        key[#key + 1] = "?"
        key[#key + 1] = query
end
key = table.concat(key)
key = ngx.md5(key)
ok,err = red:exists(key)
if  ok ~= 1 then
    ngx.say("此地址没有缓存")
    return
end
ok, err = red:del(key)
if not ok then
    ngx.say("缓存删除失败")
    return
end
ngx.say("缓存删除成功");

ok, err = red:set_keepalive(10000, 100)
    if not ok then
        ngx.log(ngx.ERR, err)
    return
end

这样,我们就可以通过修改rewrite.lua中cache_url_list来操作那些url需要缓存和缓存时间,要想清除缓存只要在缓存的具体url中增加/clearcache即可。
只是简单实现了其功能,还有许多需要完善的地方,不过这样的应用,对于提高接口性能应该还是效果很好的。

自己的测试如下:

nocache_1.php代码如下

<?php
echo "Hello World".time(111111,6666666);

ab -c 100 -n 10000 http://127.0.0.1/nocache_1.php

访问有缓存的结果
cache1.php代码如下

<?php
echo "Hello World".time(111111,6666666);

ab -c 100 -n 10000 http://127.0.0.1/cache1.php

效果还是很明显的,翻了一倍。而有缓存的结果操作了redis,redis在其他主机上,有网络IO,而无缓存PHP直接输出的,没有任何网络IO.电脑配置4核8G内存阿里云主机,centos6版本64位系统.

本方并不是比较openresty+lua和nginx+php的性能对比,而是提供一个思路,用openresty在做代理的时候,除了fastcgi_cache之外,还可能有更好方式来做些其他灵活的事情!

发表在 好文推荐, 网站架构 | 标签为 , | 31 条评论

openresty替换响应内容中http为https–replace-filter-nginx-module的使用

首先不知道openresty为何物的,可自行google!

问题:我们有一个网站,开始用的是http协议的,由于历史原因,路径写在各个地方,比较混乱。现在想启用https协议,可是现在的浏览器不充计https协议下加载http协议的样式,脚本等。

方案1: 将代码中的http全部修改成https,工作量比较大,并且风险太高

方案2: 在程序的输出到时,统一替换,这个虽然相对不错,不过感觉还是有点麻烦,把不属于业务的功能放到了业务代码上

方案3:   在web服务器上做统一替换,这也是我们最终决定的方案,我们选用openresty来做统一替换功能.

安装:

    

cd /opt/
yum install readline-devel pcre-devel openssl-devel gcc
wget https://openresty.org/download/ngx_openresty-1.9.7.1.tar.gz
git clone https://github.com/openresty/sregex.git
git clone https://github.com/openresty/replace-filter-nginx-module.git
cd  sregex
make
make install
cd ..
tar -zxvf ngx_openresty-1.9.7.1.tar.gz
cd ngx_openresty-1.9.7.1
./configure --with-luajit --add-module=/opt/replace-filter-nginx-module/ --with-debug
gmake
gmake install

这样openresty就算安装完毕,默认安装在/usr/local/openresty。

配置如下:

mkdir /usr/local/openresty/test
cd /usr/local/openresty/test
mkdir logs/ conf/

//在conf目录下创建一个文本文件作为配置文件,命名为nginx.conf

worker_processes  1;
error_log logs/error.log debug;
events {
    worker_connections 1024;
}
http {
    server {
        root            /alidata/www/test;
        index           index.php;
        charset         utf-8;
        server_name     test.xxx.com;
        listen          80;

        rewrite ^/(.*) https://$server_name/$1 permanent;    #跳转到Https

    }
    server {
        root            /alidata/www/test;
        index           index.php;
        charset         utf-8;
        server_name     test.xxx.com;
        listen          443;

        replace_filter 'http://test.xxx.com' 'https://test.xxx.com' 'ig';
        replace_filter 'http://(\d+).gravatar.com' 'https://$1.gravatar.com' 'ig';
    }
}

写一shell来start,stop,reload

  start.sh

 

#!/bin/bash
/usr/local/openresty/nginx/sbin/nginx -p /usr/local/openresty/test -c conf/nginx.conf

stop.sh

#!/bin/bash
/usr/local/openresty/nginx/sbin/nginx -p /usr/local/openresty/test -c conf/nginx.conf -s stop

reload.sh

#!/bin/bash
/usr/local/openresty/nginx/sbin/nginx -p /usr/local/openresty/test -c conf/nginx.conf -s stop

总结:

  

  通过这样简单的配置,我们就成功实现了将响应中的内容替换了,还是蛮方便的!

发表在 网站开发 | 标签为 , | 16 条评论