
0x00 背景
先說(shuō)一下需求的場(chǎng)景,策劃部門想做一個(gè)垂直領(lǐng)域的社區(qū)產(chǎn)品,類似與知乎那種,但受益人群是金融行業(yè)的從業(yè)人員。產(chǎn)品中有一個(gè)搜索問(wèn)題的需求,搜索的問(wèn)題去題庫(kù)中進(jìn)行模糊匹配,終端支持H5/APP/小程序,甚至是微信的自動(dòng)回復(fù),用過(guò)ItChat的人都知道這個(gè)強(qiáng)大的工具包,不過(guò)最近好像有封號(hào)的動(dòng)作了。做搜索,肯定就會(huì)用到分詞,當(dāng)前開(kāi)源的分詞庫(kù)jieba是做的比較好的了,分析了一下技術(shù)棧,就決定用flask來(lái)實(shí)現(xiàn)一個(gè)微服務(wù),供其他的服務(wù)模塊使用。
本人會(huì)著重講一下環(huán)境的搭建,各種配置的坑。
0x01 升級(jí)操作系統(tǒng)
操作系統(tǒng):CentOS 6.x
CentOS 7的玩家手動(dòng)跳過(guò)該環(huán)節(jié)。首先6.x的版本,默認(rèn)裝的python的版本是2.6的版本,這個(gè)版本后面用到的一些軟件支持的不是很好,所以我們首先要把python升級(jí)到2.7的版本。先創(chuàng)建一個(gè)update.sh腳本,然后把下面內(nèi)容復(fù)制進(jìn)去。
#!/usr/bin/env bash
#安裝依賴
yum install openssl openssl-devel zlib-devel gcc -y
# apt-get install libssl-dev
# apt-get install openssl openssl-devel
# 下載源碼
wget http://www.python.org/ftp/python/2.7.12/Python-2.7.12.tgz
tar -zxvf Python-2.7.12.tgz
cd Python-2.7.12
mkdir /usr/local/python2.7.12
# 開(kāi)啟zlib編譯選項(xiàng)
# sed -i '467c zlib zlibmodule.c -I$(prefix)/include -L$(exec_prefix)/lib -lz' Module/Setup
sed '467s/^#//g' Module/Setup
./configure --prefix=/usr/local/python2.7.12
make
make install
if [ $? -eq 0 ];then
echo "Python2.7.12升級(jí)完成"
else
echo "Python2.7.12升級(jí)失敗,查看報(bào)錯(cuò)信息手動(dòng)安裝"
fi
cd
mv /usr/bin/python /usr/bin/python2.6.6
ln -s /usr/local/python2.7.12/bin/python2.7 /usr/bin/python
sed -i '1s/python/python2.6/g' /usr/bin/yum
wget --no-check-certificate https://bootstrap.pypa.io/get-pip.py
python get-pip.py
if [ $? -eq 0 ];then
echo "pip升級(jí)完成"
else
echo "pip安裝失敗,查看報(bào)錯(cuò)信息手動(dòng)安裝"
fi
rm -rf /usr/bin/pip
ln -s /usr/local/python2.7.12/bin/pip2.7 /usr/bin/pip
然后把這個(gè)腳本加上可執(zhí)行的權(quán)限,并且運(yùn)行。
chmod u+x update.sh
./update.sh
0x02 創(chuàng)建python虛擬空間
這一步完成之后,我們就開(kāi)始隔離一個(gè)虛擬的空間來(lái)運(yùn)行這個(gè)微服務(wù),以后我們所有的程序都在隔離的虛擬空間中來(lái)運(yùn)行,有點(diǎn)docker的概念,這樣不管是用python2.x還是3.x都可以同時(shí)兼容了。
pip install virtualenv
cd /home/test/web
virtualenv ENV
cd bin
source active
至此就啟動(dòng)了這個(gè)docker,接下來(lái)就是在這個(gè)docker中安裝我們r(jià)equirement.txt中所需要的包了。
我們用的包有如下:
pip install flask
pip install jieba
pip install pymysql
pip install redis
pip install virtualenv
pip install uwsgi
pip install xlrd
到此為止就可以在ENV的環(huán)境中,測(cè)試app的功能了,現(xiàn)在python myapp.py試一下各接口功能。
0x03 安裝nginx
盡管測(cè)試成功了,但是線上是不能這么運(yùn)行的,因?yàn)閒lask只是一個(gè)web框架,并不是一個(gè)web server的容器,flask自帶的werkzeug只能用于開(kāi)發(fā)環(huán)境,不能用于生產(chǎn)環(huán)境,對(duì)于web服務(wù)器,我們選擇更專業(yè)的uWSGI,并且配合nginx作為反向代理。
首先,我們安裝nginx
yum -y install nginx
默認(rèn)的nginx的監(jiān)聽(tīng)端口是80,如果部署在云服務(wù)器上,80端口極大的可能被占用了,我們要去修改這個(gè)配置文件。
cd /etc/nginx
vim conf.d
查看一下配置端口的配置文件在哪里,我們看到是default.conf這個(gè)文件中有端口號(hào)的配置,我們把所有端口號(hào)都改成我們想要的端口比如8100。
在 /etc/nginx/ngixn.conf 文件的 http 部分添加一條 include 內(nèi)容,即最后一行
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
include /etc/nginx/sites-enabled/*;
}
創(chuàng)建配置文件 vim /etc/nginx/sites-enabled/hello.conf
server {
# Running port
listen 8100;
# 服務(wù)器ip 或者域名
server_name 0.0.0.0;
# Proxying connections to application servers
location / {
include uwsgi_params;
uwsgi_pass 127.0.0.1:5000;//和 uWSGI 配置文件中的 ip端口一致
}
}
然后看系統(tǒng)中是否有nginx的service腳本
vim /etc/init.d/nginx
如果沒(méi)有該腳本,在該腳本中寫(xiě)如下內(nèi)容:
#!/bin/bash
# chkconfig: - 85 15
nginx=/usr/sbin/nginx
conf=/etc/nginx/nginx.conf
case $1 in
start)
echo -n "Starting Nginx"
$nginx -c $conf
echo " done"
;;
stop)
echo -n "Stopping Nginx"
$nginx -s stop
echo " done"
;;
test)
$nginx -t -c $conf
;;
reload)
echo -n "Reloading Nginx"
$nginx -s reload
echo " done"
;;
restart)
$0 stop
$0 start
;;
show)
ps -aux|grep nginx
;;
*)
echo -n "Usage: $0 {start|restart|reload|stop|test|show}"
;;
esac
給該文件加上可執(zhí)行權(quán)限
chmod u+x nginx
service nginx start
Nginx 在 /var/log/nginx 目錄下有 access.log 和 error.log 兩個(gè)日志文件,如果有問(wèn)題可以查看這2個(gè)日志文件。
0x04 配置uWSGI
接下來(lái)配置uWSGI的啟動(dòng)文件,創(chuàng)建 uwsgi 配置文件
vim /etc/uwsgi/apps-enabled/hello.ini
[uwsgi]
// 開(kāi)啟主線程
master = true
// 項(xiàng)目目錄
base = /home/test/web
// 移動(dòng)到項(xiàng)目目錄 cd
chdir = %(base)
// 本地的ip和端口
socket = 127.0.0.1:5000
// Python 虛擬環(huán)境目錄
home = %(base)/ENV
// 程序啟動(dòng)文件
wsgi-file = hello.py
// 項(xiàng)目中引用 flask 實(shí)例的變量名
callable = app
// 處理器數(shù)
processes = 2
// 線程數(shù)
threads = 4
// 獲取uwsgi統(tǒng)計(jì)信息的服務(wù)地址
stats = 127.0.0.1:9191
保存配置文件,通過(guò) uwsgi -i /etc/uwsgi/apps-enabled/hello.ini,來(lái)啟動(dòng) uwsgi。
注意在env的環(huán)境下,uwsgi安裝的目錄不會(huì)在/usr/bin中,而是在ENV的bin中,所以
在后面的/etc/init.d/uwsgi中的路徑要注意。
創(chuàng)建uWSGI的日志文件
vim /var/log/uwsgi/hello.log
創(chuàng)建uWSGI的service文件
vim /etc/init.d/uwsgi
#!/bin/bash
# chkconfig: - 85 15
uwsgi=/home/test/web/ENV/bin/uwsgi
hello_conf=/etc/uwsgi/apps-enabled/hello.ini
case $1 in
start)
echo -n "Starting uWsgi"
nohup $uwsgi -i $hello_conf >/var/log/uwsgi/hello.log 2>&1 &
echo " done"
;;
stop)
echo -n "Stopping uWsgi"
killall -9 uwsgi
echo " done"
;;
restart)
$0 stop
$0 start
;;
show)
ps -ef|grep uwsgi
;;
*)
echo -n "Usage: $0 {start|restart|stop|show}"
;;
esac
添加可執(zhí)行屬性
sudo chmod +x /etc/init.d/uwsgi
service uwsgi start
uWSGI 在 /var/log/uwsgi 目錄下有項(xiàng)目對(duì)應(yīng)日志,有問(wèn)題可以查看。
0x05 redis的安裝
首先安裝redis的編譯工具gcc和gcc-c++
yum install gcc gcc-c++
然后從redis的官網(wǎng)上下載redis并且安裝
wget http://download.redis.io/releases/redis-3.2.5.tar.gz
tar -zxvf /soft/redis-3.2.5.tar.gz
cd redis-3.2.5
make & make install
然后配置redis.conf
bind 0.0.0.0
# 3.x版本,將此屬性關(guān)閉
protected-mode no
添加redis的service服務(wù)
vim /etc/init.d/redis
#!/bin/sh
#
# Simple Redis init.d script conceived to work on Linux systems
# as it does use of the /proc filesystem.
REDISPORT=6379
EXEC=/usr/local/bin/redis-server
CLIEXEC=/usr/local/bin/redis-cli
PIDFILE=/var/run/redis_${REDISPORT}.pid
CONF="/etc/redis/${REDISPORT}.conf"
case "$1" in
start)
if [ -f $PIDFILE ]
then
echo "$PIDFILE exists, process is already running or crashed"
else
echo "Starting Redis server..."
$EXEC $CONF
fi
;;
stop)
if [ ! -f $PIDFILE ]
then
echo "$PIDFILE does not exist, process is not running"
else
PID=$(cat $PIDFILE)
echo "Stopping ..."
$CLIEXEC -p $REDISPORT shutdown
while [ -x /proc/${PID} ]
do
echo "Waiting for Redis to shutdown ..."
sleep 1
done
echo "Redis stopped"
fi
;;
*)
echo "Please use start or stop as first argument"
;;
esac
然后啟動(dòng)服務(wù)
chmod u+x redis
service redis start
0x06 python中引入redis作為緩存
我們知道redis是k-v的數(shù)據(jù)緩存機(jī)制,當(dāng)緩存數(shù)據(jù)為string, 或是hash類型的時(shí)候,都有原生的函數(shù)支持,具體可以參考redis的API文檔。
但是當(dāng)我們緩存我們自定義的實(shí)體類的時(shí)候,有點(diǎn)力不從心,這時(shí)候可以用pickle庫(kù)來(lái)做序列化,先把實(shí)體類轉(zhuǎn)換成string類型存儲(chǔ)在redis中,取出的時(shí)候,再做反序列化的操作,具體代碼如下:
#coding=utf-8
import redis
import pickle
class Redis:
@staticmethod
def connect(host='localhost', port=6379, db=0):
r = redis.StrictRedis(host, port, db)
return r
# 將內(nèi)存數(shù)據(jù)二進(jìn)制通過(guò)序列號(hào)轉(zhuǎn)為文本流,再存入redis
@staticmethod
def set_data(r, key, data, ex=None):
r.set(pickle.dumps(key), pickle.dumps(data), ex)
# 將文本流從redis中讀取并反序列化,返回
@staticmethod
def get_data(r, key):
data = r.get(pickle.dumps(key))
if data is None:
return None
return pickle.loads(data)
0x07 總結(jié)
到此為止,一個(gè)flask的app的部署就基本完成了,中間的環(huán)節(jié)比較瑣碎,但互聯(lián)網(wǎng)上的資料也很多,基本都可以解決,祝大家玩的開(kāi)心!