日志

大数据的技术生态圈

本文来源知乎一个题为“如何用形象的比喻描述大数据的技术生态?”的精彩回答

大数据本身是个很宽泛的概念,Hadoop生态圈(或者泛生态圈)基本上都是为了处理超过单机尺度的数据处理而诞生的。你可以把它比作一个厨房所以需要的各种工具。锅碗瓢盆,各有各的用处,互相之间又有重合。你可以用汤锅直接当碗吃饭喝汤,你可以用小刀或者刨子去皮。但是每个工具有自己的特性,虽然奇怪的组合也能工作,但是未必是最佳选择。

大数据,首先你要能存的下大数据

传统的文件系统是单机的,不能横跨不同的机器。HDFS(Hadoop Distributed FileSystem)的设计本质上是为了大量的数据能横跨成百上千台机器,但是你看到的是一个文件系统而不是很多文件系统。比如你说我要获取/hdfs/tmp/file1的数据,你引用的是一个文件路径,但是实际的数据存放在很多不同的机器上。你作为用户,不需要知道这些,就好比在单机上你不关心文件分散在什么磁道什么扇区一样。HDFS为你管理这些数据。

存的下数据之后,你就开始考虑怎么处理数据

虽然HDFS可以为你整体管理不同机器上的数据,但是这些数据太大了。一台机器读取成T上P的数据(很大的数据哦,比如整个东京热有史以来所有高清电影的大小甚至更大),一台机器慢慢跑也许需要好几天甚至好几周。对于很多公司来说,单机处理是不可忍受的,比如微博要更新24小时热博,它必须在24小时之内跑完这些处理。那么我如果要用很多台机器处理,我就面临了如何分配工作,如果一台机器挂了如何重新启动相应的任务,机器之间如何互相通信交换数据以完成复杂的计算等等。这就是MapReduce / Tez / Spark的功能。MapReduce是第一代计算引擎,Tez和Spark是第二代。MapReduce的设计,采用了很简化的计算模型,只有Map和Reduce两个计算过程(中间用Shuffle串联),用这个模型,已经可以处理大数据领域很大一部分问题了。

那什么是Map什么是Reduce?

阅读全文

日志

PHP基于pcntl的多进程编程

PHP可以通过PHP的进程控制函数(PCNTL)实现多进程,要注意的是,PCNTL只在UNIX LIKE OS下有效,windows是不支持的,另外如果你在编译时没有加入这个扩展则需要自行安装.

pcntl_fork

首先我们需要了解一个非常重要的函数,pcntl_fork().

pcntl_fork —— 在当前进程当前位置产生分支(子进程).fork创建了一个子进程,父进程和子进程都从fork的位置开始向下继续执行,不同的是父进程执行过程中,得到的fork返回值为子进程号(PID),而子进程得到的是0.通过fork创建的子进程可以看成是父进程的一个拷贝,无论是数据空间还是指令指针都完全一致,但从fork之后开始这两个父子进程就再也没有任何继承关系,两者可以看成是两个独立的进程,而fork返回值的差异可以作为父子进程的区分,也是多进程编程实现的关键.另外,如果fork失败,则会返回-1.

Talk is cheap show me the code:

#!/usr/bin/env php
<?php
date_default_timezone_set("asia/shanghai");

$pid = pcntl_fork();
if ($pid==-1) {
    die('fork失败');
} else if ($pid==0) {
    //子进程执行
    $sec = 10;
    echo date('H:i:s') .'| 我是子进程 (PID:' . posix_getpid() . ')' . ',我休眠' . $sec . '秒后结束' . PHP_EOL;
    
} else if ($pid>0) {
    //父进程执行
    $sec = 15;
    echo date('H:i:s') . '| 我是父进程 (PID:' . posix_getpid() . '),我创建了一个子进程 (PID:' . $pid . ')' . ',我休眠' . $sec . '秒后结束' . PHP_EOL;
}
sleep($sec);
echo date('H:i:s') . '| 进程(PID:'.posix_getpid().')结束' . PHP_EOL;
exit(0);

/**********************************输出*************************************
16:22:13| 我是父进程 (PID:28082),我创建了一个子进程 (PID:28083),我休眠15秒后结束
16:22:13| 我是子进程 (PID:28083),我休眠10秒后结束
16:22:23| 进程(PID:28083)结束
16:22:28| 进程(PID:28082)结束
****************************************************************************/

僵尸进程

阅读全文

日志

通过nginx限制连接数和请求数

有时候服务器会遭到大流量的恶意访问,这种攻击最直接的影响就是导致服务器持续高压,严重影响正常访问,导致这种情况的原因有很多,对于一些低配置的服务器可能只需要一次简单的恶意压测就可以导致服务器502.对于这种情况,我们可以考虑对相同IP的并发连接数和请求频率进行限制,nginx本身自带了两个模块可以作为解决方案,即ngx_http_limit_conn_module和ngx_http_limit_req_module.

  • ngx_http_limit_conn_module

简介:ngx_http_limit_conn_module是一个可以根据指定key来限制连接数的模块,尤其用于根据单个IP限制连接数.

语法:limit_conn_zone key zone=name:size;

上下文:http(即nginx配置的http作用域)

说明:开辟一个名为name,大小为size的共享内存区域,用于存储一系列key(s)的状态,特别是包含各个key的连接数,其中key可以是变量、文本或二者的组合(nginx 1.7.6之前只可以包含一个变量),另外1MB共享内存可以存储3.2万个32-byte状态(在32位平台中存储状态占用32bytes)或1.6万个64-byte(64位平台),当共享内存空间不足时,之后的请求会导致服务器返回503(Service Temporarily Unavailable) 错误.

语法:limit_conn zone number;

上下文:http ,server,location

说明:设置共享内存区域zone,使zone指定的key的连接数不大于number个,当超过这个number值时服务器会返回503(Service Temporarily Unavailable) 错误.

例子:设定一个名为addr的10MB共享内存,以客户端ip作为键,限制每个客户端ip最大并发连接数为5

http{
    ...
    # $binary_remote_addr是客户端ip地址,它和$remote_addr的区别在于它是固定4字节长度
    limit_conn_zone $binary_remote_addr zone=addr:10m;
    server {
    ...
        location ~ \.php$ {
            limit_conn addr 5;
        }
    ...
    }
    ...
}
  • ngx_http_limit_req_module

阅读全文

日志

Python通过正则表达式验证素数

素数:除了1和自身外没有其他因数的数称为素数,素数又被称为质数。

验证素数的正则表达式非常简单:

/^1?$|^(11+?)\1+$/

Python实现

import re
def checkPrime(n):
    return re.compile(r'^1?$|^(11+?)\1+$').match('1' * n) is None

print[x for x in range(100) if checkPrime(x)]
##########Output###############
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]

解释

该正则表达式由两部分组成,准确来说匹配两类情况:

  1. ^1?$,匹配空字符串和1 (1既不是素数也不是合数)
  2. ^(11+?)\1+$,首先(11+?)非贪婪匹配‘11’,‘111’,‘1111’…等字符串,\1+意味着再匹配至少一次(11+?)的匹配结果,^(11+?)\1+$表示“匹配n个1(n>=2)至少m次(m>=2)”,说白了就是匹配数字n*m,正则表达式会穷举定义域内的任意n*m组合情况,而根据定义可知,n和m是数字n*m的既不为1也不为自身的因数,所以如果正则成功匹配则该数是合数,反之素数
转载请注明出处:

© http://hejunhao.me

日志

Nginx通过ngx_log_if模块实现日志过滤

有时候我们需要对服务器的access日志进行自定义过滤,例如不想记录任何404的访问日志等.在Apache下我们可以通过CustomLog [env=XXX]来实现,但Nginx自身并不提供类似的功能,不过从官方的第三方模块中我们可以找到 ngx_log_if 这个非常好用的扩展模块来实现同样的功能.

  • 重编译Nginx安装第三方模块

首先你需要知道你的Nginx版本
$ nginx -v

nginx version: nginx/1.6.3

Nginx历史版本下载 点击这里

从GIT下载 ngx_log_if 模块

$  git clone https://github.com/cfsego/ngx_log_if.git
Nginx编译
<h1>假设你的nginx安装在/etc/nginx , ngx_log_if 在/usr/lib/ngx_log_if 目录</h1>

<h1>解压nginx后开始重编译</h1>

$ ./configure --prefix=/etc/nginx --add-module=/usr/lib/ngx_log_if + ...你的原编译配置

$ make

注意:在configure参数中务必把原来的编译配置补全,通过下面的命令可以知道你原来的配置

$ nginx -V

编译结束后会生成一个新的nginx,先关闭旧的nginx,然后替换新编译的nginx(假设位于/usr/sbin/nginx),重启nginx即可

$ sudo nginx -s stop

<h1>nginx路径按需要修改</h1>

$ sudo cp objs/nginx  /usr/sbin/nginx

$ sudo nginx

至此ngx_log_if模块安装完毕

  • 通过ngx_log_if进行Access日志过滤

server {
    # 不记录400响应状态的access日志
    access_log_bypass_if ($status = 400);

<pre><code># 不记录200响应状态且uri为 status.nginx 的访问日志
access_log_bypass_if ($uri = 'status.nginx') and;
access_log_bypass_if ($status = 200);
</code></pre>

}

子配置会默认覆盖父配置

server {
    # 父配置 , 无效
    access_log_bypass_if ($status = 400);

<pre><code>location / {
    # 子配置 , 有效
    access_log_bypass_if ($host ~* 'nolog.com');
}
</code></pre>

}
转载请注明出处:

© http://hejunhao.me

日志

Python的all()和any()函数的区别

any和all函数都接受一个可迭代的(iterable)对象

  • 区别

all:当迭代对象为空(empty)或迭代对象中的所有元素都为真(True)时返回True,否则返回False

any:当迭代对象不为空任意一个元素为真(True)即会返回True,否则返回False

  • 函数实现

all:

def all(iterable):
    for element in iterable:
        if not element:
            return False
    return True

any:

def any(iterable):
    for element in iterable:
        if element:
            return True
    return False
  • 例子

>>> any(['',1,2,3,False])
True
>>> any([])
False
>>> any(['',0,False])
False
>>> all(['',1,2,3])
False
>>> all([])
True
>>> all([1,2,3])
True
转载请注明出处:

© http://hejunhao.me

日志

Nginx 禁止通过IP直接访问网站

网站备案时需要禁止IP直接访问,否则会存在风险

  • Nginx配置

nginx配置非常简单,只需要添加一个空白的server即可

server{

<pre><code>server_name _;

return 444;
</code></pre>

}

你也可以跳转到你的域名

server {
    server_name _;
    rewrite ^(.*) http://www.yourdomain.com;
}
  • 关于 444 响应状态码

444状态码用于Nginx表示服务器没有任何返回信息,并且会关闭连接.

转载请注明出处:

© http://hejunhao.me

日志

Python正则表达式的使用(re模块)

正则表达式不属于任何语言本身,而是独立的用于处理字符串的强大工具,它有独立的语法和处理引擎,只要你熟悉其语法任何语言下都能使用(部分非常用语法可能在各种语言中的支持不一致)Python处理正则表达式主要用到re模块,本文主要介绍re模块的使用,正则表达式相关语法不作为本文重点

  • 相关语法参考

Python正则表达式常用语法解释

  • 关于re模块

re是 regular expression 的缩写,即正则表达式.

通过re模块使用正则表达式主要有三个过程:

  1. 编译正则表达式得到Pattern对象
  2. 通过Pattern对象匹配文本得到Match对象
  3. 从Match对象中获取匹配信息
  • re.compile(pattern[, flag]):

re.compile的第一个参数指定正则表达式字符串,第二个参数可选,用于指定匹配模式:

re.I(IGNORECASE): 忽略大小写
re.M(MULTILINE): 多行模式
re.S(DOTALL): 点任意匹配模式
re.L(LOCALE): 使预定字符类 \w \W \b \B \s \S 取决于当前区域设定
re.U(UNICODE): 使预定字符类 \w \W \b \B \s \S \d \D 取决于unicode定义的字符属性
re.X(VERBOSE): 详细模式.这个模式下正则表达式可以是多行,忽略空白字符,并可以加入注释.

该方法返回一个Pattern对象,实际上它是Pattern类的 Factory Method

  • Match对象

每个pattern匹配成功都会返回一个match对象的结果,通过它我们可以获取一次成功匹配的诸多信息

其常用的方法如下:

group([group1, …]): 返回匹配的一组或多组结果,没有则为None,其中参数group1…可以使用别名也可以使用编号,代表第n组结果,当编号为0时代表整个匹配的子串,若参数为多个则以元组形式返回,若不给参数则视为group(0)

groups([default]):返回所有组的匹配结果的元组,相当于group(1,2,3…),没有匹配到的组以default代替,默认None

groupdict([default]): 返回有别名的组的匹配结果的字典,其中别名为键,匹配子串为值

start([group]): 返回指定组的匹配子串在string中的起始索引,group默认值为0

end([group]): 返回指定组的匹配子串在string中的结束索引(最后一个字符的索引+1),group默认值为0

span([group]): 等价于(start(group), end(group))

#-*- coding:utf-8 -*-
import re
p = re.compile(r'My name is (\w+), I am (?P<age>\d+) years old , I come from (?P<city>\w+).')
m = p.match('My name is Felix, I am 10 years old , I come from Canton.')

print "group(0):", m.group(0)
print "group(1):", m.group(1)
print "groups():", m.groups()
print "groupdict():", m.groupdict()
print "start(1):", m.start(1)
print "end(1):", m.end(1)
print "span(1):", m.span(1)

##输出##
# group(0): My name is Felix, I am 10 years old , I come from Canton.
# group(1): Felix
# groups(): ('Felix', '10', 'Canton')
# groupdict(): {'city': 'Canton', 'age': '10'}
# start(1): 11
# end(1): 16
# span(1): (11, 16)
  • Pattern对象

阅读全文

日志

Python正则表达式常用语法解释

正则表达式使用单个字符串来描述、匹配一系列符合某个句法规则的字符串

  • 正则表达式的作用

  1. 给定的字符串是否符合指定正则表达式的过滤逻辑,即匹配(例如Email地址检测,电话号码合法性判断等)
  2. 根据正则表达式从指定字符串中捕获特定的信息(例如从文章中获取所有含有a字母的单词)
  • 正则表达式的特点

  1. 灵活性、逻辑性、功能性非常强大
  2. 以极简的方式控制复杂的字符串
  3. 可读性差,对初学者晦涩难懂
  • 正则表达式语法(包括Python的专用扩展)

正则表达式由普通字符和元字符两大部分组成,而元字符相当于正则表达式的游戏规则,是其灵魂所在.因此,要掌握正则表达式在表达什么,最关键的就是要弄懂它的元字符的作用规则.

一般字符

.(点号)

匹配除了换行符之外的任意字符,在DOTALL模式下可以匹配换行符

例如:a.cd 匹配 abcd
阅读全文

日志

Ubuntu14.04 搭建 LNMP 环境

  • 环境

系统:Ubuntu 14.04.1 LTS

下面所有的安装都通过apt-get的方式,为了防止安装过程报错建议先执行一次更新

sudo apt-get update
  • MySQL安装

sudo apt-get install mysql-server mysql-client

安装期间会出现类似如下的Y/N选择,直接Y 回车即可(下同)

root@li568-33:/# sudo apt-get install mysql-server mysql-client
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following extra packages will be installed:
libaio1 libdbd-mysql-perl libdbi-perl libmysqlclient18 libterm-readkey-perl
mysql-client-5.5 mysql-client-core-5.5 mysql-common mysql-server-5.5
mysql-server-core-5.5
Suggested packages:
libclone-perl libmldbm-perl libnet-daemon-perl libplrpc-perl
libsql-statement-perl tinyca mailx
The following NEW packages will be installed:
libaio1 libdbd-mysql-perl libdbi-perl libmysqlclient18 libterm-readkey-perl
mysql-client mysql-client-5.5 mysql-client-core-5.5 mysql-common
mysql-server mysql-server-5.5 mysql-server-core-5.5
0 upgraded, 12 newly installed, 0 to remove and 123 not upgraded.
Need to get 0 B/9,260 kB of archives.
After this operation, 96.5 MB of additional disk space will be used.
Do you want to continue? [Y/n]y

中途会出现新的界面设置MySQL的root用户密码

首先设置root密码:yourpassword
然后重复输入root密码:yourpassword

等安装结束后输入以下命令查看是否成功

mysql --version

正常会显示类似以下的版本信息,则安装完成

mysql  Ver 14.14 Distrib 5.5.43, for debian-linux-gnu (x86_64) using readline 6.3

mysql的配置文件在:/etc/mysql/my.cnf
例如:若要允许远程访问请注释my.cnf 的 bind_address 127.0.0.1

  • Nginx安装

阅读全文