HI!,你好,我是zane,zanePerfor是一款我開發的一個前端性能監控平臺,如今支持web瀏覽器端和微信小程序端。html
我定義爲一款完整,高性能,高可用的前端性能監控系統,這是將來會達到的目的,現今的架構也基本支持了高可用,高性能的部署。實際上還不夠,在不少地方還有優化的空間,我會持續的優化和升級。前端
開源不易,若是你也熱愛技術,擁抱開源,但願能小小的支持給個star。node
項目的github地址:github.com/wangweiange…nginx
項目開發文檔說明:blog.seosiwei.com/performance…git
zanePerfor應用理論上可以支持千萬級以上pv項目,但實際狀況須要依賴於服務器和數據庫的性能,如下項儘量的從各類配置來提高應用的性能。github
config.default.js 配置說明複製代碼
一、servers集羣模式下服務器之間主要經過內網進行通訊,所以在這裏hostname咱們須要配置成內網IP,作以下更改便可
web
// 集羣配置(通常默認便可)
config.cluster = {
listen: {
port: config.port,
hostname: address.ip(), // 此處替換127.0.0.1
ip: address.ip(),
},
};複製代碼
二、實時統計任務在大流量項目下時間儘量的長一些,即能減輕數據庫的壓力也能提高實時統計的準確性 (定時任務時間間隔建議5-20分鐘之間)ajax
// 執行pvuvip定時任務的時間間隔 默認每分鐘定時執行一次 (可更改)
config.pvuvip_task_minute_time = '0 */1 * * * *';
// 更改成
config.pvuvip_task_minute_time = '0 */10 * * * *';複製代碼
三、上報和消費數據方式選擇redisredis
// 上報原始數據使用redis存儲、kafka儲存、仍是使用mongodb存儲
config.report_data_type = 'redis'; // redis mongodb kafka複製代碼
四、在數據庫性能足夠強悍的狀況下,每次定時任務的時間儘可能短,消費的數據儘可能多,消息隊列池儘可能不作限制mongodb
config.redis_consumption = {
// 定時任務執行時間
task_time: '*/10 * * * * *',
// 每次定時任務消費線程數(web端)
thread_web: 2000,
// 每次定時任務消費線程數(wx端)
thread_wx: 2000,
// 消息隊列池限制數, 0:不限制 number: 限制條數,高併發時服務優雅降級方案
total_limit_web: 0,
total_limit_wx: 0,
};複製代碼
task_time 消費消息定時任務間隔
thread_wx 每次消費數據條數
total_limit_wx 限制消息隊列中總條數
以上配置表示:每10秒鐘消費2000條數據,不對上報數據條數作限制 (若是定時任務設置了type: 'all',消費數據會成倍數增長)。
五、解析用戶IP使用redis方式,並關閉文件緩存(備註:流量大時,本地文件存儲的數據會比較大,每次加載會比較耗時)
// 解析用戶ip地址爲城市是使用redis仍是使用mongodb
config.ip_redis_or_mongodb = 'redis'; // redus mongodb
// 文件緩存ip對應地理位置(文件名)
config.ip_city_cache_file = {
isuse: false, // 是否開啓本地文件緩存(數據量太大時建議不開啓)
web: 'web_ip_city_cache_file.txt',
wx: 'wx_ip_city_cache_file.txt',
};複製代碼
六、mongodb集羣模式下url連接須要更改成內網ip,鏈接池能夠稍微調大一些
// mongodb 服務
const dbclients = {
db3: {
// 集羣分片
url: 'mongodb://192.168.1.10:30000/performance',
options: {
autoReconnect: true,
poolSize: 50,
},
},
};複製代碼
爲何要關閉?
而對於本應用來講,上面兩條都已知足,所以關閉keep-alive選項。
// node服務實現:
ctx.set('Connection', 'close');
// nginx服務實現:
http {
keepalive_timeout: 0;
}複製代碼
// 代碼實現:
async wxReport() {
const { ctx } = this;
ctx.set('Access-Control-Allow-Origin', '*');
ctx.set('Connection', 'close');
ctx.status = 200;
// 後續邏輯處理...
}複製代碼
使用node.js的Cluster 模塊開啓多進程,儘量的榨乾服務器資源,利用上多核 CPU 的併發優點。同時也保證單機服務的穩定性。
egg.js提供多進程模型和進程間通信。
開啓方式:
// 應用package.json
// 案例中開啓兩個worker進程,默認會開啓服務器cpu核數個worker進程
"scripts": {
"start": "egg-scripts start --daemon --workers=2 --title=performance",
}複製代碼
高流量,高併發項目少不了mongodb集羣的搭建,關於mongodb集羣搭建請參考如下兩篇文章:
zanePerfor前端性能監控平臺高可用之Mongodb集羣分片架構
zanePerfor前端性能監控平臺高可用之Mongodb副本集讀寫分離架構
案例:如今有3臺服務器,內網ip分別爲:(10.1.0.8六、10.1.0.9七、10.1.0.70),如今咱們來搭建由三臺服務器組建的集羣。
kdir -p /data/mongod/s0
mkdir -p /data/mongod/log
mkdir -p /data/mongod/c0複製代碼
mongod --dbpath /data/mongod/s0 --logpath /data/mongod/log/s0.log --fork --smallfiles --port 27020 --bind_ip 10.1.0.86 --shardsvr
mongod --dbpath /data/mongod/s0 --logpath /data/mongod/log/s0.log --fork --smallfiles --port 27020 --bind_ip 10.1.0.97 --shardsvr
mongod --dbpath /data/mongod/s0 --logpath /data/mongod/log/s0.log --fork --smallfiles --port 27020 --bind_ip 10.1.0.70 --shardsvr複製代碼
mongod --dbpath /data/mongod/c0 --logpath /data/mongod/log/c0.log --fork --smallfiles --port 27100 --bind_ip 10.1.0.86 --replSet rs1 --configsvr
mongod --dbpath /data/mongod/c0 --logpath /data/mongod/log/c0.log --fork --smallfiles --port 27100 --bind_ip 10.1.0.97 --replSet rs1 --configsvr
mongod --dbpath /data/mongod/c0 --logpath /data/mongod/log/c0.log --fork --smallfiles --port 27100 --bind_ip 10.1.0.70 --replSet rs1 --configsvr複製代碼
// 進入97的mongo
mongo --port 27100 --host 10.1.0.97
// 使用admin帳戶
use admin
// 初始化副本集
rs.initiate({_id:"rs1",members:[{_id:0,host:"10.1.0.97:27100"},{_id:1,host:"10.1.0.86:27100"},{_id:2,host:"10.1.0.70:27100"}]})
// 查看副本集狀態
rs.status()複製代碼
mongos --logpath /data/mongod/log/mongo.log --port 30000 --bind_ip 10.1.0.97 --fork --configdb rs1/10.1.0.97:27100,10.1.0.86:27100,10.1.0.70:27100複製代碼
// 進入路由服務器
mongo --port 30000 --host 10.1.0.97
// 添加分片
sh.addShard("10.1.0.97:27020")
sh.addShard("10.1.0.86:27020")
sh.addShard("10.1.0.70:27020")
// 查看分片信息
sh.status();複製代碼
//指定須要分片的數據庫
sh.enableSharding("performance")
//建立索引(須要對片建建立索引)
db.wx_ajaxs_wx3feeea844b1d03ffs.ensureIndex({"path":1})
//設置分片(對performance數據庫的wx_ajaxs_wx3feeea844b1d03ffs表按照path字段以hashed的方式分片)
sh.shardCollection("performance.wx_ajaxs_wx3feeea844b1d03ffs", { "path": "hashed"})
//查看分片信息
sh.status()複製代碼
其餘表分片重複以上步驟便可, 至此一個簡單的3臺服務器集羣搭建完畢。
servers負載:即把全部上報的請求分發到不一樣的servers進行處理,減少單個servers服務的壓力,也減輕了單個服務器的壓力。
zanePerfor作到了一套代碼多服務部署的方案
應用保證了多服務同時運行時,task任務不重複執行
此處servers負載均衡採用nginx方案,ng配置以下:
upstream ps-servers {
server 10.1.0.86:7001 weight=1 max_fails=4 fail_timeout=5;
server 10.1.0.97:7001 weight=1 max_fails=4 fail_timeout=5;
server 10.1.0.70:7001 weight=2 max_fails=4 fail_timeout=5;
}複製代碼
應用中有不少功能都會依賴於redis的緩存能力,所以一臺高性能的redis或者redis集羣顯得頗有必要。
官方如此介紹redis的強勁性能:性能極高 – Redis能讀的速度是110000次/s,寫的速度是81000次/s ,理論上來講單臺redis就能知足絕大部分的應用。
至於redis是否須要集羣的支持,須要根據各個應用的狀況來決定,博主暫時用的單臺redis,500w PV內暫未碰見性能問題。
至於redis集羣的搭建此處暫不作介紹,暫時掛個官網參考連接:redis.io/topics/clus…
zanePerfor在高流量項目下的架構配置建議實踐說明(完)。