分类 Linux 下的文章

redis-2.6安装

在使用redis2.4和redis2.6过程中,发现一个问题,在redis-cli里输入 keys * 参看键值的时候,2.4版本会卡住,应该是阻塞的,2.6就不是,留个笔记吧。。。

#!/bin/bash

wget http://download.redis.io/releases/redis-2.6.16.tar.gz
tar zxvf redis-2.6.16.tar.gz
cur_dir=$(pwd)
cd redis-2.6.16
make
cp src/redis-server /usr/sbin/
cp src/redis-cli /usr/bin/
cp utils/redis_init_script /etc/init.d/redis
curl -L https://bitbucket.org/ptylr/public-stuff/raw/41d5c8e87ce6adb34aa16cd571c3f04fb4d5e7ac/etc/init.d/redis > /etc/init.d/redis
mkdir -p /etc/redis
mkdir -p /var/redis
mkdir -p /var/lib/redis
mv ${cur_dir}/redis.conf /etc/
redis-server /etc/redis.conf

redis.conf配置文件在附件redis

Nginx反向代理和php解析配置

Nginx纯反向代理配置

upstream  firefoxbug{
        ip_hash; 
        server 10.161.171.87:80;
        server 10.160.55.81;
        server 10.160.55.93;
}

server {
    server_name         www.firefoxbug.net firefoxbug.net;
    listen              80;
    gzip                on;


    error_log           /home/logs/www_firefoxbug_net_error.log error;
    access_log          /home/logs/www_firefoxbug_net_access.log;

    ## Bypass For All
    location / {
        proxy_redirect      off;
        proxy_pass          http://firefoxbug; 
        proxy_set_header Host   $host;
        proxy_set_header    X-Real-IP       $remote_addr;
        proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

- 阅读剩余部分 -

OpenCDN流量采集bug修复

OpenCDN节点端Nginx把节点流量信息以下面这种格式输出到管道bandwidth.pipe。

nginx.conf
log_format  bandwidth   '[$time_local] $host $body_bytes_sent $upstream_cache_status';

vhost配置
access_log /usr/local/opencdn/pipe/bandwidth.pipe bandwidth;

在管道的另一段读取流量信息,然后输出到下面的文件里(shell守护)
/usr/local/opencdn/stream/域名/
-| year_month_day_hour_minute
比如
/usr/local/opencdn/stream/www_firefoxbug_net
2013_Sep_30_12_10

管控端采集流量就是通过守护,以http://%s:%s/ocdn/stream?token=%s&domain=%s来抓取流量,处理后导入数据库。

之前OpenCDN产生一个小需求,使用CDN加速的小伙伴们添加了一个域名比如是aaa.com,但是他还加了别名,xxx.aaa.com(可以是二级域名)。OpenCDN节点端会在Nginx的vhost配置server_name加一个aliasname。但是小伙伴访问都是用这个aliasname访问的。而根据上面的逻辑管控端就没有办法采集到aliasname的流量。
怎么办?在节点端加对域名的流量路径加个软链接就可以,那么aliasname访问的流量也会记录到原站点的流量下。

中间还遇到一个小问题

$ mkdir test1
$ ln -s test1 test2
$ [ -L test2 ] ; echo $?
0
$ [ -L test2/ ] ; echo $?
1

为什么测试目录链接文件加/和没加/有区别呢?得@smallfish指点,大概明白了。软链接是新建一个inode节点的,这个inode节点对应的block记录的是原目录的路径,从软链接到原目录路径其实是比正常访问多一层的。我想linux的设计就是加/来区别吧,没加/那么就是读取普通的目录文件一样,加了/就是change到原路径里去了。

Python QQ纯真库解析

QQWry.Dat不是普通的txt文件,所以python解析要特定的程序。下面是一个Python类

#!/usr/bin/python
# -*- coding: UTF-8 -*-

# author : firefoxbug
# E-Mail : wanghuafire@gmail.com
# Blog   : www.firefoxbug.net

import sys
import socket
from struct import pack, unpack

class IPInfo(object):
    '''QQWry.Dat数据库查询功能集合
    '''
    def __init__(self, dbname):

        self.dbname = dbname
        f = file(dbname, 'r')
        self.img = f.read()
        f.close()

        (self.firstIndex, self.lastIndex) = unpack('II', self.img[:8])
        self.indexCount = (self.lastIndex - self.firstIndex) / 7 + 1

    def getString(self, offset = 0):
        o2 = self.img.find('\0', offset)
        gb2312_str = self.img[offset:o2]
        try:
            utf8_str = unicode(gb2312_str,'gb2312').encode('utf-8')
        except:
            return '未知'
        return utf8_str

    def getLong3(self, offset = 0):
        s = self.img[offset: offset + 3]
        s += '\0'
        return unpack('I', s)[0]

    def getAreaAddr(self, offset = 0):
        ''' 通过给出偏移值,取得区域信息字符串,'''

        byte = ord(self.img[offset])
        if byte == 1 or byte == 2:
            p = self.getLong3(offset + 1)
            return self.getAreaAddr(p)
        else:
            return self.getString(offset)

    def getAddr(self, offset, ip = 0):
        img = self.img
        o = offset
        byte = ord(img[o])

        if byte == 1:
            return self.getAddr(self.getLong3(o + 1))

        if byte == 2:
            cArea = self.getAreaAddr(self.getLong3(o + 1))
            o += 4
            aArea = self.getAreaAddr(o)
            return (cArea, aArea)

        if byte != 1 and byte != 2:

            cArea = self.getString(o)
            o = self.img.find('\0',o) + 1
            aArea = self.getString(o)
            return (cArea, aArea)

    def find(self, ip, l, r):
        ''' 使用二分法查找网络字节编码的IP地址的索引记录'''
        if r - l <= 1:
            return l

        m = (l + r) / 2
        o = self.firstIndex + m * 7
        new_ip = unpack('I', self.img[o: o+4])[0]
        if ip <= new_ip:
            return self.find(ip, l, m)
        else:
            return self.find(ip, m, r)

    def getIPAddr(self, ip):
        ip = unpack('!I', socket.inet_aton(ip))[0]
        i = self.find(ip, 0, self.indexCount - 1)
        o = self.firstIndex + i * 7

        o2 = self.getLong3(o + 4)

        (c, a) = self.getAddr(o2 + 4)
        return (c, a)

    def output(self, first, last):
        for i in range(first, last):
            o = self.firstIndex +  i * 7
            ip = socket.inet_ntoa(pack('!I', unpack('I', self.img[o:o+4])[0]))
            offset = self.getLong3(o + 4)
            (c, a) = self.getAddr(offset + 4)
            print "%s %d %s/%s" % (ip, offset, c, a)

'''search ip and its'localtion '''
def search_ip(ip_instance,ipaddr):
    if ipaddr :
        try :
            (c, a) = ip_instance.getIPAddr(ipaddr)
            print '%s/%s'%(c,a)
        except :
            print 'Unknow/Unknow'

if __name__ == '__main__':
    ip_instance = IPInfo('./QQWry.Dat')
    search_ip(ip_instance,"8.8.8.8")

纯真库优势就是可以精确到公司,街道,网吧,但是有麻烦的一点就是统计起来不方便,因为都是一个字符串,需要再做分词。

理解inode

转自 http://www.ruanyifeng.com/blog/2011/12/inode.html

inode是一个重要概念,是理解Unix/Linux文件系统和硬盘储存的基础。

我觉得,理解inode,不仅有助于提高系统操作水平,还有助于体会Unix设计哲学,即如何把底层的复杂性抽象成一个简单概念,从而大大简化用户接口。

下面就是我的inode学习笔记,尽量保持简单。

- 阅读剩余部分 -

logstash+kibana3 GeoIP地理位置

原日志从logstash输入,根据filter匹配或者修改,通过json输出到elasticsearch,然后到kibana3。所以要显示地理位置,要在logstash里面设置。logstash的jar包默认应该是有GeoIP的包的。下面是配置,pattern主要是针对Nginx的combined日志格式

log_format  access  '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" '   '"$http_user_agent"

filter {
grok {
        type => "linux-syslog"
        pattern => "%{IPORHOST:source_ip} - %{USERNAME:remote_user} \[%{HTTPDATE:time_local}\] %{QS:request} %{INT:status} %{INT:body_bytes_sent} %{QS:http_referer} %{QS:http_user_agent}
}
geoip {
   source => "source_ip"
   type => "linux-syslog"
   add_tag => [ "geoip" ]
#   database => "/var/geoip/GeoLiteCity.dat" 不是必须
}
}

kibana5

- 阅读剩余部分 -

logstash+kibana3搭建

之前玩过一段时间的logstash+kibana3,还有elasticsearch。但是困于libana安装环境的复杂,自从kibana3出来之后就方便了很多,对于logstash的版本也会有一些问题。

logstash


yum install java-1.6.0*
wget https://download.elasticsearch.org/logstash/logstash/logstash-1.2.1-flatjar.jar
mkdir -p /usr/local/bin/logstash/
mkdir -p /etc/logstash/
cd /usr/local/bin/logstash/ && ln -s ./logstash-1.2.1-flatjar.jar ./logstash.jar

编辑logstash的配置文件

- 阅读剩余部分 -

Linux Cache和Buffers

之前在写日志模块的sql语句处理模块过程中,大概一次性插入一万多条数据到Mysql,结果top出来used内存很大,而且一直都不释放那部分内存,就很奇怪一直没有找到问题,开始还以为python哪部份内存没释放好,但是总觉得释放内存是python自己搞定的。也测试过Mysql连接数,都是正常。后来请教了下大牛,才知道原来top出来还是大有文章的。

- 阅读剩余部分 -

僵尸进程处理

写日志模块的时候处理sql语句用了子进程,结果子进程比父进程预先退出了,导致生成了一大堆的僵尸进程。原因我猜想就应该是子进程退出的时候给父进程发送信号,等待父进程进行资源回收。可是父进程没有对该信号做相应的处理导致子进程一直等待,变成了僵尸进程。所以要做的就是在父进程生成子进程之前设置下对于子进程信号的处理,可以忽略。

import signal
signal.signal(signal.SIGCHLD,signal.SIG_IGN)

其实现在比较新的内核版本的话可以用wait就解决了。

Nginx Cache中$request_filename

对于Nginx的$request_filename变量指的就是请求的资源路径。在原先OpenCDN节点端配置里面是这样的。

location ~ .*\.(png|html|htm|ico|jpg|jpeg|bmp|gif|js|css)$ {
        ## 忽略浏览器的缓存
        proxy_ignore_headers Cache-Control;
        proxy_ignore_headers Expires;

        proxy_cache cache_one;
        proxy_cache_valid 200 304 1h;

        proxy_cache_key $host$uri$is_args$args;
        expires 1h;
        ## 此处为host锁定,可定制有无
        proxy_set_header        Host    $host;

        add_header OpenCDN-Cache "$upstream_cache_status";

       if (!-f $request_filename) {
                proxy_pass http://ocdn_www.firefoxbug.net;
                break;
        }
}

- 阅读剩余部分 -

Nginx源码分析核心模块加载

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

之前一篇Nginx源码分析模块加载大概描述了Nginx官方定义的6个核心模块,本文再详细介绍这几类模块的加载。这些核心模块都属于宏NGX_CORE_MODULE,对应的模块上下文配置结构体是 ngx_core_module_t。

typedef struct {
    ngx_str_t             name;                                         //模块名,即ngx_core_module_ctx结构体对象的
    void               *(*create_conf)(ngx_cycle_t *cycle);             //解析配置项,nginx框架会调用create_conf方法
    char               *(*init_conf)(ngx_cycle_t *cycle, void *conf);   //解析配置项完成后,nginx框架会调用init_conf方法
} ngx_core_module_t;

NGX_CORE_MODULE这6类核心模块都用ngx_core_module_t接口定义上下文。

- 阅读剩余部分 -

Nginx代理被墙域名

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

今天一用户想用OpenCDN使用被墙域名,所谓被墙域名和未备案域名还是有区别的。域名被墙,是指被中国的GFW防火墙屏蔽,使用域名访问时,出现连接重置的情况。我猜想就是GFW把HTTP的URL和Host字段进行过滤,所以某个域名的包都被deny了,但是可以通过Nginx反向代理来解决这个问题。下面大概说明下

www.ooxx.com是被墙域名
源站IP是192.168.1.1(国外)
反代NginxIP是192.168.2.1(国内)

- 阅读剩余部分 -

Nginx源码分析模块指令加载

上文写到了Nginx配置文件读取以及解析,本文介绍模块的指令加载。还是以前文的nginx_move_domain_cache为例

server {
        listen 80;
        server_name www.firefoxbug.net;
        gzip on;
 
        location /mv_cache{
                mv_cache;
        }
        ....
}

上面有一模块mv_cache,这个模块里面的指令是mv_cache,参数是0个。再比如server_name也是一个指令,参数是一个"www.firefoxbug.net"。调用前文的ngx_conf_parse读取配置文件,然后调用handler函数进行解析,对于普通的处理(普通指令),会调用ngx_conf_handler,这里再回顾下模块的指令数组定义结构

- 阅读剩余部分 -

Nginx源码分析模块加载

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

前文说了Nginx里万物皆模块,今天描述下模块的加载,因为模块的加载是一个递归的过程,所以比较难以理解。

模块类型


Nginx官方定义了6种核心模块,定义宏声明是NGX_CORE_MODULE,分别是ngx_core_module,ngx_http_module,ngx_events_module,ngx_mail_module,ngx_errlog_module,ngx_openssl_module。这6种核心模块又可以定义自己全新的模块,比如ngx_events_module重新定义events类型为NGX_EVENT_MODULE,ngx_http_module定义http模块类型NGX_HTTP_MODULE。在上文叙述的ngx_command_s第二个字段就是指定这些模块类型。

- 阅读剩余部分 -

Nginx源码分析模块化

断断续续读了近半个多月Nginx的源码,感觉还是比较吃力,因为Nginx模块化的设计带来的是复杂的结构体以及回调函数,逻辑比较复杂。到现在也不知道改怎么写好Nginx源码分析这类博客,但是只能硬着头皮去写,希望写的过程中能出现各种疑问从而解决。目前还没完整地读完源码,按照Nginx执行顺序写还力不从心,所以先从如何编写三方模块开始。

在之前一篇文章写了一个Nginx删除域名Cache的三方模块 http://www.firefoxbug.com/?p=1985,Nginx源码分析就从这个模块进行分析。至于什么是模块?我们从Nginx的配置文件出发来解释。

- 阅读剩余部分 -

LVS概述

refer:http://snmlab.cs.nchu.edu.tw/CloudLab/CTSP/Lab7.html

今早X哥告诉我说他需要传10G/S的数据,我顿时就瞎了,他叫我给出下LVS的描述,我总结了下。

NAT


网络环境:LVS调度器两个网卡,一个公网IP,一个内网IP,限制于一个LAN里面。
原理:数据包到最前面的调度器(公网IP),转发到内网的机器群(内网IP),内部服务器相应完成后转发回调度器,调度器回到客户端。
总结:数据包都流经四层,调度器会是瓶颈,进出流量都经过调度器。

- 阅读剩余部分 -

Nginx一键清除域名下Cache

装载请注明出处:http://www.firefoxbug.com/?p=1985
在前面一篇文章 http://www.firefoxbug.com/?p=1861 已经介绍如何把站点缓存分域名存放。相比之前的purge一个个URL刷新,按照域名存放对于站点Cache一键刷新是很方便的。本文会介绍如何通过开发一个Nginx三方模块,一键刷新某个域名站点下缓存。 注意:在使用下面模块之前必须根据前文,站点Cache已经按照目录存储,目录在 /home/cache/下。比如 www.firefoxbug.net 的 Cache 是 /home/cache/www.firefoxbug.net/ ,通过模块能一键清除此目录cache。

- 阅读剩余部分 -