作为网络数据的中转服务,很多时候会碰到生产数据量大于消费数据量的情况,最明显的就是消费方网络带宽不足的情况下。对于这种情况的处理,通常会采用一路阻塞的模式,阻塞数据到发送端。
但有时生产方的数据,消费者并不是一个,而是有多个消费者,例如直播。不能因为一个消费者的消费慢,进而影响所有消费者的数据消费。
看到这里,很多人应该会想到使用kafka之类的中间件,来解决这个问题,也的确可以解决。本文将阐述思路以更特定的方案解决该问题。
本章前提先不考虑数据可丢失的流程,那会有其它的解决方案(如直播的话可对慢消费者抛弃I帧及其随后的P帧),假设生产方的数据都需要消费方消费。
当生产方产生数据并被中转服务收取后,数据不是直接发送给消费者,而是在消费者前面增加了一个消费者管道,也就是说生产方产生的数据,将发送给对应消费者的管道,由管道服务负责把数据再发送给对应的消费者,下面详细阐述该管道的设计结构。
上图是整体数据流程图,绿色部分是整个缓存管理服务,而黄色部分是单个消费者的管道。
管道属性信息
1. 内存最大缓存数据量
生产方的数据在内存中能够放置的最大容量,以避免过大的内存开销。
2. 磁盘缓存数据信息
当内存不足以承担所有的待消费数据时,数据将会缓存到磁盘,并标识磁盘中未消费的数据起始位置,剩余消费数据量等信息。
3. 新数据发送回调接口
当有数据需要发往消费方时,调用该接口,并传递待消费的数据,进行数据的消费,接口返回消费的数据量,是否继续消费等信息。
管理接口信息
1. 添加生产方的数据
生产方产生数据时,调用该接口,检查是否已应用了磁盘缓存或内存额度已超标,如果是,则数据追加写入到磁盘缓存的最后,反之则直接添加到内存缓存区的最后。
数据放置到位后,触发一次驱动消费接口。
2.驱动消费接口
调用该接口时,检查内存缓存的数据,如果没有数据,则检查磁盘缓存的数据,如果也没有,则直接返回,反之从磁盘缓存加载一定量的数据到内存缓存。
在内存缓存有数据的情况下,调用“新数据发送回调接口”,传递最先进入的数据作为参数,根据调用返回的状态,抉择是否本数据已消费完毕(消费完毕需要从内存释放本次数据),是否触发下一个数据的消费。直到所有数据消费完毕或达到驱动消费次数。
3. 生产方管理接口
当明确知道生产方数据都已生产完毕的情况下,调用该接口,用于标识生产方已生产完毕,并根据管道是否需要等待缓存数据消费完毕才关闭的逻辑,抉择是否立即关闭管道。
如果需要等待管道数据消费完毕,那么在最后一个数据被消费掉后,并发现生产方已关闭的情况下,立即关闭管道,释放管道的所有资源,不然继续等待新的生产数据。
4. 消费方关闭接口
在消费方关闭管道的情况下,立即关闭该管道,释放所有资源。
缓存管理服务独立驱动流程
图中驱动器根据管道本身的周期,检查对应的管道,调用驱动消费接口,以确保在生产方不再有数据产生时,能够由该驱动流程触发管道内数据的消费完成。
备注:实际使用中,如果进入了磁盘缓存,但后续磁盘缓存信息被消费完毕,那么可以重置磁盘缓存信息,释放之前缓存的数据,同时后续在内存缓存不溢出的情况下,也不会再进入到磁盘缓存。