分发
对于监控系统,需要处理很多数据,包括日志,对其中的数据采集,分析。
被监控数据对象就是数据的生产者producer,数据的处理程序就是消费者consumer。
生产者消费者模型的传统的模型,生产,消费的耦合度大,写在同一个代码中,如果生产规模扩大,就不易扩大,而且生产和消费的速度很难匹配.
简单的推拉模型,消费者主动要就是拉,生产者主动给就是推
如果消费者多,会消费速度大于生产速度,浪费资源,如果生产者多,会造成大量数据积压。
消费者和生产者的速度要匹配,消费速度略大于生产速度。假如消费者程序崩溃,可以保证运行的程序不会崩溃。
yield的思想是消费者决定速度,消费多快就去生产者取数据,但实际情况是生产者的生产是源源不断的,实际情况是数据大量的产生。
规模较大时,要分开生产者和消费者的代码,解决方案是消息队列
解决方案,队列,queue,消息应当先进先出
消息队列可以理解为超市模型,生产者只负责生产,消费者直接去消费
作用--解耦:代码是分开的,缓冲:缓冲数据,理解模型是大坝,
日志生产者会部署好几个程序,加入消息队列,消费者要在处理速度上略大于生产速度,速度匹配
数据有时效性,要及时处理,及时返回,指导生产,你的竞争对手随时都在加速
消息队列可以在容器内部建立多个队列,解决消费者处理速度不同的问题
数据生产的不稳定性,短时间的“潮涌”,需要缓冲。加缓冲队列就是解决方案
在单机中使用标准库queue模块,线程中使用threading,进程中是使用消息中间件
多进程的大型系统可以使用第三方中间件:较传统用RabbbitMQ ,RocketMQ, kafka(大数据喜欢用),都支持集群,在分布式系统中较常用,适合大型系统
如果数据瞬间就产生量极大,比如双十一的消费数据,可以到结束后再处理,就可以用到缓冲队列
消息队列可以平滑生产者和消费者模型的速度
queue 模块
from queue import Queue(类名大写)
Queue(先进先出),Lifo(后进先出,栈)
queue.Queue(maxsize=0),返回Queue对象。maxsize小于等于0,队列长度没有限制
q.empty()判断是否为空
q.full()判断是否满了,有size时才会满
q.put()加入队列,提交数据,可以提交所有合法数据,引用对象加入队列的是地址,range对象是引用对象,设置size时才会full
q.get(block=True,timeout=None)从队列取出。没有索引,队列不能在中间插入或者删除
空队列get在单线程中会阻塞,block阻塞,为False时,非阻塞行为,为空直接抛异常Empty,
timeout超时,等于None永久阻塞;block为False时,timeout无效;block为Ture时,会一直等(None)或者等一会(输入秒数)
q.get_nowait(),想当于q.get(False)
阻塞行为可以决定是否等待数据。
q.size,查看队列的大小,不是精确的,多线程中有多个消费者,你看到时,有可能已经被put了新的,或者get走了元素
get和put会一直等待结果,如果设置的时间到了,一定会抛异常,带有阻塞效果的都是这个原理
threading 线程模块
threading.Thread(group=None, target=None, name=None, args=(), kwargs=None, *, daemon=None)
target: 线程目标函数,args:参数
load函数就是从日志中提取合格的数据的生成器函数
可以作为dispatcher函数的数据源