redis缓存高并发批量写入mysql测试

redis缓存高并发批量写入mysql测试

    • 测试环境
    • 需要安装的模块
    • 测试的场景
    • 结论

测试环境

nodejs v12.13.1
redis 3.20.1000 windows版(不要鄙视我)
mysql 8.0

需要安装的模块

在npm上安装redis,cron定时任务模块,mysql模块.

测试的场景

主要针对物联网系统,带的设备数量比较多,写入操作居多,读取操作并不是很多.
与设备通讯时会产生大量的写入操作,如果直接用mysql单条写入,效率极其低下,node的性能根本发挥不出来,使用redis做缓存,定时任务从缓存读取数据,并单次批量存入数据库,减少数据库io,效率和稳定性能够大幅提升.

redis使用list类型保存缓存数据,随便写个get接口,收到请求时只要redis保存了,就可以返回结果.

let que = (req,res,next)=> {
	//适合存库的数据体
	let inObj = ['id','2020-01-06',222,'fwe2242df32edg']
	client.lpush('imgList',JSON.stringify(inObj),redis.print)
	res.send('xxx')
}

使用cron模块启动一个10秒执行一次的定时任务,具体间隔根据业务自测.
如果有请求发生,接口压入list中的数据就会在这里获取到,如果list中有数据,就会取出所有数据,转换成可以批量存入mysql的二维数组,最核心的代码就是那三个叹号的注释,测了一天,放在这里数据才不会丢失.
如果放在lrange里面,高并发时总会丢几条数据,经测试redis写入操作并没有丢,mysql批量存储也不会丢,那就是lrange的异步操作内使用del时,可能又压入了几条数据,读取到的items和del的数据不一致导致.放到紧挨着lrange后面就不会发生这种情况了.
但是redis也是单线程模型,这样写总感觉会读取不到数据,但事实是这样写很稳定,可能是lrange执行会极其短暂的阻塞进程,也没有找到相关的说明,忘指点…

const dataInJob = new cronJob('*/10 * * * * *', ()=> {
	console.log('定时任务启动')
    client.lrange('imgList', 0, -1, (err, items)=> {
		if (err) throw err
		if (items.length) {
			let arr = []
			for (let i = 0; i < items.length; i++) {
				arr.push(JSON.parse(items[i]))
			}			
			//saveFile(arr)
			saveDb(arr)
		}
	})
	//一定要写在这里,不然会丢数据!!!
	client.del('imgList')

}, null, false, 'Asia/Shanghai')

async function saveDb(list) {
	let sql = 'INSERT INTO meter_data (module_num,DATE,VALUE,img_url) VALUES ?;'
	await db(sql,[list])
}

最后使用ab压测工具
每次1000个并发,共计10000个,反复测试稳定运行.
redis缓存高并发批量写入mysql测试_第1张图片
mysql稳稳的保存住10000条数据
在这里插入图片描述

结论

也可以当作消息队列一条一条顺序慢慢处理,但那样不方便批量写入数据,执行效率并不是很高.具体可以搜索mysql单条写入和批量写入的对比文章.
代码只是测试,没有错误处理,生产中使用仍需完善.

你可能感兴趣的:(redis缓存高并发批量写入mysql测试)