• 日志系统数据采集客户端的实现--并发编程容器选型


    一个集中的日志系统,第三方应用每次写日志,都需要发送一个远程的rpc或者http请求,造成写日志的延时比较大。

    改进的做法是:提供一个写日志调用包,第三方应用写日志时,先把日志缓存到一个线程安全的容器里,然后后台线程实时消费容器内的日志,如果有持久化的需求,就可以实时的把日志flush到文件中,然后再用另外一个线程消费文件真正把日志发送到日志服务器。

    所以我们需要一个线程安全的容器,以下是常见的并发编程容器。

    CopyOnWriteArrayList是线程安全的, 且处理读操作不需要进行同步和加锁. 所以读操作具有很好的并发性。
    CopyOnWriteArrayList的写操作是代价很大的, 所以CopyOnWriteArrayList只适用于读操作频率远远大于写操作频率的场景。


    ConcurrentHashMap在read时几乎不用加锁, 而write时使用的是细粒度的分段锁, ConcurrentHashMap甚至可以做到并发write。

    ConcurrentLinkedQueue是Queue的一个安全实现.Queue中元素按FIFO原则进行排序.采用CAS操作,来保证元素的一致性。ConcurrentLinkedQueue的API 原来.size() 是要遍历一遍集合的,所以尽量要避免用size而改用isEmpty()。

    LinkedBlockingQueue实现是线程安全的,实现了先进先出等特性,是作为生产者消费者的首选,LinkedBlockingQueue 可以指定容量,也可以不指定,不指定的话,默认最大是Integer.MAX_VALUE,其中主要用到put和take方法,put方法在队列满的时候会阻塞直到有队列成员被消费,take方法在队列空的时候会阻塞,直到有队列成员被放进来。

    针对引言提出的场景需求,就可以用LinkedBlockingQueue,因为阻塞的调用,只有当有日志的时候才会触发消费,这样不需要while定时检测,可以支持实时消费。

    实时消费日志可以写成线程,如下:

    
    
      public static LinkedBlockingQueue<String> logQueue = new LinkedBlockingQueue<String>();


    while
    (true) { StringBuilder content = new StringBuilder(); //如果容器里没有数据,会一直阻塞 take和poll的配合还是值得一提的 String log = logQueue.take(); int count = 0; //凑齐一定数量log,就持久化log while(log != null) { content.append(log+" "); count++; if(count >= 100) break; //这时候不用take,而是用poll方法,因为poll有超时机制。因为有超时机制,所以不会因为凑不齐设定数量的log永久耽误之前的log持久化 log = logQueue.poll(100,TimeUnit.MILLISECONDS); } appendToFile(content.toString()); }
  • 相关阅读:
    枚举EnumHelper
    日期相关转化 TimeHelper
    C# 环境变量设置
    PDF 文件操作 PdfHelper
    32位系统支持多大内存?
    我们对待西洋近代文明的态度
    深度剖析CPython解释器》Python内存管理深度剖析Python内存管理架构、内存池的实现原理
    Element2.15.6 版本 Carousel 走马灯,当循环项长度为2时,循环动画的运行方向不能始终一致的问题处理
    python globals()[]将字符串转化类,并通过反射执行方法
    Pycharm import faker 和 colorlog提示“No module name faker/colorlog”
  • 原文地址:https://www.cnblogs.com/yanghuahui/p/3761124.html
Copyright © 2020-2023  润新知