rocketmq刷盘过程
public enum FlushDiskType {
    // 同步刷盘
    SYNC_FLUSH,
    // 异步刷盘
    ASYNC_FLUSH
}
| 线程服务 | 场景 | 写消息性能 | 
| CommitRealTimeService | 异步刷盘 && 开启内存字节缓冲区 | 第一 | 
| FlushRealTimeService | 异步刷盘 | 第二 | 
| GroupCommitService | 同步刷盘 | 第三 | 
其中CommitRealTimeService是老一些版本中没有的,它为开启内存字节缓存的刷盘服务。
介绍各个线程工作之前,先需要重点了解一下waitForRunning方法,因为在三个刷盘服务线程中都频繁使用该方法:
protected void waitForRunning(long interval) {
        if (hasNotified.compareAndSet(true, false)) {
            this.onWaitEnd();
            return;
        }
        //entry to wait
        waitPoint.reset();
        try {
            waitPoint.await(interval, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            log.error("Interrupted", e);
        } finally {
            hasNotified.set(false);
            this.onWaitEnd();
        }
    }
shutdown()
stop()
wakeup()
这里我们关心的是wakeup()方法,调用wakeup方法的几处如下

public void run() {
            CommitLog.log.info(this.getServiceName() + " service started");
            while (!this.isStopped()) {
                try {
                    this.waitForRunning(10);
                    this.doCommit();
                } catch (Exception e) {
                    CommitLog.log.warn(this.getServiceName() + " service has exception. ", e);
                }
            }
            // Under normal circumstances shutdown, wait for the arrival of the
            // request, and then flush
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                CommitLog.log.warn("GroupCommitService Exception, ", e);
            }
            synchronized (this) {
                this.swapRequests();
            }
            this.doCommit();
            CommitLog.log.info(this.getServiceName() + " service end");
        }
if (FlushDiskType.SYNC_FLUSH == this.defaultMessageStore.getMessageStoreConfig().getFlushDiskType()) {
            final GroupCommitService service = (GroupCommitService) this.flushCommitLogService;
            if (messageExt.isWaitStoreMsgOK()) {
                GroupCommitRequest request = new GroupCommitRequest(result.getWroteOffset() + result.getWroteBytes());
                service.putRequest(request);
                boolean flushOK = request.waitForFlush(this.defaultMessageStore.getMessageStoreConfig().getSyncFlushTimeout());
                if (!flushOK) {
                    log.error("do groupcommit, wait for flush failed, topic: " + messageExt.getTopic() + " tags: " + messageExt.getTags()
                        + " client address: " + messageExt.getBornHostString());
                    putMessageResult.setPutMessageStatus(PutMessageStatus.FLUSH_DISK_TIMEOUT);
                }
            } else {
                service.wakeup();
            }
}
这条消息是否已经刷盘成功进行汇报的逻辑 -- waitForFlush方法:
public static class GroupCommitRequest {
        private final long nextOffset;
        private final CountDownLatch countDownLatch = new CountDownLatch(1);
        private volatile boolean flushOK = false;
        public GroupCommitRequest(long nextOffset) {
            this.nextOffset = nextOffset;
        }
        public long getNextOffset() {
            return nextOffset;
        }
        public void wakeupCustomer(final boolean flushOK) {
            this.flushOK = flushOK;
            this.countDownLatch.countDown();
        }
        public boolean waitForFlush(long timeout) {
            try {
 // 阻塞当前工作线程,等待时间5s后或者countDownLatch记数为0时,停止阻塞,执行下一条语句
                this.countDownLatch.await(timeout, TimeUnit.MILLISECONDS);
                return this.flushOK;
            } catch (InterruptedException e) {
                log.error("Interrupted", e);
                return false;
            }
        }
}
 private void swapRequests() {
        List<GroupCommitRequest> tmp = this.requestsWrite;
        this.requestsWrite = this.requestsRead;
        this.requestsRead = tmp;
}
private void doCommit() {
    //
            synchronized (this.requestsRead) {
                if (!this.requestsRead.isEmpty()) {
                    for (GroupCommitRequest req : this.requestsRead) {
                        // There may be a message in the next file, so a maximum of
                        // two times the flush
                        boolean flushOK = false;
                        for (int i = 0; i < 2 && !flushOK; i++) {
                            flushOK = CommitLog.this.mappedFileQueue.getFlushedWhere() >= req.getNextOffset();
                            if (!flushOK) {
                                CommitLog.this.mappedFileQueue.flush(0);
                            }
                        }
                        req.wakeupCustomer(flushOK);
                    }
                    long storeTimestamp = CommitLog.this.mappedFileQueue.getStoreTimestamp();
                    if (storeTimestamp > 0) {
                        CommitLog.this.defaultMessageStore.getStoreCheckpoint().setPhysicMsgTimestamp(storeTimestamp);
                    }
                    this.requestsRead.clear();
                } else {
                    // Because of individual messages is set to not sync flush, it
                    // will come to this process
                    CommitLog.this.mappedFileQueue.flush(0);
                }
            }
}
 public boolean flush(final int flushLeastPages) {
        boolean result = true;
        MappedFile mappedFile = this.findMappedFileByOffset(this.flushedWhere, false);
        if (mappedFile != null) {
            long tmpTimeStamp = mappedFile.getStoreTimestamp();
            int offset = mappedFile.flush(flushLeastPages);
            long where = mappedFile.getFileFromOffset() + offset;
            result = where == this.flushedWhere;
            this.flushedWhere = where;
            if (0 == flushLeastPages) {
                this.storeTimestamp = tmpTimeStamp;
            }
        }
        return result;
    }
commit
public boolean commit(final int commitLeastPages) {
        boolean result = true;
        MappedFile mappedFile = this.findMappedFileByOffset(this.committedWhere, false);
        if (mappedFile != null) {
            int offset = mappedFile.commit(commitLeastPages);
            long where = mappedFile.getFileFromOffset() + offset;
            result = where == this.committedWhere;
            this.committedWhere = where;
        }
        return result;
    }
rocketmq刷盘过程的更多相关文章
- RocketMQ消息丢失解决方案:同步刷盘+手动提交
		前言 之前我们一起了解了使用RocketMQ事务消息解决生产者发送消息时消息丢失的问题,但使用了事务消息后消息就一定不会丢失了吗,肯定是不能保证的. 因为虽然我们解决了生产者发送消息时候的消息丢失问题 ... 
- RocketMQ中Broker的刷盘源码分析
		上一篇博客的最后简单提了下CommitLog的刷盘 [RocketMQ中Broker的消息存储源码分析] (这篇博客和上一篇有很大的联系) Broker的CommitLog刷盘会启动一个线程,不停地 ... 
- 【RocketMQ】消息的刷盘机制
		刷盘策略 CommitLog的asyncPutMessage方法中可以看到在写入消息之后,调用了submitFlushRequest方法执行刷盘策略: public class CommitLog { ... 
- HTC A510C电信手机刷机过程
		HTC A510C电信手机刷机过程记录 Writed by Peter Hu(2014.6.7) ON WIN7_64 刷机需要的步骤: 1) 将S-ON加密保护式去掉,改成S-OFF模式,这样才能 ... 
- mq刷盘方式
		Broker 在收到Producer发送过来的消息后,会存入CommitLog对应的内存映射区中,见CommitLog类的putMessage方法.该方法执行OK后,会判断存储配置中刷盘模式:同步or ... 
- Rocket重试机制,消息模式,刷盘方式
		一.Consumer 批量消费(推模式) 可以通过 consumer.setConsumeMessageBatchMaxSize(10);//每次拉取10条 这里需要分为2种情况 Consumer端先 ... 
- MySQL InnoDB 日志管理机制中的MTR和日志刷盘
		1.MTR(mini-transaction) 在MySQL的 InnoDB日志管理机制中,有一个很重要的概念就是MTR.MTR是InnoDB存储擎中一个很重要的用来保证物理写的完整性和持久性的机制. ... 
- 【软件安装与环境配置】TX2刷机过程
		前言 使用TX2板子之前需要进行刷机,一般都是按照官网教程的步骤刷机,无奈买不起的宝宝只有TX2核心板,其他外设自己搭建,所以只能重新制作镜像,使用该镜像进行刷机. 系统需求 1.Host Platf ... 
- 从CM刷机过程和原理分析Android系统结构
		前面101篇文章都是分析Android系统源代码,似乎不够接地气. 假设能让Android系统源代码在真实设备上跑跑看效果,那该多好.这不就是传说中的刷ROM吗?刷ROM这个话题是老罗曾经一直避免谈的 ... 
随机推荐
- __getitem__ 专用方法
			(1) __getitem__ 专用方法很简单.像普通的方法 clear,keys 和 values 一样,它只是重定向到字典,返回字典的值.但是怎么调用它呢?哦,你可以直接调用 __getitem ... 
- C# 导出图片到Word (通过XML实现)
			private void ExportDataToWord(string content) { StringBuilder sbMain = new StringBuilder(); #region ... 
- python模块--json \ pickle  \  shelve  \   XML模块
			一.json模块 之前学习过的eval内置方法可以将一个字符串转成一个python对象,不过eval方法时有局限性的,对于普通的数据类型,json.loads和eval都能用,但遇到特殊类型的时候,e ... 
- centos6.6安装php5.3.3(2015/3/4)
			问题:centos6.6因要升级mysql5.5所以yum重新更新了源,导致按照原来lamp环境安装步骤,安装php时一直找webtitic源,php5.3.24 而且一直无法安装下去 利用yum r ... 
- bzoj 2597 [Wc2007]剪刀石头布——费用流
			题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2597 三个人之间的关系,除了“剪刀石头布”,就是有一个人赢了2局:所以考虑算补集,则每个人对 ... 
- 10.Python运行Scrapy时出现错误: ModuleNotFoundError: No module named 'win32api'
			1.在命令行输入:scrapy crawl demo(demo为爬虫标识,是唯一的) 2.报错信息如下所示: 3.解决方法:https://github.com/mhammond/pywin32/re ... 
- xunsearch的使用(二)
			1.查看配置文件vim /data/local/xunsearch/sdk/php/app/demo.ini [pid] type = id [subject] type = title [messa ... 
- java http头信息
			JAVA 从http请求头中获取Header信息: request.getHeader(),request.getHeaderNames(),request.getHeaders() Java获取Ht ... 
- common-lang3-version.jar 提供java.lang的扩展功能
			Apache Commons Lang 3.6 API 
- AD域中客户端时间与服务器同步
			1.域控配置 修改注册表,设置域控服务器名称 设置组策略,启动NTP服务器 域策略中设置windows time服务自动启动 2.客户端 更新域策略gpupdate /force 如果不重启的话,先n ... 
