一次flask+redis的微服務(wù)實(shí)戰(zhàn)

flask

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)心!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容