Flask+nginx负载均衡综合使用
2臺機(jī)子模仿負(fù)載均衡的實(shí)驗(yàn).
本機(jī)IP:115.213.73.254
云主機(jī)IP:xxx.xxx.xxx.xxx(保密起見,下同) 公網(wǎng)IP
本機(jī)運(yùn)行連接云主機(jī):
ssh ubuntu@某大佬 -p 10070
---------------------------------------云主機(jī)上運(yùn)行netstat -pan結(jié)果如下------------------------------------------------
tcp ? ? ? ?0 ? ?464 192.168.1.109:22 ? ? ? ?115.213.73.254:16328 ? ?ESTABLISHED - ? ? ? ? ? ? ? ? ??
tcp ? ? ? ?0 ? ? ?0 192.168.1.109:22 ? ? ? ?115.213.73.254:16890 ? ?ESTABLISHED - ? ? ? ? ? ? ? ? ??
tcp ? ? ? ?0 ? ? ?0 192.168.1.109:22 ? ? ? ?115.213.73.254:16253 ? ?ESTABLISHED - ??
可以看到:
192.168.1.109是云主機(jī)的局域網(wǎng)IP
115.213.73.254:16328是臺式機(jī)所屬路由器的端口
----------------------------------自己臺式機(jī)上運(yùn)行netstat -pan結(jié)果如下-----------------------------------------------------
(python3.6) appleyuchi@ubuntu:~$ netstat -pan|grep 10070
(Not all processes could be identified, non-owned process info
?will not be shown, you would have to be root to see it all.)
tcp ? ? ? ?0 ? ? ?0 192.168.0.101:47450 ? ? xxx.xxx.xxx.xxx:10070 ? ? ? ESTABLISHED 8775/SecureCRT ? ? ?
tcp ? ? ? ?0 ? ? ?0 192.168.0.101:47534? ? ?xxx.xxx.xxx.xxx:10070 ? ? ? ESTABLISHED 8775/SecureCRT?
192.168.0.101:47450是自己臺式機(jī)的局域網(wǎng)IP和端口
啦啦啦:10070是云主機(jī)的IP和防火墻端口
-------------------------------------------------概念總結(jié)--------------------------------------------------------------------------------------------
端口監(jiān)聽就是端口占用
上面涉及了四種端口
本機(jī)局域網(wǎng)端口->路由器端口->云主機(jī)防火墻端口->云主機(jī)內(nèi)部局域網(wǎng)端口
因?yàn)楸緳C(jī)是沒有公網(wǎng)端口的,所以本地netstat查到的端口與云主機(jī)netstat查到的端口是不對應(yīng)的
主要流程:
云主機(jī)內(nèi)部局域網(wǎng)端口->云主機(jī)內(nèi)部防火墻端口->云主機(jī)管理平臺防火墻端口->客戶路由器端口->客戶本地端口->訪問內(nèi)容。
-------------------------------------------能不能用命令查詢云主機(jī)管理平臺防火墻?------------------------------------------------------------------
管理員大大說,refused還是drop都是云主機(jī)管理平臺設(shè)定的,所以不能根據(jù)信息來判斷端口到底咋了。
問了其他幾位網(wǎng)友也是:不能用命令查。
?
命令查詢防火墻端口是否沒開:
云主機(jī)內(nèi)部:
1.用web app監(jiān)聽一個port的情況下,
2.自己的臺式機(jī)telnet 云主機(jī)IP 端口,返回connection?refused
滿足上述兩個條件,就表示云主機(jī)管理平臺防火墻端口沒開。
-----------------------------------------------------------實(shí)驗(yàn)架構(gòu)--------------------------------------------------------------------------
我們用兩臺機(jī)子,調(diào)度分發(fā)的時候,一臺是發(fā)給自己,一臺是發(fā)給云主機(jī)。
------------------------------------------------------web app部署、nginx配置、測試-------------------------------------------------------------------
1.《Flask Web開發(fā):基于Python的Web應(yīng)用開發(fā)實(shí)戰(zhàn)》第四章的代碼,具體操作如下:
①git clone?https://github.com/miguelgrinberg/flasky
②gitcheck out 4c
③把上述步驟得到的文件夾分別拷貝到本機(jī)和云主機(jī)任意位置。
④分別修改本機(jī)和云主機(jī)和hello.py,具體修改在文末附錄。
⑤分別在本機(jī)和云主機(jī)執(zhí)行
python3 hello.py
2.
①文末附錄的兩個nginx.conf分別放到本機(jī)和云主機(jī)的/etc/nginx/路徑下,
②nginx -s reload
3.測試:
chromium瀏覽器(不要使用Chrome瀏覽器,因?yàn)樗鼤詣友a(bǔ)充斜杠"/"導(dǎo)致訪問失敗,很討厭,當(dāng)然可以自己額外去hello.py中修改)
打開http://127.0.0.1:9020/flask_learn2
多打開幾次會發(fā)現(xiàn)效果如下:
負(fù)載均衡成功。
-----------------------------------------------實(shí)驗(yàn)分析與調(diào)試---------------------------------------------------------------------
如果運(yùn)行失敗,檢查以下環(huán)節(jié):
不要在nginx.conf中使用ngrok穿透出來的網(wǎng)址,容易失敗。
理清楚端口之間的關(guān)系,不要把端口設(shè)置重復(fù)了。
查清楚上面的“概念總結(jié)”中每一層端口是否被封
?
整體端口占用示意圖:
? ? ? ? ? ? ? ? ? ? ? ?/本機(jī)127.0.0.1:9002->本機(jī)127.0.0.1:9000
本機(jī):9020
? ? ? ? ? ? ? ? ? ? ? ? \云主機(jī)xx.xx.xx.xx:10072->云主機(jī)127.0.0.1:10071
上述9020,9002,10072端口都被nginx占用,其余都被Flask web app占用
?
另外,檢查端口是否被占用,可以使用:
lsof -i:port
-------------------------------------------------附錄-代碼-------------------------------------------------------------------------
云主機(jī)的hello.py
from flask import Flask, render_template, session, redirect, url_for, flash from flask_bootstrap import Bootstrap from flask_moment import Moment from flask_wtf import FlaskForm from wtforms import StringField, SubmitField from wtforms.validators import DataRequiredapp = Flask(__name__) app.config['SECRET_KEY'] = 'hard to guess string'bootstrap = Bootstrap(app) moment = Moment(app)class NameForm(FlaskForm):name = StringField('What is your name?', validators=[DataRequired()])submit = SubmitField('Submit')@app.errorhandler(404) def page_not_found(e):return render_template('404.html'), 404@app.errorhandler(500) def internal_server_error(e):return render_template('500.html'), 500@app.route('/flask_learn2', methods=['GET', 'POST']) def index():form = NameForm()if form.validate_on_submit():#用戶第2次以上訪問程序,這個地方的有效性(validate)驗(yàn)證就是看你輸入了東西沒,沒輸入東西的話就會提醒你輸入print(dir(session))old_name = session.get('name')#直接從回話中讀取name參數(shù)的值# old_name = session['name']#session用來跨請求保存數(shù)據(jù)!# old_name沒有跨請求的能力print("old_name=",old_name)if old_name is not None and old_name != form.name.data:#form.name.data是html頁面?zhèn)鬟^來的新數(shù)據(jù)flash('Looks like you have changed your name!')session['name'] = form.name.datareturn redirect(url_for('index'))if session.get("name") is None:print("進(jìn)入if")return render_template('index.html', form=form, name=session.get('name'))#用戶第一次訪問程序else:print("進(jìn)入else")return render_template('index.html', form=form, name=session.get('name')+"當(dāng)前是(云主機(jī))")#form.name.data最新提交的數(shù)據(jù),但是這個請求一旦結(jié)束,數(shù)據(jù)就丟失了#session.get('name')老數(shù)據(jù)#session['name']老數(shù)據(jù)#從上面的代碼來看,session['name']完全等效於session.get('name')#----------------------------關(guān)閉被占用的端口----------------------------------------- def killport(port):command='''kill -9 $(netstat -nlp | grep :'''+str(port)+''' | awk '{print $7}' | awk -F"/" '{ print $1 }')'''os.system(command) if __name__ == '__main__':port=10071app.run(host="127.0.0.1", port=port)本機(jī)(就是自己的電腦)中的hello.py如下:
from flask import Flask, render_template, session, redirect, url_for, flash from flask_bootstrap import Bootstrap from flask_moment import Moment from flask_wtf import FlaskForm from wtforms import StringField, SubmitField from wtforms.validators import DataRequiredapp = Flask(__name__) app.config['SECRET_KEY'] = 'hard to guess string'bootstrap = Bootstrap(app) moment = Moment(app)class NameForm(FlaskForm):name = StringField('What is your name?', validators=[DataRequired()])submit = SubmitField('Submit')@app.errorhandler(404) def page_not_found(e):return render_template('404.html'), 404@app.errorhandler(500) def internal_server_error(e):return render_template('500.html'), 500@app.route('/flask_learn2', methods=['GET', 'POST']) def index():form = NameForm()if form.validate_on_submit():#用戶第2次以上訪問程序,這個地方的有效性(validate)驗(yàn)證就是看你輸入了東西沒,沒輸入東西的話就會提醒你輸入print(dir(session))old_name = session.get('name')#直接從回話中讀取name參數(shù)的值# old_name = session['name']#session用來跨請求保存數(shù)據(jù)!# old_name沒有跨請求的能力print("old_name=",old_name)if old_name is not None and old_name != form.name.data:#form.name.data是html頁面?zhèn)鬟^來的新數(shù)據(jù)flash('Looks like you have changed your name!')session['name'] = form.name.datareturn redirect(url_for('index'))if session.get("name") is None:print("進(jìn)入if")return render_template('index.html', form=form, name=session.get('name'))#用戶第一次訪問程序else:print("進(jìn)入else")return render_template('index.html', form=form, name=session.get('name')+"當(dāng)前是(本地)")#form.name.data最新提交的數(shù)據(jù),但是這個請求一旦結(jié)束,數(shù)據(jù)就丟失了#session.get('name')老數(shù)據(jù)#session['name']老數(shù)據(jù)#從上面的代碼來看,session['name']完全等效於session.get('name')#----------------------------關(guān)閉被占用的端口----------------------------------------- def killport(port):command='''kill -9 $(netstat -nlp | grep :'''+str(port)+''' | awk '{print $7}' | awk -F"/" '{ print $1 }')'''os.system(command) if __name__ == '__main__':port=9000app.run(host="127.0.0.1", port=port)-------------------------------------------------附錄-nginx-----------------------------------------------------------------------
云主機(jī)完整nginx.conf
user www-data; worker_processes auto; pid /run/nginx.pid;events {worker_connections 768;# multi_accept on; }http {### Basic Settings##sendfile on;tcp_nopush on;tcp_nodelay on;keepalive_timeout 65;types_hash_max_size 2048;# server_tokens off;# server_names_hash_bucket_size 64;# server_name_in_redirect off;include /etc/nginx/mime.types;default_type application/octet-stream;### SSL Settings##ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLEssl_prefer_server_ciphers on;### Logging Settings##access_log /var/log/nginx/access.log;error_log /var/log/nginx/error.log;### Gzip Settings##gzip on;gzip_disable "msie6";# gzip_vary on;# gzip_proxied any;# gzip_comp_level 6;# gzip_buffers 16 8k;# gzip_http_version 1.1;# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;### Virtual Host Configs##include /etc/nginx/conf.d/*.conf;include /etc/nginx/sites-enabled/*;server {listen 10072;#server_name mycard.moe;#charset koi8-r;#access_log /var/log/nginx/log/host.access.log main;location / {proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header Host $http_host;proxy_set_header X-NginX-Proxy true;proxy_pass http://127.0.0.1:10071/; fastcgi_intercept_errors on; proxy_redirect off;}}}?
本地完整nginx.conf(下面公網(wǎng)IP:xx.xx.xx.xx需要改成自己的)
user www-data; worker_processes auto; pid /run/nginx.pid;events {worker_connections 768;# multi_accept on; }http {### Basic Settings##sendfile on;tcp_nopush on;tcp_nodelay on;keepalive_timeout 65;types_hash_max_size 2048;# server_tokens off;# server_names_hash_bucket_size 64;# server_name_in_redirect off;include /etc/nginx/mime.types;default_type application/octet-stream;### SSL Settings##ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLEssl_prefer_server_ciphers on;### Logging Settings##access_log /var/log/nginx/access.log;error_log /var/log/nginx/error.log;### Gzip Settings##gzip on;gzip_disable "msie6";# gzip_vary on;# gzip_proxied any;# gzip_comp_level 6;# gzip_buffers 16 8k;# gzip_http_version 1.1;# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;### Virtual Host Configs##include /etc/nginx/conf.d/*.conf;include /etc/nginx/sites-enabled/*;upstream myapp{server 127.0.0.1:9002 weight=5;server xx.xx.xx.xx:10072 weight=5;#server srv3.example.com;}server{listen 9020;#server_namelocation / {proxy_pass http://myapp;}}server {listen 9002;#server_name xxx.cn#charset koi8-r;#access_log /var/log/nginx/log/host.access.log main;location /{proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header Host $http_host;proxy_set_header X-NginX-Proxy true;proxy_pass http://127.0.0.1:9000/;proxy_redirect off;}}}-------------------------------------------------------相關(guān)資料閱讀和小記------------------------------------------------------------
[1]提到了各種負(fù)載均衡的類型(看完了)
[2]提到了flask+uwsgi
根據(jù)[3],uwsgi和gunicorn是兩個相似的東西
[4]提到了nginx負(fù)載均衡, 并且有l(wèi)ocalhost測試的極好案例。
[5]提到了動靜分離(動態(tài)網(wǎng)絡(luò)資源和靜態(tài)網(wǎng)絡(luò)資源)
[6]nginx+Django+uwsgi
[7]提到了nginx對四層和七層的負(fù)載均衡的實(shí)現(xiàn).
[8]提到了多個nginx的配置文件...不知道怎么一起操作.
[9]中server和upstream一起使用
[10]中一個conf文件里面有多個upstream,不知道含義是什么
[11]中提到,upstream是用來跨越單機(jī)(意思應(yīng)該是轉(zhuǎn)發(fā)給別的單機(jī))
三臺服務(wù)器,需要3個nginx.conf,但是每臺機(jī)子上的nginx.conf內(nèi)容都是不同的.
?
Reference:
[1]http://www.ttlsa.com/nginx/using-nginx-as-http-loadbalancer/
[2]https://my.oschina.net/RabbitXiao/blog/1583662
[3]https://segmentfault.com/q/1010000008927097/a-1020000008927326
[4]https://www.jianshu.com/p/4c250c1cd6cd
[5]https://blog.51cto.com/13178102/2063271
[6]https://segmentfault.com/a/1190000016108576
[7]https://www.jb51.net/article/153710.htm
[8]https://www.cnblogs.com/crazymagic/p/11029415.html
[9]https://www.cnblogs.com/winniejohn/p/9855351.html
[10]https://www.cnblogs.com/diantong/p/11208508.html
[11]https://blog.csdn.net/gu_wen_jie/article/details/82149003
總結(jié)
以上是生活随笔為你收集整理的Flask+nginx负载均衡综合使用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: nginx.conf删除与否网页都能访问
- 下一篇: 误操作导致系统只剩下lo