HI!,你好,我是zane,zanePerfor是一款我开发的一个前端性能监控平台,现在支持web浏览器端和微信小程序端。
我定义为一款完整,高性能,高可用的前端性能监控系统,这是未来会达到的目的,现今的架构也基本支持了高可用,高性能的部署。实际上还不够,在很多地方还有优化的空间,我会持续的优化和升级。
开源不易,如果你也热爱技术,拥抱开源,希望能小小的支持给个star。
项目的github地址:github.com/wangweiange…
项目开发文档说明:blog.seosiwei.com/performance…
zanePerfor应用理论上能够支持千万级以上pv项目,但实际情况需要依赖于服务器和数据库的性能,以下项尽可能的从各种配置来提升应用的性能。
一:相关项目配置项说明
config.default.js 配置说明复制代码
1、servers集群模式下服务器之间主要通过内网进行通信,因此在这里hostname我们需要配置成内网IP,做如下更改即可
// 集群配置(一般默认即可)
config.cluster = {
listen: {
port: config.port,
hostname: address.ip(), // 此处替换127.0.0.1
ip: address.ip(),
},
};复制代码
2、实时统计任务在大流量项目下时间尽可能的长一些,即能减轻数据库的压力也能提升实时统计的准确性 (定时任务时间间隔建议5-20分钟之间)
// 执行pvuvip定时任务的时间间隔 默认每分钟定时执行一次 (可更改)
config.pvuvip_task_minute_time = '0 */1 * * * *';
// 更改为
config.pvuvip_task_minute_time = '0 */10 * * * *';复制代码
3、上报和消费数据方式选择redis
// 上报原始数据使用redis存储、kafka储存、还是使用mongodb存储
config.report_data_type = 'redis'; // redis mongodb kafka复制代码
4、在数据库性能足够强悍的情况下,每次定时任务的时间尽量短,消费的数据尽量多,消息队列池尽量不做限制
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',消费数据会成倍数增加)。
5、解析用户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',
};复制代码
6、mongodb集群模式下url链接需要更改为内网ip,连接池可以稍微调大一些
// mongodb 服务
const dbclients = {
db3: {
// 集群分片
url: 'mongodb://192.168.1.10:30000/performance',
options: {
autoReconnect: true,
poolSize: 50,
},
},
};复制代码
二:HTTP层面说明(以下内容已在程序中实现)
1、设置Connection,关闭keep-alive
为什么要关闭?
- 在高并发项目下,tcp保持连接时间不要太长,因此nginx的keepalive_timeout尽量设置的更短
- 同一域下请求频率低、请求次数少的http链接尽量减少tcp链接时间,因此keepalive_timeout尽量设置低
而对于本应用来说,上面两条都已满足,因此关闭keep-alive选项。
// node服务实现:
ctx.set('Connection', 'close');
// nginx服务实现:
http {
keepalive_timeout: 0;
}复制代码
2、返回空body信息
- 上报接口接收到请求就尽快返回状态码,逻辑处理放到后面处理
- body返回内容尽量简短或者为空
// 代码实现:
async wxReport() {
const { ctx } = this;
ctx.set('Access-Control-Allow-Origin', '*');
ctx.set('Connection', 'close');
ctx.status = 200;
// 后续逻辑处理...
}复制代码
三:node单机集群
使用node.js的Cluster 模块开启多进程,尽可能的榨干服务器资源,利用上多核 CPU 的并发优势。同时也保证单机服务的稳定性。
egg.js提供多进程模型和进程间通讯。
开启方式:
// 应用package.json
// 案例中开启两个worker进程,默认会开启服务器cpu核数个worker进程
"scripts": {
"start": "egg-scripts start --daemon --workers=2 --title=performance",
}复制代码
四:Mongodb集群搭建
高流量,高并发项目少不了mongodb集群的搭建,关于mongodb集群搭建请参考以下两篇文章:
zanePerfor前端性能监控平台高可用之Mongodb集群分片架构
zanePerfor前端性能监控平台高可用之Mongodb副本集读写分离架构
案例:现在有3台服务器,内网ip分别为:(10.1.0.86、10.1.0.97、10.1.0.70),现在我们来搭建由三台服务器组建的集群。
1、分别在每台服务器上创建如下3个文件
kdir -p /data/mongod/s0
mkdir -p /data/mongod/log
mkdir -p /data/mongod/c0复制代码
2、分别在每台服务器上启动Shard Server
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复制代码
3、分别在每台服务器上启动Config Server
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复制代码
4、配置副本集
// 进入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()复制代码
5、启动Route Process服务
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复制代码
6、配置Sharding分片
// 进入路由服务器
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();复制代码
7、设置分片数据库与片键
//指定需要分片的数据库
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台服务器集群搭建完毕。
备注:应用中对浏览器端 | 微信小程序端 默认使用 _id字段 进行分片, 尽量不要更改。
五:servers负载均衡
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;
}复制代码
参数说明:
weight=number:设置服务器的权重,默认情况下为1max_conns=number:限制到代理服务器的同时活动连接的最大数量,默认为0
max_fails=number:服务器通信的失败尝试次数
fail_timeout=number:服务器通信失败超时时间,默认为10
backup:将服务器标记为备份服务器。它将在主服务器不可用时传递请求
down:将服务器标记为永久不可用
六:redis集群
应用中有很多功能都会依赖于redis的缓存能力,因此一台高性能的redis或者redis集群显得很有必要。
官方如此介绍redis的强劲性能:性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s ,理论上来说单台redis就能满足绝大部分的应用。
至于redis是否需要集群的支持,需要根据各个应用的情况来决定,博主暂时用的单台redis,500w PV内暂未遇见性能问题。
至于redis集群的搭建此处暂不做介绍,暂时挂个官网参考链接:redis.io/topics/clus…
zanePerfor在高流量项目下的架构配置建议实践说明(完)。