Flask+nginx负载均衡综合使用
2臺機子模仿負載均衡的實驗.
本機IP:115.213.73.254
云主機IP:xxx.xxx.xxx.xxx(保密起見,下同) 公網IP
本機運行連接云主機:
ssh ubuntu@某大佬 -p 10070
---------------------------------------云主機上運行netstat -pan結果如下------------------------------------------------
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是云主機的局域網IP
115.213.73.254:16328是臺式機所屬路由器的端口
----------------------------------自己臺式機上運行netstat -pan結果如下-----------------------------------------------------
(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是自己臺式機的局域網IP和端口
啦啦啦:10070是云主機的IP和防火墻端口
-------------------------------------------------概念總結--------------------------------------------------------------------------------------------
端口監聽就是端口占用
上面涉及了四種端口
本機局域網端口->路由器端口->云主機防火墻端口->云主機內部局域網端口
因為本機是沒有公網端口的,所以本地netstat查到的端口與云主機netstat查到的端口是不對應的
主要流程:
云主機內部局域網端口->云主機內部防火墻端口->云主機管理平臺防火墻端口->客戶路由器端口->客戶本地端口->訪問內容。
-------------------------------------------能不能用命令查詢云主機管理平臺防火墻?------------------------------------------------------------------
管理員大大說,refused還是drop都是云主機管理平臺設定的,所以不能根據信息來判斷端口到底咋了。
問了其他幾位網友也是:不能用命令查。
?
命令查詢防火墻端口是否沒開:
云主機內部:
1.用web app監聽一個port的情況下,
2.自己的臺式機telnet 云主機IP 端口,返回connection?refused
滿足上述兩個條件,就表示云主機管理平臺防火墻端口沒開。
-----------------------------------------------------------實驗架構--------------------------------------------------------------------------
我們用兩臺機子,調度分發的時候,一臺是發給自己,一臺是發給云主機。
------------------------------------------------------web app部署、nginx配置、測試-------------------------------------------------------------------
1.《Flask Web開發:基于Python的Web應用開發實戰》第四章的代碼,具體操作如下:
①git clone?https://github.com/miguelgrinberg/flasky
②gitcheck out 4c
③把上述步驟得到的文件夾分別拷貝到本機和云主機任意位置。
④分別修改本機和云主機和hello.py,具體修改在文末附錄。
⑤分別在本機和云主機執行
python3 hello.py
2.
①文末附錄的兩個nginx.conf分別放到本機和云主機的/etc/nginx/路徑下,
②nginx -s reload
3.測試:
chromium瀏覽器(不要使用Chrome瀏覽器,因為它會自動補充斜杠"/"導致訪問失敗,很討厭,當然可以自己額外去hello.py中修改)
打開http://127.0.0.1:9020/flask_learn2
多打開幾次會發現效果如下:
負載均衡成功。
-----------------------------------------------實驗分析與調試---------------------------------------------------------------------
如果運行失敗,檢查以下環節:
不要在nginx.conf中使用ngrok穿透出來的網址,容易失敗。
理清楚端口之間的關系,不要把端口設置重復了。
查清楚上面的“概念總結”中每一層端口是否被封
?
整體端口占用示意圖:
? ? ? ? ? ? ? ? ? ? ? ?/本機127.0.0.1:9002->本機127.0.0.1:9000
本機:9020
? ? ? ? ? ? ? ? ? ? ? ? \云主機xx.xx.xx.xx:10072->云主機127.0.0.1:10071
上述9020,9002,10072端口都被nginx占用,其余都被Flask web app占用
?
另外,檢查端口是否被占用,可以使用:
lsof -i:port
-------------------------------------------------附錄-代碼-------------------------------------------------------------------------
云主機的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)驗證就是看你輸入了東西沒,沒輸入東西的話就會提醒你輸入print(dir(session))old_name = session.get('name')#直接從回話中讀取name參數的值# old_name = session['name']#session用來跨請求保存數據!# old_name沒有跨請求的能力print("old_name=",old_name)if old_name is not None and old_name != form.name.data:#form.name.data是html頁面傳過來的新數據flash('Looks like you have changed your name!')session['name'] = form.name.datareturn redirect(url_for('index'))if session.get("name") is None:print("進入if")return render_template('index.html', form=form, name=session.get('name'))#用戶第一次訪問程序else:print("進入else")return render_template('index.html', form=form, name=session.get('name')+"當前是(云主機)")#form.name.data最新提交的數據,但是這個請求一旦結束,數據就丟失了#session.get('name')老數據#session['name']老數據#從上面的代碼來看,session['name']完全等效於session.get('name')#----------------------------關閉被占用的端口----------------------------------------- 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)本機(就是自己的電腦)中的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)驗證就是看你輸入了東西沒,沒輸入東西的話就會提醒你輸入print(dir(session))old_name = session.get('name')#直接從回話中讀取name參數的值# old_name = session['name']#session用來跨請求保存數據!# old_name沒有跨請求的能力print("old_name=",old_name)if old_name is not None and old_name != form.name.data:#form.name.data是html頁面傳過來的新數據flash('Looks like you have changed your name!')session['name'] = form.name.datareturn redirect(url_for('index'))if session.get("name") is None:print("進入if")return render_template('index.html', form=form, name=session.get('name'))#用戶第一次訪問程序else:print("進入else")return render_template('index.html', form=form, name=session.get('name')+"當前是(本地)")#form.name.data最新提交的數據,但是這個請求一旦結束,數據就丟失了#session.get('name')老數據#session['name']老數據#從上面的代碼來看,session['name']完全等效於session.get('name')#----------------------------關閉被占用的端口----------------------------------------- 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-----------------------------------------------------------------------
云主機完整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(下面公網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;}}}-------------------------------------------------------相關資料閱讀和小記------------------------------------------------------------
[1]提到了各種負載均衡的類型(看完了)
[2]提到了flask+uwsgi
根據[3],uwsgi和gunicorn是兩個相似的東西
[4]提到了nginx負載均衡, 并且有localhost測試的極好案例。
[5]提到了動靜分離(動態網絡資源和靜態網絡資源)
[6]nginx+Django+uwsgi
[7]提到了nginx對四層和七層的負載均衡的實現.
[8]提到了多個nginx的配置文件...不知道怎么一起操作.
[9]中server和upstream一起使用
[10]中一個conf文件里面有多個upstream,不知道含義是什么
[11]中提到,upstream是用來跨越單機(意思應該是轉發給別的單機)
三臺服務器,需要3個nginx.conf,但是每臺機子上的nginx.conf內容都是不同的.
?
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
總結
以上是生活随笔為你收集整理的Flask+nginx负载均衡综合使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: nginx.conf删除与否网页都能访问
- 下一篇: xfce4开始菜单中的小老鼠图标不见了