上文說到如何利用node-mapnik架設OpenStreetMap瓦片服務,解決了有沒有的問題。然而這個服務還是比較孱弱,主要表現在以下幾個方面:
1. Node.js只能使用CPU的一個核,不能有效發揮服務器的多核優勢;
2. 前端使用了一台TileStrata服務器,即無法實現負載均衡,也無法實現服務主備冗余;
3. 后端使用了一台PostgreSQL,和前端一樣,無法達到高性能和高可用性;
4. 在Node.js和PostgreSQL之間沒有使用連接池,造成數據數性能低下;
針對這些問題,本文將給出解決方案。然而“調優性能”的關鍵是“調”,本文只是給出思路和一般性方法,可能無法真正在您的環境中能起到立竿見影的效果。針對具體的環境,可能需要采用具體的參數。接下來,我將從后端到前端來介紹。
一、PostgreSQL連接池
本文不打算提PostgreSQL性能調優,因為這一塊太大、太深奧,我自已也沒有什么好的心得體會,就不耽誤大家了,接下來有工夫了我也要好好的學習下PostgreSQL性能調優技術。請大家自行Google,如果有好的方法記得留言分享哦:)
當應用程序直接訪問PostgreSQL時,每次連接時PostgreSQL者會克隆出一個服務進程來為應用程序服務,在關閉連接后,PostgreSQL將自動把服務進程停掉。頻繁的創建和銷毀進程,會大大消耗服務器資源。要解決這個問題,就要引入數據庫連接池,把連接緩存住,實現降低服務器資源消耗的目的。
PostgreSQL有兩個知名的連接池: PgBouncer (官網)和 Pgpool-II (官網)。其中 PgBouncer比較單純,僅作數據庫連接池之用;而 Pgpool-II則功能較為強大,除可用於連接池外,還能用於PostgreSQL服務復制、負載均衡以及並行查詢。然而貌似 Pgpool-II 在集群中的服務和並發連接較少時效果並不顯著,甚至還要性能還要遠低於單機性能,所以這里就不考慮使用 Pgpool-II 了。本文將選用 PgBouncer 作為PostgreSQL的連接池。下面將介紹安裝及配置方法。
1. 從yum安裝pgbouncer及工具的依賴項
yum install pgbouncer python-psycopg2 -y
2. 修改pgbouncer配置
vim /etc/pgbouncer/pgbouncer.ini
a. [databases] 節
#gis = 是PgBouncer公開給客戶端的數據庫名稱,可以和實際數據庫不一致
#connect_query=驗證數據庫是否正常連接
#此外沒有指定user和password參數,將從下面的pgbouncer配置節中從auth_file中匹配
gis = host=127.0.0.1 port=5432 dbname=gis datestyle=ISO connect_query='SELECT 1'
b. [pgbouncer] 節
logfile = /var/log/pgbouncer/pgbouncer.log pidfile = /var/run/pgbouncer/pgbouncer.pid
#*代表任意地址 listen_addr = * listen_port = 6432 auth_type = md5
#auth_file是連接數據庫的用戶名和密碼匹配文件 auth_file = /etc/pgbouncer/userlist.txt
#postgres是可以登錄到虛擬的pgbouncer庫的管理用戶 admin_users = postgres stats_users = stats, postgres pool_mode = session server_reset_query = DISCARD ALL max_client_conn = 100 default_pool_size = 20
3. 生成 auth_file 文件,該文件存儲實際用於登錄的用戶名和密碼。
cd /etc/pgbouncer
# 第二個參數將使用PostgreSQL的配置項 ./mkauth.py "/etc/pgbouncer/userlist.txt" "dbname='postgres' user='postgres' password='111111' host='127.0.0.1'" chown pgbouncer:pgbouncer userlist.txt
4. 啟動並驗證pgbouncer ,注意,此處不可使用 root 用戶,請使用安裝包自動創建的 pgbouncer 用戶
su pgbouncer pgbouncer -d /etc/pgbouncer/pgbouncer.ini
5. 查看pgbouncer連接池和客戶端
#經實測,如果不使用-h參數將無法登錄
psql -p 6432 -h 127.0.0.1 -U postgres -d pgbouncer -W show pools; show clients; show help;
6. 關閉pgbouncer
sudo pkill -9 -f 'pgbouncer'
二、PostgreSQL主備模式
PostgreSQL提供了Standby(主備)模式,用於實現一台主數據庫、n台備數據庫,達到高可用性的目的。該模式也順便為實現多台只讀數據庫提供了條件。接下來將介紹如何實現Standby模式。
1. 安裝PostgreSQL主庫步驟(過程略),詳情請參見《CentOS7下安裝並簡單設置PostgreSQL筆記》
2. 導入OpenStreetMap數據(過程略),詳情請參見《CentOS7部署PostGis》、《CentOS7部署osm2pgsql》
3. 安裝PostgreSQL備庫(終於到主角上場了),咱就不再Step by Step了,直接一次性裝上。
yum install http://yum.postgresql.org/9.5/redhat/rhel-7-x86_64/pgdg-redhat95-9.5-2.noarch.rpm -y yum install postgresql95-server postgresql95-contrib -y
#安裝PostGis
yum install postgis2_95 postgis2_95-client ogr_fdw95 pgrouting_95 -y
mkdir /home/postgresql_data
4. 修改主庫配置,請注意,這里不是修改剛安裝好的數據庫,而是修改第1步中主庫的配置文件
a. $PGPATH下的 pg_hba.conf 文件
在文件最下面添加如下配置
host replication postgres 192.168.1.0/24 md5
b. $PGPATH下 postgresql.conf 文件,確保有三處配置如下:
i. listen_address = '*'
ii. wal_level = hot_standby
iii. max_wal_senders = 5
c. 為postgres數據庫帳號設置密碼
ALTER USER postgres WITH PASSWORD '111111'
d. 重啟Postgresql服務,使配置生效 systemctl restart postgresql-9.5
5. 在備庫服務器上生成基礎備份,請注意,此處回到備庫的服務器進行操作
# -D參數是你要把主庫備份出來的目的目錄 # -l參數是你備份的標簽,請隨意 pg_basebackup -h 192.168.1.99 -U postgres -F p -P -x -R -D /home/postgresql_data -l pgbak201701291308
6. 修改備庫配置文件, vim /home/postgresql_data/postgresql.conf
hot_standby = on
7. 設置備庫數據目錄的所有者和權限
chown -R postgres:postgres /home/postgresql_data chmod -R 700 /home/postgresql_data
8. 設置備庫postgresql服務啟動選項 vim /usr/lib/systemd/system/postgresql-9.5.service
Environment=PGDATA=/home/postgresql_data
9. 啟動備庫並查看狀態
systemctl start postgresql-9.5
systemctl status postgresql-9.5
10. 查看備庫狀態:
11. 驗證主備模式是否有效,當前主庫的測試表數據是:
select * from tetst01;
在主庫中添加一行數據
insert into test01(id,note) values (2, 'aCloud');
再在備庫中查詢
至此,PostgreSQL的主備模式構建完成。
三、使用HAProxy 實現PostgreSQL負載均衡
上一節中我們通過建立Standby模式,在一台主數據庫和n台備數據庫之間實現了數據同步。雖然備數據庫只能提供只讀服務,然而對於存儲地理空間數據的應用而言,90%的情況下就夠用了,因為我們要修改數據的時機還是比較少的,因此采用負載均衡技術將應用程序對數據庫的請求分攤到幾台數據庫服務器上,將有助於性能提升。
通常而言,負載均衡服務軟件有三種:Nginx、HAProxy和LVS。Nginx在網絡的第7層、LVS在網絡的第4層,而HAProxy在4、7層都可以工作,而且有文章指出,HAProxy在虛擬機上能較好的工作,So,不費勁了,直接選HAProxy吧。
1. 安裝HAProxy
yum install haproxy -y
2. 配置HAProxy, vim /etc/haproxy/haproxy.cfg ,配置文件中超時時間和網絡檢查時間設置的偏大,這是因為如果這些值設置的太小的話,postgresql在進行運算時,舊的查詢還沒有完成,新的請求或檢查就來了,就造成超時了。這個問題在以后有時間了再好好的研究下,看是否有更好的辦法。目前使用這個方法也能解決問題。
global
log 127.0.0.1 local2
chroot /var/lib/haproxy
pidfile /var/run/haproxy.pid
maxconn 4000
user haproxy
group haproxy
daemon
stats socket /var/lib/haproxy/stats
defaults
mode tcp
log global
option redispatch
option httplog
retries 10
timeout queue 5m
timeout connect 5m
timeout client 5m
timeout server 5m
timeout http-keep-alive 20m
timeout check 1m
maxconn 3000
listen webservers
bind 0.0.0.0:808
mode http
log global
stats refresh 30s
stats realm Private lands
stats uri /admin?stats
stats auth admin:111111
listen postgres
bind 0.0.0.0:7432
mode tcp
balance roundrobin
server pg1 192.168.1.99:6432 weight 1 maxconn 1000 check inter 5m
server pg2 192.168.1.80:6432 weight 1 maxconn 1000 check inter 5m
server pg3 192.168.1.85:6432 weight 1 maxconn 1000 check inter 5m
server pg4 192.168.1.86:6432 weight 1 maxconn 1000 check inter 5m
3. 防火牆打洞
firewall-cmd --zone=public --add-port=7432/tcp --permanent
firewall-cmd --reload
4. 關閉SELinux(規則太難配,干脆關了), vim /etc/selinux/config
SELinux=disabled
5. 啟動HAProxy
systemctl start haproxy
systemctl enable haproxy
6. 使用 http://haproxyaddr:port/admin?stats 可對HAProxy狀態進行監控。這里我們可以看到目前狀態正常。
7. 至此,我們已經有了四個PostgreSQL數據庫,並且使用HAProxy進行負載均衡,下面就可以配置mapnik,使用HAProxy。打開 OpenStreetMap-Carto 文件夾(不知道這個文件夾在什么地方?請參考《使用node-mapnik生成openstreetmap-carto風格的瓦片》一文中的設置),修改 project.mml ,將其中的 host 、 port 修改為HAProxy的地址和偵聽端口,將 dbname 修改為 pgbouncer.ini 中 [databases] 的值。將 user 、 password 修改為 pgbouncer.ini 中 auth_file 文件中的相應用戶名和密碼信息。
8. 重新生成mapnik配置
carto project.mml > mapnik.xml
此時, node-mapnik 就可以使用HAProxy提供的服務了。
四、TileStrata實現瓦片服務負載均衡
1. 《使用node-mapnik和openstreetmap數據初步搭建瓦片服務》的第四節,已經講了TileStrata提供的 TileStrata-Balancer 組件實現瓦片服務負載均衡,本文繼續使用該節內容,有需要的筒子們請參考。效果如下:
tilestrata-balancer --hostname=192.168.1.51 --port=8083 --private-port=8081 --check-interval=5000 --unhealthy-count=1
注意:記得在提供瓦片服務的服務器上打開相應的防火牆端口。為了省事,最好把SELinux關閉掉。最后,不要把tilestrata-balancer的private端口公布到公網上。
五、Node.js的單機集群
Node.js應用程序一般情況下僅能使用CPU的一個核,要充分利用CPU,最好是每個核上跑一個Node.js的程序。簡單點來說,Node.js內置了這一實現,看下面代碼:
1. tileserver/server/cluster.js ,在這個文件中,Node.js將在每一個CPU的核心上執行一個 ./server.js 文件。為了能成功加入到 tilestrata-balancer ,我給每一個fork指定一個單獨的端口號
var cluster = require('cluster'); var cpus = require('os').cpus(); cluster.setupMaster({ exec: './server.js' }); for(var i = 0; i < cpus.length; i++){ var port = 8088 + i; cluster.fork({port : port}); }
2. tileserver/server/server.js ,在 cluster.js 傳來的端口上進行偵聽
var tilestrata = require('tilestrata'); var disk = require('tilestrata-disk'); var mapnik = require('tilestrata-mapnik'); var strata = tilestrata({ balancer: { host: '192.168.1.51:8081' } }); strata.layer('map') .route('tile.png') .use(disk.cache({dir: './tilecache'})) .use(mapnik({ pathname: '/home/openstreetmap/openstreetmap-carto/mapnik.xml' })); var port = process.env['port']; strata.listen(port);
3. 進入服務端程序目錄,啟動程序
cd projectdir/tileserver/server
node cluster
可以看到四核CPU,就起了四個端口,效果如下:
六、OpenLayers使用多個瓦片服務器
如果我們看OpenStreetMap官網,就可以發現它使用的瓦片服務器可不止一台,下面我們看如何使用OpenStreetMap來實現類似效果(OpenStreetMap使用的是Leaflet)
只需要定義Tile時,指定 ulrs 屬性為一個瓦片服務Url的數組就行了
var tileStrataMapLayer = new ol.layer.Tile({ source: new ol.source.XYZ({ urls: [ 'http://192.168.1.51:8083/map/{z}/{x}/{y}/tile.png', 'http://192.168.1.99:8083/map/{z}/{x}/{y}/tile.png'] })});
效果如下:
后記:
前前后后好長時間了,主要還是時間嚴重不足,導致這個系列進度過於緩慢,而且每一篇都只能草草的講講過程,對於其中的原理講的很少。但這也沒有辦法,過完春節后可能工作要更忙了,所以OpenStreetMap、node-mapnik這個系列很可能不會再做深入的學習了。未來主要是想辦法將這些技術應用到工作中,以及提升這些技術的高性能、高可用性。歡迎有相同興趣的兄弟一起研討。每次寫文章,都是趁着休息時間弄,文字上面也不太講究,不太通順的地方請諒解。
如果非得讓我學點新的,我希望能實現Docker下的OpenStreetMap數據服務和OpenStreetMap數據的WMS服務。
轉載請注明原作者(think8848)和出處(http://think8848.cnblogs.com)