supervisord 管理多进程程序如 pyspider 时的合适配置

2014-11-05 • Linux 笔记 • #python #pyspider #supervisord

现在的工程中,有一部分是用 pyspider 来抓取数据的,使用 supervisord 来管理它的进程。在使用过程中,遇到一个奇怪的问题:用supervisorctl stop pyspider之后,pyspider 并未全部停止,而是留下了三四个进程在系统中。

查阅官方手册,在 [program:x] Section Settings 中找到了名为 stopasgroup 的选项,解释如下:

If true, the flag causes supervisor to send the stop signal to the whole process group and implies killasgroup is true. This is useful for programs, such as Flask in debug mode, that do not propagate stop signals to their children, leaving them orphaned.

在 [program:pyspider] 小节,开启这个选项。如:

[program:pyspider]
command=/home/oott123/pyspider/run.py
autorestart=true
startsecs=2
user=oott123
directory=/home/oott123/pyspider/
redirect_stderr=true
stopasgroup=true
environment=WEBUI_HOST="127.0.0.1",WEBUI_PORT="5033"

然后重启 supervisord ,再测试停止 pyspider 的服务,它就不会残留那几个进程了。

CentOS 7 下 docker 安装拾穗

2014-10-29 • Linux 笔记 • #CentOS #docker

如何安装 docker

docker 在 CentOS 7 下已经收录到了 extras 包中,因此我们只需要执行:yum install docker 即可安装 docker。

安装后,使用systemctl start docker来启动 docker 的服务,再用systemctl enable docker来使其开机启动。顺带一提,service docker startchkconfig docker on也能达到同样的效果;但由于 CentOS 7 采用了 systemd 来管理服务和开启启动项,因此我们尽量使用 systemctl 来操作服务。

安装后输入 docker info 来查看 docker 信息。

[root@localhost data]# docker info
Containers: 0
Images: 0
Storage Driver: devicemapper
 Pool Name: docker-253:0-68161190-pool
 Data file: /var/lib/docker/devicemapper/devicemapper/data
 Metadata file: /var/lib/docker/devicemapper/devicemapper/metadata
 Data Space Used: 293.0 Mb
 Data Space Total: 102400.0 Mb
 Metadata Space Used: 0.7 Mb
 Metadata Space Total: 2048.0 Mb
Execution Driver: native-0.2
Kernel Version: 3.10.0-123.el7.x86_64

如何修改 Data file 路径

遇到的第一个问题,则是:docker 的数据都放到哪里了?显然,上面的 docker info 给了我们答案: 在/var/lib/docker/ 下。由于种种神奇的原因,我们希望尝试 修改 docker 的数据存放目录

编辑这个文件:vim /etc/sysconfig/docker,找到OPTIONS=--selinux-enabled -H fd://,修改为:OPTIONS=-g /mnt/docker0/data --selinux-enabled -H fd://。这样我们就成功的将 docker 目录修改成功了。

执行 systemctl restart docker ,再 docker info ,可以看到目录已经修改成功了。

如何使用国内的 docker 镜像源

考虑 DockerPool 这个 docker poll。

例如,我要下载 CentOS 7 的 docker 镜像,那么执行:

docker pull dl.dockerpool.com:5000/centos:centos7

镜像文件略微有点大,下得我心醉。在 DockerPoll Downloads 可以找到其它的镜像列表。

下载完成后,要把第三方 registry 的下载的文件打上 tag

docker tag dl.dockerpool.com:5000/centos:centos7 centos:centos7

如何清理 docker 容器

执行了一些简单的命令,比如docker run -t -i centos:centos7 ping baidu.com之后,再看 docker info ,发现 Containers 居然到了 4 。大惊,用 docker ps -a 查看后才知道,每次我用 docker run 的时候他都会新建一个 Container。试了下 docker rm ,一次只能删除一个。改用 docker rm $(docker ps -aq) ,成功删除它们。

参考:Docker——从入门到实践

还算比较完善的 Linux 服务器自动备份、上传脚本

2014-09-12 • Linux 笔记 • #linux #备份

脚本托管于gist,点击查看

由于内嵌会导致一定程度的网页加载阻塞,故此处内嵌并非实时版本。

#!/bin/bash
Err() { echo -ne "\e[1;31m"; Log "$@" 1>&2; echo -ne "\e[0m";}
Log() { echo $(date +"[%Y-%m-%d %H:%M:%S]") $@; }
Log ====每日备份脚本开始运行====
UPLOADER_BIN="/root/auto-scripts/bpcs_uploader/bpcs" #bpcs 上传脚本路径(见下方bpcs文件)
REMOTE_DIR=$(date +"%Y%m")/$(date +"%Y%m%d") # 远端上传路径
WORKING_DIR="/root/auto-scripts/backup_daily" # 工作路径
CONFIG_DIR=$WORKING_DIR/list.d #配置文件路径
BACKUP_DIR=$WORKING_DIR/backups #本地备份路径
CURRENT_DIR=$BACKUP_DIR/$(date +"%Y%m%d")
OLD_DIR=$BACKUP_DIR/$(date -d -3day +"%Y%m%d")
zipPassword=ChangeThePasswordToYourOwn #备份密码
#准备删除老文件
Log 删除旧备份文件夹:$OLD_DIR
rm -rf $OLD_DIR
#创建新目录
mkdir -p $CURRENT_DIR
#遍历配置目录,进行备份
for i in $(ls $CONFIG_DIR)
do
zipExclude="*/cache/* */tmp/* */temp/* */.npm/* */data/threadcache/*"
. $CONFIG_DIR/$i
Log 备份$backupDir为$i……
backupFile=$i.zip
zip -r -P $zipPassword $CURRENT_DIR/$backupFile $backupDir -x $zipExclude
Log 上传备份……
$UPLOADER_BIN upload $CURRENT_DIR/$backupFile $REMOTE_DIR/$backupFile
done
Log 备份完成!

用法懒的写,自己研究!

依赖:bpcs_uploader,以及 zip 。yum install zip

机器学习 - 第三周:逻辑回归

2014-09-11 • 原理拾穗 • #machine learning #机器学习 #coursera #ml-006

分类(Classification)问题

逻辑回归(Logistic Regression)主要是用于分类问题的。分类问题,即对数据集中的数据进行分类,区分出两个或多个类别。

例如,之前提到的邮箱判定是否为垃圾邮件的算法,即一类分类算法:区分一封邮件是垃圾邮件,或是非垃圾邮件。

处理这种问题,其实和线性回归的问题如出一辙:只需判定其属于某个分类的概率——例如某封邮件经过算法计算出为垃圾邮件的概率为 0.9 ,我们则有充分的理由认为这是一封垃圾邮件。

模型表达

继续用 $$h_\theta(x)$$ 来表示我们的假设函数。由于我们计算出的是分类的概率,则由概率论(常识),应有 $$0 \le {{\rm{h}}_\theta }(x) \le 1$$ 。但线性回归函数计算出的 $$\theta^T$$ 并不是在此范围内,我们需要选择一个函数 $$g(z)$$ ,使得 $$ 0 \le h_\theta(x) = g(\theta^T) \le 1 $$ 。

我们取下列的 $$g(z)$$ :

$$g(z) = {1 \over {1 + {e^{ - z}}}}$$

则我们的假设函数 $$h(\theta)$$ 为:

$${h_\theta }(x) = {1 \over {1 + {e^{ - {\theta ^T}x}}}}$$

函数$$g(z)$$单调递增,且$$g(0)=0.5$$、$$0 \le g(z) \le 1$$,函数图形类似积分符号“$$\int$$”,比较适合作为一个分类的假设函数。

此时 $$h_\theta(x)$$ 表示的则是“输入x时,y=1的概率”。用概率论中的条件概率表示,则是$$P(y = 1|x;\theta )$$。

决策边界(Decision boundary)

(啊突然发现真的有点不得不配图了……我还要再坚持一下!)

考虑只有两个参数:$$x_1$$、$$x_2$$的情况。将不同分类的数据集以不同符号标注在平面直角坐标系上;再将预测函数 $$h_\theta$$ 亦画出在同一个坐标系中。此时,预测函数 $$h_\theta$$ 将不同的数据集分开——这就是决策边界。

决策边境亦可以是非线性的——只需在预测函数中加入高次项。

成本函数

$$J(\theta ) = - {1 \over m}[\sum\limits_{i = 1}^m {{y^{(i)}}\log {h_\theta }({x^{(i)}}) + (1 - {y^{(i)}})\log (1 - {h_\theta }({x^{(i)}}))]} $$

总之大概就是以上这坨玩意。

当然,要用梯度下降法求它的最小值,我们需要知道它的偏导数……如下:

$${\partial \over {\partial {\theta _j}}}J(\theta ) = {1 \over m}\sum\limits_{i = 1}^m {({h_\theta }({x^{(i)}}) - {y^{(i)}})x_j^{(i)}}$$

高级优化算法(Advanced optimization)

还有一些比梯度下降法牛逼得多的算法,例如:

  • Conjugate gradient
  • BFGS
  • L-BFGS

这些算法在 MATLAB 或者 octave 里都有,我们要做的只是传入成本函数和偏导数,然后可以由内置的算法自动计算出最合适的 $$\theta$$ 值。

多类别的逻辑回归算法

在目标数据集有多个分类的情况,我们使用一种“一对多”(one vs all)的方式来计算。原理很简单,例如我们有$$n$$个分类,我们依次挑选其中的1个分类,将剩下的$$n-1$$个分类作为另一个分类来运行逻辑回归算法。

机器学习 - 第二周:多变量线性回归

2014-09-09 • 原理拾穗 • #machine learning #机器学习 #coursera #ml-006

好吧……我成功的把 coursera 的 Machine Learning 课完完全全的坑掉了…… Courera 都发信告诉我你快去 check 你的 Review questions 啦否则要不及格了!我才发现我已经完完全全的跟不上进度了哭瞎…… 估计我要跟着 ml-007 班才可能上完这门课了 QAQ 留级什么的……

于是这是多变量线性回归的总结。

多变量线性回归,其实亦是线性回归:其区别主要在于,参与回归的变量变多了,也就是要用多个因素来共同预测同一个结果。

模型表达

$${{\rm{h}}_\theta }(x) = {\theta _0} + {\theta _1}{x_1} + {\theta _2}{x_2} + ... + {\theta _n}{x_n}$$

——其实有 $$x_0$$ 的,只是它等于1,于是就没有 $$x_0$$ 了。

当然它可以用简洁大气的向量形式表示,如下:

$${{\rm{h}}_\theta }(x) = {\theta ^T}x$$

多变量的梯度下降算法

成本函数

$$J(\theta ) = {1 \over {2m}}\sum\limits_{i = 1}^m {{{({h_\theta }({x^{(i)}}) - {y^{(i)}})}^2}} $$

成本函数和单变量的并无本质区别,唯需注意:其中的 $$\theta$$ 和 $$x$$ 已经是向量。

梯度下降

梯度下降也并无区别;唯将同步更新的 $$\theta_0$$ 和 $$\theta_1$$ 变成了 $$\theta_0$$ 到 $$\theta_j$$ 而已。

特征缩放(Feature Scaling)

Google 上随便搜了下,没找着合适的中文翻译,暂且叫他特征缩放吧。其主要目的,则是让各个特征——即参与预测的参数,保持在同一个数量级上,以减少迭代的次数。

参与预测的各特征由于种种原因,其大小并不在同一个数量级上;也就是说,特征的单位往往不统一。而这会造成迭代上的问题——有的次要特征无法快速减小,以至于消耗大量的时间;而主要特征有可能无法快速上升从而达到最佳解。

而特征缩放,将所有的特征都限定在 $$ - 1 \le x \le 1$$ 的范围内,使特征都保持在同一个数量级。这样一来,梯度下降算法将会提升其效率,运行得更加快速干净。

一般我们采用如下算法:记特征的平均值为 $$\mu $$ ,而特征的范围(最大值减去最小值)为 $$s$$ ,则将以下的变量代替特征 $$x$$ 参与迭代:

$${{x - \mu } \over s}$$

学习速率(Learning rate, $$\alpha$$)

提到学习速率之前,需要先了解我们是如何处理梯度下降算法中的问题的——即,我们如何知道梯度下降算法是否正在朝我们想要的结果发展?

最简单明了的方式,就是画出迭代次数-成本函数的直角坐标系图。在每次迭代时,该图线持续下降——亦即,Jmin(t)是一个单调递减的函数。

那学习速率 $$\alpha$$ 又会以怎样的方式影响梯度下降算法呢?回到之前我们的梯度下降算法公式:

$$\theta_{j}:=\theta_{j}-\alpha\frac{\partial}{\partial\theta_{j}}J(\theta_{0},\theta_{1})$$

观察到,每次迭代都将下降$${\partial \over {\partial {\theta _j}}}J({\theta _0},{\theta _1})$$的$$\alpha$$倍。

显然,若是$$\alpha$$取值太小,则每次下降的步幅太小,则效率太低;若$$\alpha$$的取值太大,则将错过最低值而走向离最低值越来越远的道路——穿过最低值后,其导数值可能比上一次迭代更高,于是一次比一次跳跃得更远,也就无法取到最小值了。

选择学习速率$$\alpha$$的方法是凭经验:依次取0.001、0.003、0.01……1、3、10、……如此尝试。在尝试的过程中,可以首先将迭代次数降低;然后试着画出 Jmin-t 的图线;观察图线,然后根据图线调整 $$\alpha$$ 的值。

线性回归中的多次式

之前我们提到的线性回归预测,多是一次项比较多;但某些特征,对结果的影响可能不是一次的——可能是二次、三次甚至更甚。于是,可以用 $$x^2_i$$ 、 $$x^3_i$$ 来代替 $$x_i$$ 参与线性回归。

一般等式

可用下列等式直接求出线性回归时我们所求的 $$\theta$$ 值:

$$\theta = {({X^T}X)^{ - 1}}{X^T}{\rm{y}}$$

适用于样本数量 n 比较小的情况——因为 n 大了会比较慢。

当 $${X^T}X$$ 没有逆矩阵时,可以用 octave 的 pinv 方法求得伪逆——主要是特征太多的情况下会导致这种情况的发生。

友情链接