汪微的博客
zane,做一个有思维的开发者

汪微的博客

zanePerfor在高流量项目下的架构配置建议实践说明

2019年04月04日870 browse

HI!,你好,我是zane,zanePerfor是一款我开发的一个前端性能监控平台,现在支持web浏览器端和微信小程序端。

我定义为一款完整,高性能,高可用的前端性能监控系统,这是未来会达到的目的,现今的架构也基本支持了高可用,高性能的部署。实际上还不够,在很多地方还有优化的空间,我会持续的优化和升级。

开源不易,如果你也热爱技术,拥抱开源,希望能小小的支持给个star。

项目的github地址:https://github.com/wangweianger/zanePerfor

项目开发文档说明:https://blog.seosiwei.com/performance/index.html


zanePerfor应用理论上能够支持千万级以上pv项目,但实际情况需要依赖于服务器和数据库的性能,以下项尽可能的从各种配置来提升应用的性能。

备注:以下内容以选择redis消息队列来阐述和说明。


一:相关项目配置项说明

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提供多进程模型和进程间通讯。

传送门:https://eggjs.org/zh-cn/core/cluster-and-ipc.html

开启方式:

// 应用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台服务器集群搭建完毕。

注意事项:对mongodb进行分片时需要绑定内网IP,不然请求无法连通。

备注:应用中对浏览器端 | 微信小程序端 默认使用 _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:设置服务器的权重,默认情况下为1
max_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 (1千多万ajax请求量)内暂未遇见性能问题。

至于redis集群的搭建此处暂不做介绍,暂时挂个官网参考链接:https://redis.io/topics/cluster-tutorial


zanePerfor在高流量项目下的架构配置建议实践说明(完)。



博主 zane 发表于 2019-04-04 17:20:14,添加在了 node.js 标签下

打赏

您的支持将鼓励我继续努力与分享。

扫码打赏,建议金额1-10元

提醒:打赏金额将直接进此方账号,无法退款,请您谨慎操作。

评论

正在加载验证码......

提交

2019-07-02 19:46:52

f's'd'f

2019-05-08 20:51:18

你可以加qq群并在里面反馈你所遇到的问题

2019-05-07 14:10:35

运行的时候报错,能帮忙解决一下吗

2019-04-29 10:52:46

👍

2019-04-05 13:15:01