Comments

背景故事

线上服务器一直没有开启防火墙,没有约束用起来倒也省事。部署 Hadoop 集群(CDH 发行版)的时候,所有网上看过的教程和笔记(包括 CDH 官方文档),全部都提到了部署过程中要关闭防火墙;极少数教程会提到如果有需要,可以在部署完成后再开启;然而没有任何教程在最后真正开启了防火墙。

因为没有防火墙,其实也发生过几次安全事故:

  • 某天某台服务器 CPU 利用率很高,后来发现是因为被人利用 rundeck 的漏洞植入了一个挖矿程序;
  • 某天有个跑在 Docker 里的 Redis 出现故障,经查也是被植入了挖矿程序
  • 某天发现有台机器上有个废弃的 MySQL 跑在公网上,日志里面几乎全是尝试登录的记录

这几次事故虽然没有导致财产损失,但是公网太可怕,没有防火墙就是在外面裸奔,随时可能受到攻击。Hadoop 集群所有服务都是绑定到 0.0.0.0,加上没有开启认证,很容易被拖库。

FirewallD

最先想到的是用 iptables,之前也有使用经历,然而这玩意儿实在太复杂,概念、规则太多,一直没弄懂。CentOS 7 默认安装了 FirewallD,使用起来非常方便,也很好理解。网上的介绍和教程很多,不赘述。直接介绍我的使用策略。

FirewallD 有很多种 zone policy,直接使用默认的 public.

Read on →
Comments

  • 查询所有 session
SELECT * FROM stv_sessions;
  • 终止 session
SELECT pg_terminate_backend(32281);

即,调用 pg_terminate_backend 函数,传入 process_id。

权限:普通用户只能终止自己的 session,超级用户能终止任意 session.

  • 查询正在运行的 queries

类似 MySQL 的 SHOW PROCESSLIST.

SELECT stv_recents.userid, stv_recents.status, stv_recents.starttime,
       stv_recents.duration, stv_recents.user_name, stv_recents.db_name,
       stv_recents.query, stv_recents.pid
FROM stv_recents
WHERE stv_recents.status = 'Running'::bpchar;
Read on →
Comments

应用使用虚拟环境是每个 Python 程序员都应该要掌握的技能。 pyenv 是一个非常好用的 Python 环境管理工具。有这些主要特性:

  1. 方便的安装、管理不同版本的 Python,而且不需要 sudo 权限,不会污染系统的 Python 版本
  2. 可以修改当前用户使用的默认 Python 版本
  3. 集成 virtualenv,自动安装、激活
  4. 命令行自动补全

详细内容见 Github - pyenv/pyenv.

安装 pyenv

最简单的方式是使用 pyenv-installer:

curl -L https://raw.githubusercontent.com/pyenv/pyenv-installer/master/bin/pyenv-installer | bash

然后在 ~/.bashrc~/.zshrc 中添加如下内容:

export PATH="~/.pyenv/bin:$PATH"
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"
Read on →
Comments

通过 yum 安装:

$ sudo yum install java-1.8.0
$ sudo rpm -Uvh http://repo.rundeck.org/latest.rpm
$ sudo yum install rundeck

如果已经安装了 Java,第一步可以略过。安装过程中有几个步骤需要确认,一路同意(输入 y)即可。

安装完成后可以立即运行:

$ sudo service rundeckd start

但生产环境还是要修改一些默认配置。上面的安装过程会添加一个名为 rundeck 的用户和组。配置文件位于 /etc/rundeck:

$ sudo su - rundeck
$ cd /etc/rundeck/
$ ll
-rw-r-----. 1 rundeck rundeck  738 Apr 20 07:47 admin.aclpolicy
-rw-r-----. 1 rundeck rundeck 1104 Apr 20 07:47 apitoken.aclpolicy
-rw-r-----. 1 rundeck rundeck  511 Apr 20 07:47 cli-log4j.properties
-rw-r-----. 1 rundeck rundeck 1438 Jun 19 16:52 framework.properties
-rw-r-----. 1 rundeck rundeck  136 Apr 20 07:47 jaas-loginmodule.conf
-rw-r-----. 1 rundeck rundeck 7538 Apr 20 07:47 log4j.properties
-rw-r-----. 1 rundeck rundeck 2889 Apr 20 07:47 profile
-rw-r-----. 1 rundeck rundeck  549 Apr 20 07:47 project.properties
-rw-r-----. 1 rundeck rundeck 1065 Jun 20 11:54 realm.properties
-rw-r-----. 1 rundeck rundeck  579 Jun 20 11:56 rundeck-config.properties
drwxr-x---. 2 rundeck rundeck   27 Jun 19 16:52 ssl
Read on →
Comments

Babel

Babel is an integrated collection of utilities that assist in internationalizing and localizing Python applications, with an emphasis on web-based applications.

  • 文档:http://babel.pocoo.org/en/latest/
  • 代码:https://github.com/python-babel/babel

Flask-Babel

Flask 的 i18n 扩展,集成 babel、pytz 等。

  • 文档:https://pythonhosted.org/Flask-Babel/
  • 代码:https://github.com/python-babel/flask-babel

使用

  • 安装:pip install Flask-Babel

  • babel 配置文件:babel.cfg

[python: **.py]
[jinja2: **.html]
extensions=jinja2.ext.autoescape,jinja2.ext.with_,webassets.ext.jinja2.AssetsExtension
Read on →
Comments

创建 EC2 实例的时候可以选择添加 EBS 卷,在实例运行后,需要手动挂载上去。

详情见 EBS 的文档

lsblk 命令查看所有可用的磁盘及其安装点

$ lsblk
NAME    MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
xvda    202:0    0   8G  0 disk
`-xvda1 202:1    0   8G  0 part /
xvdb    202:16   0  30G  0 disk

其中 xvda1 是根设备,挂载到了 /xvdb 是刚才添加的 EBS 卷,还没有挂载。

Read on →
Comments

设计表

首先是设计表结构。建表语法差别不大,有一些地方可以注意一下:

  • Redshift 貌似没有无符号类型,所以要把 unsigned 类型的字段修改成相应的 INT 或 BIGINT 类型。
  • FLOAT 类型改成 REAL 或 FLOAT4
  • 把索引语句去掉,保留主键、外键、唯一性约束,Redshift 不会检查这些约束,但是查询时会用于优化。
  • Redshift 的 CHAR 类型只能包含单字节 ASCII 字符,对于非 ASCII 数据需要把 CHAR 改成 VARCHAR 类型
  • 有可能 MySQL 中存的是 unicode,而 Redshift 中存的是 bytes,所以 VARCHAR 的长度也要调整,避免溢出。最简单的,可以用 MySQL 的字段长度 * 3.

关于 sort key, dist key 等设计,只属于 Redshift 范畴,参考官网文档即可。

Read on →
Comments

启动 EC2 实例

先根据 Tableau Server 的使用情况确定需要的配置,从而确定实例类型。

  • AMI: Microsoft Windows Server 2012 R2 Base(简体中文)
  • 类型: m4.4xlarge

启动、配置步骤略去不表,有两点需要注意:

  • VPC 需要开启 3389 端口用于远程登录(RDP)
  • 密钥对会用于解密登录密码

安装 Tableau Server

从 Tableau 官网下载然后安装,配置、激活过程比较简单,略去不表。

Read on →
Comments

前段时间帮同事处理了一个把 CSV 数据导入到 MySQL 的需求。两个很大的 CSV 文件, 分别有 3GB、2100 万条记录和 7GB、3500 万条记录。对于这个量级的数据,用简单的单进程/单线程导入 会耗时很久,最终用了多进程的方式来实现。具体过程不赘述,记录一下几个要点:

  • 批量插入而不是逐条插入
  • 为了加快插入速度,先不要建索引
  • 生产者和消费者模型,主进程读文件,多个 worker 进程执行插入
  • 注意控制 worker 的数量,避免对 MySQL 造成太大的压力
  • 注意处理脏数据导致的异常
  • 原始数据是 GBK 编码,所以还要注意转换成 UTF-8
  • click 封装命令行工具

具体的代码实现如下:

Read on →
Comments

在 Flask 项目中使用 Celery 这篇文章谈到了如何在 Flask 项目中集成 Celery,也讲了在 celery 任务中引用 Flask 的 application context 的方法。一般情况下那样使用是没问题的,但是如果需要在 task 中使用 gevent,就需要一些额外的改进。至少有两点。

1. 使用 gevent 并发模型

如果在 task 中要使用 gevent,就必须使用 gevent 并发模型。这很好处理,只需要修改启动选项就行:

$ celery worker -A celery_worker.celery -P gevent -c 10 -l INFO

上面的命令,-P 选项指定 pool,默认是 prefork,这里是 gevent; -c 设置并发数。

Read on →
getElementsByTagName('BODY')[0]).appendChild(s); }()); getElementsByTagName('BODY')[0]).appendChild(s); }()); getElementsByTagName('BODY')[0]).appendChild(s); }());