日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

RocketMQ 源码分析 事务消息

發布時間:2023/12/15 编程问答 51 豆豆
生活随笔 收集整理的這篇文章主要介紹了 RocketMQ 源码分析 事务消息 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

為什么80%的碼農都做不了架構師?>>> ??

1. 概述

必須必須必須?前置閱讀內容:

  • 《事務消息(阿里云)》

2. 事務消息發送

2.1 Producer 發送事務消息

  • 活動圖如下(結合?核心代碼?理解):

  • 實現代碼如下:
1: // 【DefaultMQProducerImpl.java】2: /**3: * 發送事務消息4: *5: * @param msg 消息6: * @param tranExecuter 【本地事務】執行器7: * @param arg 【本地事務】執行器參數8: * @return 事務發送結果9: * @throws MQClientException 當 Client 發生異常時10: */11: public TransactionSendResult sendMessageInTransaction(final Message msg, final LocalTransactionExecuter tranExecuter, final Object arg)12: throws MQClientException {13: if (null == tranExecuter) {14: throw new MQClientException("tranExecutor is null", null);15: }16: Validators.checkMessage(msg, this.defaultMQProducer);17: 18: // 發送【Half消息】19: SendResult sendResult;20: MessageAccessor.putProperty(msg, MessageConst.PROPERTY_TRANSACTION_PREPARED, "true");21: MessageAccessor.putProperty(msg, MessageConst.PROPERTY_PRODUCER_GROUP, this.defaultMQProducer.getProducerGroup());22: try {23: sendResult = this.send(msg);24: } catch (Exception e) {25: throw new MQClientException("send message Exception", e);26: }27: 28: // 處理發送【Half消息】結果29: LocalTransactionState localTransactionState = LocalTransactionState.UNKNOW;30: Throwable localException = null;31: switch (sendResult.getSendStatus()) {32: // 發送【Half消息】成功,執行【本地事務】邏輯33: case SEND_OK: {34: try {35: if (sendResult.getTransactionId() != null) { // 事務編號,目前開源版本暫時沒用到,猜想ONS在使用36: msg.putUserProperty("__transactionId__", sendResult.getTransactionId());37: }38: 39: // 執行【本地事務】邏輯40: localTransactionState = tranExecuter.executeLocalTransactionBranch(msg, arg);41: if (null == localTransactionState) {42: localTransactionState = LocalTransactionState.UNKNOW;43: }44: 45: if (localTransactionState != LocalTransactionState.COMMIT_MESSAGE) {46: log.info("executeLocalTransactionBranch return {}", localTransactionState);47: log.info(msg.toString());48: }49: } catch (Throwable e) {50: log.info("executeLocalTransactionBranch exception", e);51: log.info(msg.toString());52: localException = e;53: }54: }55: break;56: // 發送【Half消息】失敗,標記【本地事務】狀態為回滾57: case FLUSH_DISK_TIMEOUT:58: case FLUSH_SLAVE_TIMEOUT:59: case SLAVE_NOT_AVAILABLE:60: localTransactionState = LocalTransactionState.ROLLBACK_MESSAGE;61: break;62: default:63: break;64: }65: 66: // 結束事務:提交消息 COMMIT / ROLLBACK67: try {68: this.endTransaction(sendResult, localTransactionState, localException);69: } catch (Exception e) {70: log.warn("local transaction execute " + localTransactionState + ", but end broker transaction failed", e);71: }72: 73: // 返回【事務發送結果】74: TransactionSendResult transactionSendResult = new TransactionSendResult();75: transactionSendResult.setSendStatus(sendResult.getSendStatus());76: transactionSendResult.setMessageQueue(sendResult.getMessageQueue());77: transactionSendResult.setMsgId(sendResult.getMsgId());78: transactionSendResult.setQueueOffset(sendResult.getQueueOffset());79: transactionSendResult.setTransactionId(sendResult.getTransactionId());80: transactionSendResult.setLocalTransactionState(localTransactionState);81: return transactionSendResult;82: }83: 84: /**85: * 結束事務:提交消息 COMMIT / ROLLBACK86: *87: * @param sendResult 發送【Half消息】結果88: * @param localTransactionState 【本地事務】狀態89: * @param localException 執行【本地事務】邏輯產生的異常90: * @throws RemotingException 當遠程調用發生異常時91: * @throws MQBrokerException 當 Broker 發生異常時92: * @throws InterruptedException 當線程中斷時93: * @throws UnknownHostException 當解碼消息編號失敗是94: */95: public void endTransaction(//96: final SendResult sendResult, //97: final LocalTransactionState localTransactionState, //98: final Throwable localException) throws RemotingException, MQBrokerException, InterruptedException, UnknownHostException {99: // 解碼消息編號 100: final MessageId id; 101: if (sendResult.getOffsetMsgId() != null) { 102: id = MessageDecoder.decodeMessageId(sendResult.getOffsetMsgId()); 103: } else { 104: id = MessageDecoder.decodeMessageId(sendResult.getMsgId()); 105: } 106: 107: // 創建請求 108: String transactionId = sendResult.getTransactionId(); 109: final String brokerAddr = this.mQClientFactory.findBrokerAddressInPublish(sendResult.getMessageQueue().getBrokerName()); 110: EndTransactionRequestHeader requestHeader = new EndTransactionRequestHeader(); 111: requestHeader.setTransactionId(transactionId); 112: requestHeader.setCommitLogOffset(id.getOffset()); 113: switch (localTransactionState) { 114: case COMMIT_MESSAGE: 115: requestHeader.setCommitOrRollback(MessageSysFlag.TRANSACTION_COMMIT_TYPE); 116: break; 117: case ROLLBACK_MESSAGE: 118: requestHeader.setCommitOrRollback(MessageSysFlag.TRANSACTION_ROLLBACK_TYPE); 119: break; 120: case UNKNOW: 121: requestHeader.setCommitOrRollback(MessageSysFlag.TRANSACTION_NOT_TYPE); 122: break; 123: default: 124: break; 125: } 126: requestHeader.setProducerGroup(this.defaultMQProducer.getProducerGroup()); 127: requestHeader.setTranStateTableOffset(sendResult.getQueueOffset()); 128: requestHeader.setMsgId(sendResult.getMsgId()); 129: String remark = localException != null ? ("executeLocalTransactionBranch exception: " + localException.toString()) : null; 130: 131: // 提交消息 COMMIT / ROLLBACK!!!通信方式為:Oneway!!! 132: this.mQClientFactory.getMQClientAPIImpl().endTransactionOneway(brokerAddr, requestHeader, remark, this.defaultMQProducer.getSendMsgTimeout()); 133: }

2.2 Broker 處理結束事務請求

  • ?查詢請求的消息,進行提交 / 回滾。實現代碼如下:
1: // 【EndTransactionProcessor.java】2: public RemotingCommand processRequest(ChannelHandlerContext ctx, RemotingCommand request) throws RemotingCommandException {3: final RemotingCommand response = RemotingCommand.createResponseCommand(null);4: final EndTransactionRequestHeader requestHeader = (EndTransactionRequestHeader) request.decodeCommandCustomHeader(EndTransactionRequestHeader.class);5: 6: // 省略代碼 =》打印日志(只處理 COMMIT / ROLLBACK)7: 8: // 查詢提交的消息9: final MessageExt msgExt = this.brokerController.getMessageStore().lookMessageByOffset(requestHeader.getCommitLogOffset()); 10: if (msgExt != null) { 11: // 省略代碼 =》校驗消息 12: 13: // 生成消息 14: MessageExtBrokerInner msgInner = this.endMessageTransaction(msgExt); 15: msgInner.setSysFlag(MessageSysFlag.resetTransactionValue(msgInner.getSysFlag(), requestHeader.getCommitOrRollback())); 16: msgInner.setQueueOffset(requestHeader.getTranStateTableOffset()); 17: msgInner.setPreparedTransactionOffset(requestHeader.getCommitLogOffset()); 18: msgInner.setStoreTimestamp(msgExt.getStoreTimestamp()); 19: if (MessageSysFlag.TRANSACTION_ROLLBACK_TYPE == requestHeader.getCommitOrRollback()) { 20: msgInner.setBody(null); 21: } 22: 23: // 存儲生成消息 24: final MessageStore messageStore = this.brokerController.getMessageStore(); 25: final PutMessageResult putMessageResult = messageStore.putMessage(msgInner); 26: 27: // 處理存儲結果 28: if (putMessageResult != null) { 29: switch (putMessageResult.getPutMessageStatus()) { 30: // Success 31: case PUT_OK: 32: case FLUSH_DISK_TIMEOUT: 33: case FLUSH_SLAVE_TIMEOUT: 34: case SLAVE_NOT_AVAILABLE: 35: response.setCode(ResponseCode.SUCCESS); 36: response.setRemark(null); 37: break; 38: // Failed 39: case CREATE_MAPEDFILE_FAILED: 40: response.setCode(ResponseCode.SYSTEM_ERROR); 41: response.setRemark("create maped file failed."); 42: break; 43: case MESSAGE_ILLEGAL: 44: case PROPERTIES_SIZE_EXCEEDED: 45: response.setCode(ResponseCode.MESSAGE_ILLEGAL); 46: response.setRemark("the message is illegal, maybe msg body or properties length not matched. msg body length limit 128k, msg properties length limit 32k."); 47: break; 48: case SERVICE_NOT_AVAILABLE: 49: response.setCode(ResponseCode.SERVICE_NOT_AVAILABLE); 50: response.setRemark("service not available now."); 51: break; 52: case OS_PAGECACHE_BUSY: 53: response.setCode(ResponseCode.SYSTEM_ERROR); 54: response.setRemark("OS page cache busy, please try another machine"); 55: break; 56: case UNKNOWN_ERROR: 57: response.setCode(ResponseCode.SYSTEM_ERROR); 58: response.setRemark("UNKNOWN_ERROR"); 59: break; 60: default: 61: response.setCode(ResponseCode.SYSTEM_ERROR); 62: response.setRemark("UNKNOWN_ERROR DEFAULT"); 63: break; 64: } 65: 66: return response; 67: } else { 68: response.setCode(ResponseCode.SYSTEM_ERROR); 69: response.setRemark("store putMessage return null"); 70: } 71: } else { 72: response.setCode(ResponseCode.SYSTEM_ERROR); 73: response.setRemark("find prepared transaction message failed"); 74: return response; 75: } 76: 77: return response; 78: }

2.3 Broker 生成 ConsumeQueue

  • ?事務消息,提交(COMMIT)后才生成?ConsumeQueue。
1: // 【DefaultMessageStore.java】2: public void doDispatch(DispatchRequest req) {3: // 非事務消息 或 事務提交消息 建立 消息位置信息 到 ConsumeQueue4: final int tranType = MessageSysFlag.getTransactionValue(req.getSysFlag());5: switch (tranType) {6: case MessageSysFlag.TRANSACTION_NOT_TYPE: // 非事務消息7: case MessageSysFlag.TRANSACTION_COMMIT_TYPE: // 事務消息COMMIT8: DefaultMessageStore.this.putMessagePositionInfo(req.getTopic(), req.getQueueId(), req.getCommitLogOffset(), req.getMsgSize(),9: req.getTagsCode(), req.getStoreTimestamp(), req.getConsumeQueueOffset()); 10: break; 11: case MessageSysFlag.TRANSACTION_PREPARED_TYPE: // 事務消息PREPARED 12: case MessageSysFlag.TRANSACTION_ROLLBACK_TYPE: // 事務消息ROLLBACK 13: break; 14: } 15: // 省略代碼 => 建立 索引信息 到 IndexFile 16: }

3. 事務消息回查

  • 【事務消息回查】功能曾經開源過,目前(V4.0.0)暫未開源。如下是該功能的開源情況:
版本【事務消息回查】?
官方V3.0.4 ~ V3.1.4基于 文件系統 實現已開源
官方V3.1.5 ~ V4.0.0基于 數據庫 實現未完全開源

我們來看看兩種情況下是怎么實現的。

3.1 Broker 發起【事務消息回查】

3.1.1 官方V3.1.4:基于文件系統

倉庫地址:https://github.com/YunaiV/rocketmq-3.1.9/tree/release_3.1.4

相較于普通消息,【事務消息】多依賴如下三個組件:

  • TransactionStateService?:事務狀態服務,負責對【事務消息】進行管理,包括存儲與更新事務消息狀態、回查事務消息狀態等等。
  • TranStateTable?:【事務消息】狀態存儲。基于?MappedFileQueue?實現,默認存儲路徑為~/store/transaction/statetable,每條【事務消息】狀態存儲結構如下:
第幾位字段說明數據類型字節數
1offsetCommitLog 物理存儲位置Long8
2size消息長度Int4
3timestamp消息存儲時間,單位:秒Int4
4producerGroupHashproducerGroup 求 HashCodeInt4
5state事務狀態Int4
  • TranRedoLog?:TranStateTable?重放日志,每次寫操作?TranStateTable?記錄重放日志。當Broker?異常關閉時,使用?TranRedoLog?恢復?TranStateTable。基于?ConsumeQueue?實現,Topic?為?TRANSACTION_REDOLOG_TOPIC_XXXX,默認存儲路徑為?~/store/transaction/redolog。

簡單手繪邏輯圖如下?:

3.1.1.1 存儲消息到 CommitLog

  • 存儲【half消息】到?CommitLog?時,消息隊列位置(queueOffset)使用?TranStateTable?最大物理位置(可寫入物理位置)。這樣,消息可以索引到自己對應的?TranStateTable?的位置和記錄。

核心代碼如下:

1: // 【DefaultAppendMessageCallback.java】2: class DefaultAppendMessageCallback implements AppendMessageCallback {3: public AppendMessageResult doAppend(final long fileFromOffset, final ByteBuffer byteBuffer, final int maxBlank, final Object msg) {4: // ... ...5: 6: // 事務消息需要特殊處理 7: final int tranType = MessageSysFlag.getTransactionValue(msgInner.getSysFlag());8: switch (tranType) {9: case MessageSysFlag.TransactionPreparedType: // 消息隊列位置(queueOffset)使用 TranStateTable 最大物理位置(可寫入物理位置) 10: queueOffset = CommitLog.this.defaultMessageStore.getTransactionStateService().getTranStateTableOffset().get(); 11: break; 12: case MessageSysFlag.TransactionRollbackType: 13: queueOffset = msgInner.getQueueOffset(); 14: break; 15: case MessageSysFlag.TransactionNotType: 16: case MessageSysFlag.TransactionCommitType: 17: default: 18: break; 19: } 20: 21: // ... ... 22: 23: switch (tranType) { 24: case MessageSysFlag.TransactionPreparedType: 25: // 更新 TranStateTable 最大物理位置(可寫入物理位置) 26: CommitLog.this.defaultMessageStore.getTransactionStateService().getTranStateTableOffset().incrementAndGet(); 27: break; 28: case MessageSysFlag.TransactionRollbackType: 29: break; 30: case MessageSysFlag.TransactionNotType: 31: case MessageSysFlag.TransactionCommitType: 32: // 更新下一次的ConsumeQueue信息 33: CommitLog.this.topicQueueTable.put(key, ++queueOffset); 34: break; 35: default: 36: break; 37: } 38: 39: // 返回結果 40: return result; 41: } 42: }

3.1.1.2 寫【事務消息】狀態存儲(TranStateTable)

  • 處理【Half消息】時,新增【事務消息】狀態存儲(TranStateTable)。
  • 處理【Commit / Rollback消息】時,更新 【事務消息】狀態存儲(TranStateTable) COMMIT / ROLLBACK。
  • 每次寫操作【事務消息】狀態存儲(TranStateTable),記錄重放日志(TranRedoLog)。

核心代碼如下:

1: // 【DispatchMessageService.java】2: private void doDispatch() {3: if (!this.requestsRead.isEmpty()) {4: for (DispatchRequest req : this.requestsRead) {5: 6: // ... ...7: 8: // 2、寫【事務消息】狀態存儲(TranStateTable)9: if (req.getProducerGroup() != null) {10: switch (tranType) {11: case MessageSysFlag.TransactionNotType:12: break;13: case MessageSysFlag.TransactionPreparedType:14: // 新增 【事務消息】狀態存儲(TranStateTable)15: DefaultMessageStore.this.getTransactionStateService().appendPreparedTransaction(16: req.getCommitLogOffset(), req.getMsgSize(), (int) (req.getStoreTimestamp() / 1000), req.getProducerGroup().hashCode());17: break;18: case MessageSysFlag.TransactionCommitType:19: case MessageSysFlag.TransactionRollbackType:20: // 更新 【事務消息】狀態存儲(TranStateTable) COMMIT / ROLLBACK21: DefaultMessageStore.this.getTransactionStateService().updateTransactionState(22: req.getTranStateTableOffset(), req.getPreparedTransactionOffset(), req.getProducerGroup().hashCode(), tranType);23: break;24: }25: }26: // 3、記錄 TranRedoLog27: switch (tranType) {28: case MessageSysFlag.TransactionNotType:29: break;30: case MessageSysFlag.TransactionPreparedType:31: // 記錄 TranRedoLog32: DefaultMessageStore.this.getTransactionStateService().getTranRedoLog().putMessagePostionInfoWrapper(33: req.getCommitLogOffset(), req.getMsgSize(), TransactionStateService.PreparedMessageTagsCode,34: req.getStoreTimestamp(), 0L);35: break;36: case MessageSysFlag.TransactionCommitType:37: case MessageSysFlag.TransactionRollbackType:38: // 記錄 TranRedoLog39: DefaultMessageStore.this.getTransactionStateService().getTranRedoLog().putMessagePostionInfoWrapper(40: req.getCommitLogOffset(), req.getMsgSize(), req.getPreparedTransactionOffset(),41: req.getStoreTimestamp(), 0L);42: break;43: }44: }45: 46: // ...省略代碼47: }48: }49: // ??????【TransactionStateService.java】50: /**51: * 新增事務狀態52: *53: * @param clOffset commitLog 物理位置54: * @param size 消息長度55: * @param timestamp 消息存儲時間56: * @param groupHashCode groupHashCode57: * @return 是否成功58: */59: public boolean appendPreparedTransaction(//60: final long clOffset,//61: final int size,//62: final int timestamp,//63: final int groupHashCode//64: ) {65: MapedFile mapedFile = this.tranStateTable.getLastMapedFile();66: if (null == mapedFile) {67: log.error("appendPreparedTransaction: create mapedfile error.");68: return false;69: }70: 71: // 首次創建,加入定時任務中72: if (0 == mapedFile.getWrotePostion()) {73: this.addTimerTask(mapedFile);74: }75: 76: this.byteBufferAppend.position(0);77: this.byteBufferAppend.limit(TSStoreUnitSize);78: 79: // Commit Log Offset80: this.byteBufferAppend.putLong(clOffset);81: // Message Size82: this.byteBufferAppend.putInt(size);83: // Timestamp84: this.byteBufferAppend.putInt(timestamp);85: // Producer Group Hashcode86: this.byteBufferAppend.putInt(groupHashCode);87: // Transaction State88: this.byteBufferAppend.putInt(MessageSysFlag.TransactionPreparedType);89: 90: return mapedFile.appendMessage(this.byteBufferAppend.array());91: }92: 93: /**94: * 更新事務狀態95: *96: * @param tsOffset tranStateTable 物理位置97: * @param clOffset commitLog 物理位置98: * @param groupHashCode groupHashCode99: * @param state 事務狀態 100: * @return 是否成功 101: */ 102: public boolean updateTransactionState( 103: final long tsOffset, 104: final long clOffset, 105: final int groupHashCode, 106: final int state) { 107: SelectMapedBufferResult selectMapedBufferResult = this.findTransactionBuffer(tsOffset); 108: if (selectMapedBufferResult != null) { 109: try { 110: // 校驗是否能夠更新 111: // .... ... 112: 113: // 更新事務狀態 114: selectMapedBufferResult.getByteBuffer().putInt(TS_STATE_POS, state); 115: } 116: catch (Exception e) { 117: log.error("updateTransactionState exception", e); 118: } 119: finally { 120: selectMapedBufferResult.release(); 121: } 122: } 123: 124: return false; 125: }

3.1.1.3 【事務消息】回查

  • TranStateTable?每個?MappedFile?都對應一個?Timer。Timer?固定周期(默認:60s)遍歷MappedFile,查找【half消息】,向?Producer?發起【事務消息】回查請求。【事務消息】回查結果的邏輯不在此處進行,在?CommitLog dispatch時執行。

實現代碼如下:

1: // 【TransactionStateService.java】2: /**3: * 初始化定時任務4: */5: private void initTimerTask() {6: //7: final List<MapedFile> mapedFiles = this.tranStateTable.getMapedFiles();8: for (MapedFile mf : mapedFiles) {9: this.addTimerTask(mf);10: }11: }12: 13: /**14: * 每個文件初始化定時任務15: * @param mf 文件16: */17: private void addTimerTask(final MapedFile mf) {18: this.timer.scheduleAtFixedRate(new TimerTask() {19: private final MapedFile mapedFile = mf;20: private final TransactionCheckExecuter transactionCheckExecuter = TransactionStateService.this.defaultMessageStore.getTransactionCheckExecuter();21: private final long checkTransactionMessageAtleastInterval = TransactionStateService.this.defaultMessageStore.getMessageStoreConfig()22: .getCheckTransactionMessageAtleastInterval();23: private final boolean slave = TransactionStateService.this.defaultMessageStore.getMessageStoreConfig().getBrokerRole() == BrokerRole.SLAVE;24: 25: @Override26: public void run() {27: // Slave不需要回查事務狀態28: if (slave) {29: return;30: }31: // Check功能是否開啟32: if (!TransactionStateService.this.defaultMessageStore.getMessageStoreConfig()33: .isCheckTransactionMessageEnable()) {34: return;35: }36: 37: try {38: SelectMapedBufferResult selectMapedBufferResult = mapedFile.selectMapedBuffer(0);39: if (selectMapedBufferResult != null) {40: long preparedMessageCountInThisMapedFile = 0; // 回查的【half消息】數量41: int i = 0;42: try {43: // 循環每條【事務消息】狀態,對【half消息】進行回查44: for (; i < selectMapedBufferResult.getSize(); i += TSStoreUnitSize) {45: selectMapedBufferResult.getByteBuffer().position(i);46: 47: // Commit Log Offset48: long clOffset = selectMapedBufferResult.getByteBuffer().getLong();49: // Message Size50: int msgSize = selectMapedBufferResult.getByteBuffer().getInt();51: // Timestamp52: int timestamp = selectMapedBufferResult.getByteBuffer().getInt();53: // Producer Group Hashcode54: int groupHashCode = selectMapedBufferResult.getByteBuffer().getInt();55: // Transaction State56: int tranType = selectMapedBufferResult.getByteBuffer().getInt();57: 58: // 已經提交或者回滾的消息跳過59: if (tranType != MessageSysFlag.TransactionPreparedType) {60: continue;61: }62: 63: // 遇到時間不符合最小輪詢間隔,終止64: long timestampLong = timestamp * 1000;65: long diff = System.currentTimeMillis() - timestampLong;66: if (diff < checkTransactionMessageAtleastInterval) {67: break;68: }69: 70: preparedMessageCountInThisMapedFile++;71: 72: // 回查Producer73: try {74: this.transactionCheckExecuter.gotoCheck(groupHashCode, getTranStateOffset(i), clOffset, msgSize);75: } catch (Exception e) {76: tranlog.warn("gotoCheck Exception", e);77: }78: }79: 80: // 無回查的【half消息】數量,且遍歷完,則終止定時任務81: if (0 == preparedMessageCountInThisMapedFile //82: && i == mapedFile.getFileSize()) {83: tranlog.info("remove the transaction timer task, because no prepared message in this mapedfile[{}]", mapedFile.getFileName());84: this.cancel();85: }86: } finally {87: selectMapedBufferResult.release();88: }89: 90: tranlog.info("the transaction timer task execute over in this period, {} Prepared Message: {} Check Progress: {}/{}", mapedFile.getFileName(),//91: preparedMessageCountInThisMapedFile, i / TSStoreUnitSize, mapedFile.getFileSize() / TSStoreUnitSize);92: } else if (mapedFile.isFull()) {93: tranlog.info("the mapedfile[{}] maybe deleted, cancel check transaction timer task", mapedFile.getFileName());94: this.cancel();95: return;96: }97: } catch (Exception e) {98: log.error("check transaction timer task Exception", e);99: } 100: } 101: 102: 103: private long getTranStateOffset(final long currentIndex) { 104: long offset = (this.mapedFile.getFileFromOffset() + currentIndex) / TransactionStateService.TSStoreUnitSize; 105: return offset; 106: } 107: }, 1000 * 60, this.defaultMessageStore.getMessageStoreConfig().getCheckTransactionMessageTimerInterval()); 108: } 109: 110: // 【DefaultTransactionCheckExecuter.java】 111: @Override 112: public void gotoCheck(int producerGroupHashCode, long tranStateTableOffset, long commitLogOffset, 113: int msgSize) { 114: // 第一步、查詢Producer 115: final ClientChannelInfo clientChannelInfo = this.brokerController.getProducerManager().pickProducerChannelRandomly(producerGroupHashCode); 116: if (null == clientChannelInfo) { 117: log.warn("check a producer transaction state, but not find any channel of this group[{}]", producerGroupHashCode); 118: return; 119: } 120: 121: // 第二步、查詢消息 122: SelectMapedBufferResult selectMapedBufferResult = this.brokerController.getMessageStore().selectOneMessageByOffset(commitLogOffset, msgSize); 123: if (null == selectMapedBufferResult) { 124: log.warn("check a producer transaction state, but not find message by commitLogOffset: {}, msgSize: ", commitLogOffset, msgSize); 125: return; 126: } 127: 128: // 第三步、向Producer發起請求 129: final CheckTransactionStateRequestHeader requestHeader = new CheckTransactionStateRequestHeader(); 130: requestHeader.setCommitLogOffset(commitLogOffset); 131: requestHeader.setTranStateTableOffset(tranStateTableOffset); 132: this.brokerController.getBroker2Client().checkProducerTransactionState(clientChannelInfo.getChannel(), requestHeader, selectMapedBufferResult); 133: }

3.1.1.4 初始化【事務消息】狀態存儲(TranStateTable)

  • 根據最后 Broker 關閉是否正常,會有不同的初始化方式。

核心代碼如下:

?

1: // 【TransactionStateService.java】2: /**3: * 初始化 TranRedoLog4: * @param lastExitOK 是否正常退出5: */6: public void recoverStateTable(final boolean lastExitOK) {7: if (lastExitOK) {8: this.recoverStateTableNormal();9: } else {10: // 第一步,刪除State Table11: this.tranStateTable.destroy();12: // 第二步,通過RedoLog全量恢復StateTable13: this.recreateStateTable();14: }15: }16: 17: /**18: * 掃描 TranRedoLog 重建 StateTable19: */20: private void recreateStateTable() {21: this.tranStateTable = new MapedFileQueue(StorePathConfigHelper.getTranStateTableStorePath(defaultMessageStore22: .getMessageStoreConfig().getStorePathRootDir()), defaultMessageStore23: .getMessageStoreConfig().getTranStateTableMapedFileSize(), null);24: 25: final TreeSet<Long> preparedItemSet = new TreeSet<Long>();26: 27: // 第一步,從頭掃描RedoLog28: final long minOffset = this.tranRedoLog.getMinOffsetInQuque();29: long processOffset = minOffset;30: while (true) {31: SelectMapedBufferResult bufferConsumeQueue = this.tranRedoLog.getIndexBuffer(processOffset);32: if (bufferConsumeQueue != null) {33: try {34: long i = 0;35: for (; i < bufferConsumeQueue.getSize(); i += ConsumeQueue.CQStoreUnitSize) {36: long offsetMsg = bufferConsumeQueue.getByteBuffer().getLong();37: int sizeMsg = bufferConsumeQueue.getByteBuffer().getInt();38: long tagsCode = bufferConsumeQueue.getByteBuffer().getLong();39: 40: if (TransactionStateService.PreparedMessageTagsCode == tagsCode) { // Prepared41: preparedItemSet.add(offsetMsg);42: } else { // Commit/Rollback43: preparedItemSet.remove(tagsCode);44: }45: }46: 47: processOffset += i;48: } finally { // 必須釋放資源49: bufferConsumeQueue.release();50: }51: } else {52: break;53: }54: }55: log.info("scan transaction redolog over, End offset: {}, Prepared Transaction Count: {}", processOffset, preparedItemSet.size());56: 57: // 第二步,重建StateTable58: Iterator<Long> it = preparedItemSet.iterator();59: while (it.hasNext()) {60: Long offset = it.next();61: MessageExt msgExt = this.defaultMessageStore.lookMessageByOffset(offset);62: if (msgExt != null) {63: this.appendPreparedTransaction(msgExt.getCommitLogOffset(), msgExt.getStoreSize(),64: (int) (msgExt.getStoreTimestamp() / 1000),65: msgExt.getProperty(MessageConst.PROPERTY_PRODUCER_GROUP).hashCode());66: this.tranStateTableOffset.incrementAndGet();67: }68: }69: }70: 71: /**72: * 加載(解析)TranStateTable 的 MappedFile73: * 1. 清理多余 MappedFile,設置最后一個 MappedFile的寫入位置(position74: * 2. 設置 TanStateTable 最大物理位置(可寫入位置)75: */76: private void recoverStateTableNormal() {77: final List<MapedFile> mapedFiles = this.tranStateTable.getMapedFiles();78: if (!mapedFiles.isEmpty()) {79: // 從倒數第三個文件開始恢復80: int index = mapedFiles.size() - 3;81: if (index < 0) {82: index = 0;83: }84: 85: int mapedFileSizeLogics = this.tranStateTable.getMapedFileSize();86: MapedFile mapedFile = mapedFiles.get(index);87: ByteBuffer byteBuffer = mapedFile.sliceByteBuffer();88: long processOffset = mapedFile.getFileFromOffset();89: long mapedFileOffset = 0;90: while (true) {91: for (int i = 0; i < mapedFileSizeLogics; i += TSStoreUnitSize) {92: 93: final long clOffset_read = byteBuffer.getLong();94: final int size_read = byteBuffer.getInt();95: final int timestamp_read = byteBuffer.getInt();96: final int groupHashCode_read = byteBuffer.getInt();97: final int state_read = byteBuffer.getInt();98: 99: boolean stateOK = false; 100: switch (state_read) { 101: case MessageSysFlag.TransactionPreparedType: 102: case MessageSysFlag.TransactionCommitType: 103: case MessageSysFlag.TransactionRollbackType: 104: stateOK = true; 105: break; 106: default: 107: break; 108: } 109: 110: // 說明當前存儲單元有效 111: if (clOffset_read >= 0 && size_read > 0 && stateOK) { 112: mapedFileOffset = i + TSStoreUnitSize; 113: } else { 114: log.info("recover current transaction state table file over, " + mapedFile.getFileName() + " " 115: + clOffset_read + " " + size_read + " " + timestamp_read); 116: break; 117: } 118: } 119: 120: // 走到文件末尾,切換至下一個文件 121: if (mapedFileOffset == mapedFileSizeLogics) { 122: index++; 123: if (index >= mapedFiles.size()) { // 循環while結束 124: log.info("recover last transaction state table file over, last maped file " + mapedFile.getFileName()); 125: break; 126: } else { // 切換下一個文件 127: mapedFile = mapedFiles.get(index); 128: byteBuffer = mapedFile.sliceByteBuffer(); 129: processOffset = mapedFile.getFileFromOffset(); 130: mapedFileOffset = 0; 131: log.info("recover next transaction state table file, " + mapedFile.getFileName()); 132: } 133: } else { 134: log.info("recover current transaction state table queue over " + mapedFile.getFileName() + " " + (processOffset + mapedFileOffset)); 135: break; 136: } 137: } 138: 139: // 清理多余 MappedFile,設置最后一個 MappedFile的寫入位置(position 140: processOffset += mapedFileOffset; 141: this.tranStateTable.truncateDirtyFiles(processOffset); 142: 143: // 設置 TanStateTable 最大物理位置(可寫入位置) 144: this.tranStateTableOffset.set(this.tranStateTable.getMaxOffset() / TSStoreUnitSize); 145: log.info("recover normal over, transaction state table max offset: {}", this.tranStateTableOffset.get()); 146: } 147: }

3.1.1.5 補充

  • 為什么 V3.1.5 開始,使用 數據庫 實現【事務狀態】的存儲?如下是來自官方文檔的說明,可能是一部分原因:

RocketMQ 這種實現事務方式,沒有通過 KV 存儲做,而是通過 Offset 方式,存在一個顯著缺陷,即通過 Offset 更改數據,會令系統的臟頁過多,需要特別關注。

3.1.2 官方V4.0.0:基于數據庫

倉庫地址:https://github.com/apache/incubator-rocketmq

官方V4.0.0 暫時未完全開源【事務消息回查】功能,So 我們需要進行一些猜想,可能不一定正確?

?我們來對比【官方V3.1.4:基于文件】的實現。

  • TransactionRecord :記錄每條【事務消息】。類似?TranStateTable。
TranStateTableTransactionRecord?
offsetoffset?
producerGroupHashproducerGroup?
size非必須字段:【事務消息】回查時,使用 offset 讀取 CommitLog 獲得。
timestamp非必須字段:【事務消息】回查時,使用 offset 讀取 CommitLog 獲得。
state非必須字段: 事務開始,增加記錄;事務結束,刪除記錄。

另外,數據庫本身保證了數據存儲的可靠性,無需?TranRedoLog。

簡單手繪邏輯圖如下?:

3.2 Producer 接收【事務消息回查】

  • 順序圖如下:

  • 核心代碼如下:
1: // 【DefaultMQProducerImpl.java】2: /**3: * 檢查【事務狀態】狀態4: *5: * @param addr broker地址6: * @param msg 消息7: * @param header 請求8: */9: @Override10: public void checkTransactionState(final String addr, final MessageExt msg, final CheckTransactionStateRequestHeader header) {11: Runnable request = new Runnable() {12: private final String brokerAddr = addr;13: private final MessageExt message = msg;14: private final CheckTransactionStateRequestHeader checkRequestHeader = header;15: private final String group = DefaultMQProducerImpl.this.defaultMQProducer.getProducerGroup();16: 17: @Override18: public void run() {19: TransactionCheckListener transactionCheckListener = DefaultMQProducerImpl.this.checkListener();20: if (transactionCheckListener != null) {21: // 獲取事務執行狀態22: LocalTransactionState localTransactionState = LocalTransactionState.UNKNOW;23: Throwable exception = null;24: try {25: localTransactionState = transactionCheckListener.checkLocalTransactionState(message);26: } catch (Throwable e) {27: log.error("Broker call checkTransactionState, but checkLocalTransactionState exception", e);28: exception = e;29: }30: 31: // 處理事務結果,提交消息 COMMIT / ROLLBACK32: this.processTransactionState(//33: localTransactionState, //34: group, //35: exception);36: } else {37: log.warn("checkTransactionState, pick transactionCheckListener by group[{}] failed", group);38: }39: }40: 41: /**42: * 處理事務結果,提交消息 COMMIT / ROLLBACK43: *44: * @param localTransactionState 【本地事務】狀態45: * @param producerGroup producerGroup46: * @param exception 檢查【本地事務】狀態發生的異常47: */48: private void processTransactionState(//49: final LocalTransactionState localTransactionState, //50: final String producerGroup, //51: final Throwable exception) {52: final EndTransactionRequestHeader thisHeader = new EndTransactionRequestHeader();53: thisHeader.setCommitLogOffset(checkRequestHeader.getCommitLogOffset());54: thisHeader.setProducerGroup(producerGroup);55: thisHeader.setTranStateTableOffset(checkRequestHeader.getTranStateTableOffset());56: thisHeader.setFromTransactionCheck(true);57: 58: // 設置消息編號59: String uniqueKey = message.getProperties().get(MessageConst.PROPERTY_UNIQ_CLIENT_MESSAGE_ID_KEYIDX);60: if (uniqueKey == null) {61: uniqueKey = message.getMsgId();62: }63: thisHeader.setMsgId(uniqueKey);64: 65: thisHeader.setTransactionId(checkRequestHeader.getTransactionId());66: switch (localTransactionState) {67: case COMMIT_MESSAGE:68: thisHeader.setCommitOrRollback(MessageSysFlag.TRANSACTION_COMMIT_TYPE);69: break;70: case ROLLBACK_MESSAGE:71: thisHeader.setCommitOrRollback(MessageSysFlag.TRANSACTION_ROLLBACK_TYPE);72: log.warn("when broker check, client rollback this transaction, {}", thisHeader);73: break;74: case UNKNOW:75: thisHeader.setCommitOrRollback(MessageSysFlag.TRANSACTION_NOT_TYPE);76: log.warn("when broker check, client does not know this transaction state, {}", thisHeader);77: break;78: default:79: break;80: }81: 82: String remark = null;83: if (exception != null) {84: remark = "checkLocalTransactionState Exception: " + RemotingHelper.exceptionSimpleDesc(exception);85: }86: 87: try {88: // 提交消息 COMMIT / ROLLBACK89: DefaultMQProducerImpl.this.mQClientFactory.getMQClientAPIImpl().endTransactionOneway(brokerAddr, thisHeader, remark,90: 3000);91: } catch (Exception e) {92: log.error("endTransactionOneway exception", e);93: }94: }95: };96: 97: // 提交執行98: this.checkExecutor.submit(request);99: } 100: 101: // 【DefaultMQProducerImpl.java】 102: /** 103: * 【事務消息回查】檢查監聽器 104: */ 105: public interface TransactionCheckListener { 106: 107: /** 108: * 獲取(檢查)【本地事務】狀態 109: * 110: * @param msg 消息 111: * @return 事務狀態 112: */ 113: LocalTransactionState checkLocalTransactionState(final MessageExt msg); 114: 115: }

?

轉載于:https://my.oschina.net/oosc/blog/1795277

總結

以上是生活随笔為你收集整理的RocketMQ 源码分析 事务消息的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

最新av网址在线 | 亚洲欧美婷婷六月色综合 | 天天在线操 | 亚洲深夜影院 | 热久精品 | 91精选| 99久久久国产精品 | 国产精品久久久久影视 | 亚洲精品久 | 午夜精品一区二区三区在线 | 不卡精品视频 | 久久久久电影 | 综合色中文| av不卡免费看 | 69国产盗摄一区二区三区五区 | 性色在线视频 | 欧美日韩另类在线观看 | 国产精选在线 | 国产91影院 | 亚洲三级在线免费观看 | 99这里只有久久精品视频 | 青青草国产精品视频 | 中文字幕国产视频 | www.av中文字幕.com | 国产精品手机播放 | 国产一区二区三区高清播放 | 婷婷丁香六月 | 人人看人人爱 | 最新三级在线 | 黄色软件视频网站 | 久久久久久久久亚洲精品 | 日韩一级精品 | 国产精品成人一区二区 | 成人在线一区二区三区 | 亚洲综合在线发布 | 亚洲视频一区二区三区在线观看 | 国产精品视频你懂的 | 三级在线视频播放 | 成年人在线 | 色黄www小说 | 99精品免费网 | 国产 欧美 日产久久 | 成年人app网址 | 激情中文在线 | 国产欧美综合视频 | 精品久久久久久久久久久久 | 久久这里有 | 久久久影院官网 | 免费黄av| 国产精品亚洲片夜色在线 | 狠狠操夜夜| 亚洲精品中文在线观看 | 天天人人综合 | av 在线观看 | 国产区网址 | 国产高清一级 | 干干夜夜 | 天天摸夜夜操 | 一区二区三区av在线 | 国产污视频在线观看 | 四虎永久免费在线观看 | 天天玩夜夜操 | 欧美日韩国产综合网 | 毛片无卡免费无播放器 | 在线播放 日韩专区 | 99亚洲天堂| 日韩精品一区二区三区三炮视频 | 日韩av高清在线观看 | 成人一级片在线观看 | 国产日韩视频在线观看 | 国产精品久久久久久爽爽爽 | 在线成人国产 | 天堂va在线高清一区 | 亚洲一区欧美精品 | 久久图 | 免费成人av | 美女一级毛片视频 | 国产系列 在线观看 | av高清一区二区三区 | 超碰97成人 | 久久影视网 | 高清av免费看 | www.xxx.性狂虐 | 69精品人人人人 | 久久激情网站 | 在线播放日韩av | 久久久久久久久久久国产精品 | 国产黑丝一区二区 | 色网址99| 99re8这里有精品热视频免费 | 久久精品一区二 | 中文字幕电影一区 | 三上悠亚一区二区在线观看 | 波多野结衣电影一区二区三区 | 91在线小视频 | 国产日韩在线观看一区 | 精品视频在线免费 | 亚洲综合视频在线观看 | 亚洲九九九在线观看 | 亚洲精品88欧美一区二区 | 射久久久 | 欧美日韩一区久久 | 久久久久久久久久久久国产精品 | 精品一区二区在线免费观看 | 免费国产在线精品 | 四虎影视成人永久免费观看亚洲欧美 | 亚洲国产中文字幕在线观看 | 久久久国产一区二区三区四区小说 | 天天色草| 香蕉网址| 成人久久久久 | 91大神免费在线观看 | 欧美在线视频免费 | 91av国产视频 | 欧美在线一级片 | 免费观看版 | 97人人艹 | 超碰在线官网 | 亚洲成人av片在线观看 | 激情综合网在线观看 | 99精品视频精品精品视频 | 久久久久免费网站 | 狠狠地操 | 国产免费不卡 | 国产精品久久久久久久99 | 久久精品电影院 | 九九热.com| 偷拍区另类综合在线 | 亚洲免费公开视频 | 欧美日韩在线观看一区 | 日本公妇色中文字幕 | 久久亚洲热 | 久久99免费视频 | 天天射天天 | 中文字幕免费在线 | 天天射天天色天天干 | 亚洲三级黄 | 欧美精品在线免费 | 97av超碰| 成人欧美一区二区三区黑人麻豆 | 一级久久精品 | 久久优 | 亚洲国产合集 | 国产一区二区三区高清播放 | 在线黄色av| 欧美激情第28页 | 色国产在线 | 亚在线播放中文视频 | 日韩一区二区三 | 美女久久久久久久久久久 | 日韩欧美精品一区二区三区经典 | 亚洲午夜精品在线观看 | 久久精品国产成人精品 | 国产99久久久久久免费看 | 激情久久一区二区三区 | 亚洲欧美在线综合 | 天天天天色射综合 | 免费观看国产精品视频 | 日韩激情视频在线观看 | 91成人在线视频 | 玖玖精品在线 | 中文在线免费观看 | 日韩日韩日韩日韩 | 91热精品| 五月婷婷av在线 | 日操操| 99热在线精品观看 | 综合伊人av | a黄色片在线观看 | 成人宗合网 | 国产精品成久久久久 | 精品字幕在线 | 一本到在线 | 91精品网站在线观看 | 日日插日日干 | 欧美日韩不卡一区 | 欧美日韩国产二区 | 久久精品官网 | 国产在线免费av | 色综合久久精品 | 久久爱综合 | www.夜夜操 | 日韩欧美一区二区三区在线 | 国产粉嫩在线观看 | 国产最新福利 | 国产中文字幕视频在线 | 国产麻豆精品在线观看 | 亚洲毛片一区二区三区 | www91在线观看| 国产一级在线视频 | 麻豆视频免费在线播放 | 欧美一级片免费观看 | 高清精品久久 | 六月婷色| 国产一区高清在线观看 | 人人干人人搞 | 久久精品精品 | 日韩精品一区二区三区外面 | 成人黄色国产 | 六月色丁香 | 激情五月伊人 | 99久久精品久久亚洲精品 | 成人在线播放av | 天天操操操操操 | 日本xxxx裸体xxxx17 | 黄网站免费久久 | 99精品区 | 最近中文字幕完整高清 | 99精品免费久久久久久日本 | 国内精品久久久久久中文字幕 | 少妇bbbb| 国产理伦在线 | 一区二区不卡在线观看 | 波多野结衣电影一区 | 国产黄色免费看 | 久久手机免费视频 | 日韩高清在线不卡 | 爱色婷婷| 成人毛片在线观看视频 | 97视频亚洲| 亚洲麻豆精品 | 久艹视频免费观看 | 91成人短视频在线观看 | 黄色精品久久 | 超碰精品在线 | 亚洲人成在线观看 | www.天天干.com| 亚洲国产影院av久久久久 | 久草在线视频资源 | 91亚洲永久精品 | 日韩高清国产精品 | 黄色毛片视频免费 | 久久久久 免费视频 | 亚洲成人精品国产 | 精品91视频 | 国产麻豆剧传媒免费观看 | 成人久久久久久久久久 | 国产精品毛片久久久 | 欧美先锋影音 | www.天天射.com | 最近中文字幕在线播放 | www狠狠| 日韩欧美在线一区二区 | 久久精品久久国产 | 中文一区在线 | 九色视频网址 | 黄av在线 | 97精品伊人 | 国产精品婷婷午夜在线观看 | 成人久久久久 | 97超视频在线观看 | 最新精品国产 | 久久久精品国产免费观看一区二区 | 国产精品视频资源 | 欧美日韩国产综合一区二区 | 色在线国产 | 亚洲 欧美 综合 在线 精品 | 日本婷婷色 | 国产视频在线看 | 精品久久久999 | 又污又黄网站 | 亚洲三级黄 | 黄色成人影视 | 国产成人一区二区三区在线观看 | 色婷婷天天干 | 成人理论电影 | 麻豆91精品视频 | 国产伦精品一区二区三区… | 久久国内免费视频 | 五月婷婷综合色拍 | 黄毛片在线观看 | 日韩av电影中文字幕在线观看 | 丁香婷婷深情五月亚洲 | 成人在线视频免费 | 亚洲国产精品99久久久久久久久 | 一区二区三区四区精品 | 亚洲欧美乱综合图片区小说区 | 狠狠狠狠干 | 欧美analxxxx| av中文字幕av | 夜夜狠狠 | 久久www免费人成看片高清 | 亚洲精品视频在线播放 | 国产精品免费在线 | 久久看片网站 | 91视频在线国产 | 天天干人人 | 五月天激情婷婷 | 久久久在线免费观看 | 91精品一区二区三区久久久久久 | 日韩综合色 | 国产视频2区 | 久久久久一区二区三区四区 | 久草新在线 | 午夜国产一区二区 | 亚洲欧洲久久久 | 亚洲综合爱 | 久久精品日韩 | 96亚洲精品久久久蜜桃 | 欧美日韩免费在线观看视频 | 97在线观看视频国产 | 在线视频一区观看 | 久久人人精品 | 999精品| 欧美福利久久 | 黄色福利视频网站 | 天天色 天天 | 高清不卡一区二区三区 | www色 | 波多野结衣精品 | 97精品国产91久久久久久久 | 狠狠干夜夜操天天爽 | av资源网在线播放 | 亚洲成人家庭影院 | 最新免费av在线 | 日韩精品视频在线观看网址 | 97超碰人人干 | www.69xx| 久久久资源网 | 中文字幕一区二区在线观看 | 久色网 | 色婷婷视频 | 中文字幕av最新 | 99在线免费视频观看 | 久久99电影 | 碰天天操天天 | 蜜臀av性久久久久蜜臀aⅴ流畅 | 日韩在线免费播放 | 波多野结衣视频一区 | 超碰免费观看 | 99久久er热在这里只有精品66 | 综合在线亚洲 | 色先锋资源网 | 日韩电影一区二区三区在线观看 | 国产精品毛片完整版 | 久久久久国产精品视频 | 国产91精品欧美 | 日韩偷拍精品 | 亚洲黄色网络 | 黄色中文字幕在线 | 日韩午夜小视频 | 蜜臀久久99精品久久久无需会员 | 国产一级免费观看视频 | 成人在线你懂得 | 天天性天天草 | 国产日本三级 | 久久视屏网 | 中文字幕在线观看视频一区二区三区 | 丁香婷婷网 | 国产99久久精品一区二区永久免费 | 日本精品一二区 | 一区二区三区免费在线 | 91精品国产91久久久久久三级 | 婷婷六月网| 99色99| 又大又硬又黄又爽视频在线观看 | 在线观看视频你懂 | 九九三级毛片 | 美女精品久久久 | 在线免费国产视频 | 91精品国产乱码 | 美女免费视频网站 | 狠狠搞,com| 国模一二三区 | 国产精品美女久久久久久网站 | 免费观看丰满少妇做爰 | 国产一区精品在线 | 免费在线看v| 色com网| 欧美激情视频一二三区 | 国产亚洲精品久久久久久无几年桃 | 欧美影片 | 日韩精品一区二区三区高清免费 | 这里只有精品视频在线观看 | 天堂av一区二区 | 97人人模人人爽人人喊中文字 | 免费观看一级 | 国产精品视频内 | 日韩av影视| 国产精品久久久久久久久久久久冷 | 久久婷婷一区 | 国产精品久久一区二区三区不卡 | 久久国产精品99久久久久久老狼 | 中文字幕av最新 | 狠狠操狠狠操 | 欧美特一级片 | 女人18精品一区二区三区 | 国产1级毛片 | 色婷婷狠狠五月综合天色拍 | 亚洲精品久久久蜜桃 | 在线观看视频福利 | 国产91欧美 | 在线免费观看欧美日韩 | 成人天堂网| 91av播放 | 国产资源精品 | 久久久91精品国产 | 91网页版在线观看 | 精品国产aⅴ一区二区三区 在线直播av | 婷婷丁香视频 | 国产日韩欧美在线 | 天堂久久电影网 | 91亚洲精品国偷拍 | 亚洲精品美女视频 | 成 人 黄 色 视频 免费观看 | 天天色天天综合网 | 在线视频 你懂得 | 精品在线视频观看 | 天天色视频 | 成人av在线直播 | 超碰在线人人爱 | 国产精品一区二区久久 | 在线视频 你懂得 | 夜夜狠狠| 香蕉视频18 | 国模一二三区 | 中文字幕视频在线播放 | 久久久久免费网 | www.99在线观看 | 日本一区二区免费在线观看 | 在线观看免费高清视频大全追剧 | 一区二区激情视频 | 成年人视频免费在线播放 | 国产人成看黄久久久久久久久 | 丁香婷婷久久久综合精品国产 | 欧美一级片| 国内精品美女在线观看 | 亚洲狠狠操 | 337p日本欧洲亚洲大胆裸体艺术 | 免费在线国产精品 | 国产中文字幕在线视频 | 色偷偷888欧美精品久久久 | 久久久久国产精品厨房 | 一级黄色片毛片 | 国产又粗又长又硬免费视频 | 日日干天天爽 | 99视频在线 | 国产精品久久久久久久久久免费看 | 久久精品视频在线免费观看 | 日黄网站 | 欧美日韩久久不卡 | 在线观看精品黄av片免费 | 在线涩涩| 久久网站最新地址 | 亚洲片在线观看 | 天天拍天天色 | 日韩久久精品一区二区三区下载 | 福利视频 | av福利资源 | 成 人 a v天堂 | 久久亚洲精品国产亚洲老地址 | 综合色中文 | 一区中文字幕 | 麻豆播放 | 夜夜操天天摸 | 91精品国产99久久久久 | 色香蕉视频 | 黄色www免费 | 久久国产精品色婷婷 | 99在线观看 | 亚在线播放中文视频 | 久久精品视频国产 | 在线成人看片 | 99r国产精品 | 香蕉影院在线播放 | 69国产精品视频 | 亚洲在线黄色 | 久草久草视频 | 天天曰天天干 | 色偷偷97| 亚洲精品国偷自产在线99热 | 久草在线观看 | 久久亚洲欧美 | 国产精品毛片一区二区在线 | 黄网站色成年免费观看 | 精品产品国产在线不卡 | 久久免费视频在线观看30 | 超碰人人干人人 | 色婷五月 | 色婷五月天 | 激情影音先锋 | 久久国产欧美日韩精品 | 欧美色图30p | 开心丁香婷婷深爱五月 | 人人爽人人做 | 精品久久久久久久久久久久久久久久 | 激情av在线播放 | 成年人免费看av | 99精品国产一区二区三区麻豆 | 激情在线网址 | 91视频免费看片 | 极品嫩模被强到高潮呻吟91 | a在线视频v视频 | 麻豆精品视频在线观看免费 | 欧美天天综合 | 在线看国产日韩 | 少妇bbw撒尿 | 超碰资源在线 | 一区二区三区免费在线 | 国产成人在线网站 | 欧美日韩高清在线观看 | 日一日干一干 | 国产亚洲成av人片在线观看桃 | av久久久久久 | 亚洲aⅴ在线 | 国产麻豆视频 | 久久免费福利视频 | 欧美在线视频a | 亚洲精品白浆高清久久久久久 | 婷婷色狠狠 | 久久99久久99精品 | 日韩欧美在线第一页 | 久久精品牌麻豆国产大山 | 免费在线激情电影 | 国产一级免费在线观看 | 麻豆观看| 91成人在线视频观看 | 91精品影视| 波多野结衣电影一区二区 | 精品视频专区 | 国产日韩中文字幕 | 欧美日韩aa | 三级黄色a | 中文字幕免费观看全部电影 | 国产成人三级在线播放 | 国产 在线 高清 精品 | 一区中文字幕电影 | 五月天婷婷狠狠 | 亚洲v欧美v国产v在线观看 | 麻豆视频在线看 | 亚洲情感电影大片 | 国产三级av在线 | 欧美午夜一区二区福利视频 | 久久久久久久久久久免费视频 | 人人干在线观看 | 国产最顶级的黄色片在线免费观看 | 亚洲毛片一区二区三区 | 欧美性超爽 | 精品视频www | 免费看片网址 | 美女网站在线免费观看 | 久久精品99久久久久久 | 精品av网站 | 婷婷视频 | 91精品视频免费观看 | 亚洲精品福利在线 | 免费黄色a网站 | 国产视频在线观看一区 | 成年人视频在线观看免费 | 国产视频日韩 | 99久久精品免费看国产一区二区三区 | 精品久久福利 | 天天射天天干天天爽 | 人人插人人爱 | 97超碰人人爱 | 成人av电影在线播放 | 成人免费观看av | 亚洲视频高清 | 中文字幕在线观看网址 | 亚洲精品一区二区18漫画 | 国产乱对白刺激视频在线观看女王 | 国产精品igao视频网入口 | 狠狠躁天天躁 | 日一日干一干 | 亚洲精品国产精品国自产 | 99精品在线视频观看 | 久久精品官网 | 亚洲成人网在线 | 天天色天天射天天综合网 | 久草观看视频 | 亚洲天堂网在线观看视频 | 亚洲高清91| 狠狠网站 | www操操 | 91亚洲在线观看 | 日韩精品久久中文字幕 | 国产精品涩涩屋www在线观看 | 香蕉精品视频在线观看 | 麻豆一精品传二传媒短视频 | 在线一二区 | 国产精品久久久久久久久久久久 | 国产精品6 | 久精品一区 | 日韩亚洲在线观看 | 亚洲精品动漫成人3d无尽在线 | 久久精品最新 | 欧美 亚洲 另类 激情 另类 | 亚洲综合狠狠干 | 国产精品6| 五月婷网站 | 久草精品电影 | 国产在线超碰 | 中文字幕一区二区三区四区 | 中文字幕高清有码 | www.eeuss影院av撸 | 天天躁日日躁狠狠躁av中文 | 精品一区二区三区香蕉蜜桃 | 久久免费视频在线观看 | 色偷偷男人的天堂av | 国产黄免费在线观看 | 亚洲精品午夜一区人人爽 | 色视频在线 | 国产成人精品久久亚洲高清不卡 | 久久久综合香蕉尹人综合网 | 中文字幕在线观看av | 97在线成人 | 日韩中文字幕视频在线 | 欧美一区三区四区 | 五月婷婷av在线 | 日韩av一区二区在线播放 | 成人免费在线看片 | 久久久免费观看视频 | 激情综合五月天 | 色综合天天色综合 | 成人一级片在线观看 | 国产黄色电影 | 久久久久亚洲最大xxxx | 99视频精品 | 99精品在线视频观看 | 亚洲国产精品一区二区久久hs | 97精产国品一二三产区在线 | 黄色在线观看免费网站 | 欧美极品xxx | 久久久精品网站 | 日韩欧美视频免费在线观看 | 99精品欧美一区二区蜜桃免费 | 黄色不卡av | 国产精品久久久久久久久久白浆 | 国产精品美女久久久久久久久 | 国产一级性生活视频 | 日韩专区视频 | 国产一线二线三线在线观看 | 伊人狠狠色 | 久色婷婷 | 激情网五月天 | 国产精品一区二区三区久久 | 手机版av在线 | 在线播放视频一区 | 久久99影院 | 中文字幕亚洲综合久久五月天色无吗'' | 国产精品99久久久久久久久 | 涩涩成人在线 | 国产精品视频内 | 亚色视频在线观看 | 色婷婷久久久综合中文字幕 | 国产精品涩涩屋www在线观看 | 亚洲精品人人 | 麻豆视频国产 | 色噜噜狠狠狠狠色综合久不 | 天堂资源在线观看视频 | 国产丝袜高跟 | 黄免费网站| 欧美激情另类 | 亚洲乱亚洲乱亚洲 | 久久精品国产第一区二区三区 | 午夜精品一区二区三区在线 | 国产精品毛片久久久 | 免费成人在线视频网站 | 国产视频色| 国产精品成人久久久久久久 | 成人av电影网址 | 国产精品永久久久久久久久久 | av在线之家电影网站 | 一本一道久久a久久综合蜜桃 | 成人高清av在线 | 国产手机av在线 | 韩国av免费在线观看 | 国产精品亚洲精品 | 伊人久久影视 | 国产午夜三级一区二区三 | 青青河边草手机免费 | 精品久久久久久国产 | 久草免费色站 | av福利第一导航 | 最近字幕在线观看第一季 | 在线亚洲成人 | 久久久综合九色合综国产精品 | 狠狠干狠狠色 | 丁香六月婷婷开心 | 中文字幕观看av | 日日摸日日碰 | 婷婷在线视频观看 | 麻豆成人网 | 国产精品丝袜在线 | 天天色天天草天天射 | 国产成人精品av在线观 | 国产精品永久免费观看 | 中文字幕刺激在线 | 天天天天色射综合 | 午夜av在线免费 | 久久兔费看a级 | 伊人网站| 婷婷丁香激情五月 | 国产精品你懂的在线观看 | 99国产精品一区二区 | 91在线一区二区 | 日韩精品免费在线播放 | 顶级bbw搡bbbb搡bbbb | 国产精品mv在线观看 | 免费三级影片 | 色综合久久网 | 99免费在线观看 | 久草精品在线观看 | 亚洲精品97 | 日韩美女黄色片 | 亚洲日韩中文字幕 | 亚洲涩涩一区 | www.伊人网| av在线播放快速免费阴 | 91视频在线免费观看 | 午夜影院在线观看18 | 久久精品一区二 | 久久精品一区 | 成人黄色在线观看视频 | 99久久久国产精品免费99 | 制服丝袜亚洲 | 久久综合九色99 | 91视频免费视频 | 久久这里只精品 | 久久理伦片| 国产97视频在线 | 国外调教视频网站 | 亚洲三区在线 | 国产18精品乱码免费看 | 国产一线在线 | 久久久久久久影视 | 日韩二级毛片 | 婷婷5月激情5月 | 国产精品大尺度 | 日韩高清在线一区 | 91麻豆精品国产91久久久无限制版 | 99精品欧美一区二区三区 | 午夜在线观看 | 国产亚洲午夜高清国产拍精品 | 日韩免费在线观看视频 | 三上悠亚一区二区在线观看 | 最近中文字幕完整视频高清1 | 亚洲五月六月 | 免费中文字幕视频 | 激情欧美一区二区三区免费看 | 麻豆精品传媒视频 | 国内精品免费久久影院 | 激情综合五月婷婷 | 综合五月婷婷 | 免费看成人 | 国产高清久久久久 | 国产小视频91 | 久草在线免费在线观看 | 中文字幕色在线 | 99视频国产精品免费观看 | 探花系列在线 | 日韩av不卡在线播放 | 国产视频欧美视频 | 亚洲国产日韩在线 | 九九在线视频 | 最近免费观看的电影完整版 | 天天久久夜夜 | 91丨九色丨首页 | 综合网伊人 | 婷婷中文字幕在线观看 | 免费看一及片 | 午夜一级免费电影 | 激情视频一区二区 | 久久你懂的 | 天天色天天操天天爽 | 国产在线 一区二区三区 | 日韩精品视频免费 | 99久热在线精品视频观看 | 久久久久久综合 | 国产精品白浆视频 | 亚洲激情p | 91视频专区 | 久久视频一区 | 国产精品免费在线 | 中文字幕在线观看第三页 | 欧美日韩国产精品一区二区三区 | 天天做天天看 | 亚洲男人天堂2018 | 97福利在线观看 | 在线黄色免费av | 在线免费观看视频 | 搡bbbb搡bbb视频 | 日韩精品高清视频 | 亚洲理论影院 | 亚洲精品影视在线观看 | 中文字幕乱码日本亚洲一区二区 | 欧美成人在线网站 | www日韩视频 | 亚洲视频在线免费观看 | 韩国av不卡 | 狠狠狠狠狠狠狠狠干 | 国产精品一区二区三区四区在线观看 | 99亚洲视频| 中文 一区二区 | 中文字幕网站视频在线 | 色婷婷电影网 | 97国产大学生情侣白嫩酒店 | 美女免费视频黄 | 久草在线一免费新视频 | 91精品啪在线观看国产 | 久久刺激视频 | 日韩一区二区三区高清在线观看 | 有没有在线观看av | 五月天视频网 | 日韩免费高清在线 | av免费看av | 狠狠色丁香 | 97香蕉久久国产在线观看 | 97精品国产97久久久久久免费 | 美女在线免费观看视频 | 在线亚洲人成电影网站色www | 亚洲精品视| 久久99精品波多结衣一区 | 久久免费视频3 | 国产女教师精品久久av | 国产在线精品一区二区不卡了 | 中文字幕在线观看免费 | 亚洲三级黄色 | 国产精品aⅴ | 欧美激情视频一区二区三区免费 | 免费视频久久久久久久 | 国产免费片 | 国产99在线免费 | 久久黄色a级片 | 96在线 | 激情动态 | 天天干天天弄 | 91日本在线播放 | 亚洲综合黄色 | 久久久久麻豆v国产 | 99精品国产成人一区二区 | 日本精品视频一区 | 97网站| 精品久久久久久久久久久久 | 手机色在线 | 国产精品爽爽爽 | 一区二区 精品 | 婷婷丁香花 | 亚洲午夜激情网 | 狠狠做深爱婷婷综合一区 | 中文字幕国内精品 | 国产最新视频在线观看 | 91色影院 | 在线高清av | 国产精品区一区 | 夜夜夜夜猛噜噜噜噜噜初音未来 | 最近最新最好看中文视频 | 免费看污黄网站 | 在线观看免费黄视频 | 日韩高清精品免费观看 | 国产精品国产自产拍高清av | 久久人人爽爽人人爽人人片av | av先锋影音少妇 | 日b视频在线观看网址 | 欧美一区免费观看 | 探花视频免费在线观看 | 国产剧情久久 | a视频免费看 | 久久草在线精品 | 免费麻豆 | 国产精品久久电影观看 | 超碰在线9| 欧美成人xxxx | 天天曰天天干 | 在线播放你懂 | 免费观看www7722午夜电影 | 久久久精品二区 | 日韩av影片在线观看 | 在线视频福利 | 在线观看免费黄视频 | 91人人爱 | 成人黄色一级视频 | 亚洲精品中文在线资源 | 欧美日韩一区二区三区在线观看视频 | 欧美精品二 | 色综合人人 | 国产伦精品一区二区三区无广告 | 99国产视频 | 免费观看的黄色片 | av在线播放中文字幕 | 91精品福利在线 | 欧美日韩裸体免费视频 | 97超碰在线久草超碰在线观看 | 91大神在线观看视频 | 国产一区二区三区久久久 | 精品女同一区二区三区在线观看 | 日韩国产高清在线 | 国产成人精品一区二区三区免费 | 中文字幕一区二区三区乱码不卡 | 天天操狠狠干 | 婷婷五月在线视频 | 国产系列精品av | 国产一区二区三区在线 | 激情av在线资源 | 久久久综合九色合综国产精品 | 亚洲 欧美 综合 在线 精品 | 天天人人 | 亚洲午夜av久久乱码 | 天天射天天搞 | 国产成人av电影在线观看 | 欧美aa级| 狠狠操影视 | 亚洲欧美国产视频 | 免费亚洲精品视频 | 99热最新网址| 在线观看视频在线观看 | 中文字幕有码在线播放 | 久久久久激情 | av三级av| 久久精品网站免费观看 | 欧美性成人 | 国产一区 在线播放 | 免费高清在线观看成人 | 欧美色图30p | 蜜臀av网址| 在线观av| 中文字幕国产一区 | 欧美日一级片 | 91爱看片| 国产精品久久在线观看 | 成人全视频免费观看在线看 | 精品久久久久亚洲 | 国产韩国日本高清视频 | 韩国精品福利一区二区三区 | 中文字幕国内精品 | 亚洲成人av电影在线 | 亚洲精品欧美视频 | 伊人影院得得 | 国产理论片在线观看 | 免费久久久 | 最新极品jizzhd欧美 | 99久热在线精品视频成人一区 | 午夜精品一二区 | 久久久久久国产一区二区三区 | 国产黄色av网站 | 亚洲黄色av | 日韩影视大全 | 色香com. | 成人av地址| 在线成人小视频 | 久久国产一区二区三区 | 国产精品不卡一区 | 极品美女被弄高潮视频网站 | 成人av资源网站 | 美女黄色网在线播放 | 黄色福利网站 | 97精品一区 | 超碰在线公开 | 黄色电影在线免费观看 | 精品一二三区视频 | 精品在线观看视频 | 狠狠操欧美 | 久久久精品二区 | 日本久久久亚洲精品 | 天天色天天射天天操 | 国产成人综合在线观看 | 欧美性色综合网站 | www.夜色321.com| 国产一级在线观看视频 | 欧美综合色 | 奇米影视777影音先锋 | 久久草网 | 日本中文字幕在线电影 | 免费av在线播放 | 国产伦精品一区二区三区四区视频 | 黄色片网站av | 国产91九色蝌蚪 | 夜夜澡人模人人添人人看 | 日韩欧美一区二区在线播放 | 欧美精品一区二区在线播放 | 狠狠狠色丁香综合久久天下网 | 亚洲精品国产区 | 激情五月五月婷婷 | 在线精品视频在线观看高清 | 成人黄色大片在线观看 | 97色综合 | 超碰在线日韩 | 亚洲最新视频在线播放 | 国产精品国产精品 | 五月婷婷综合久久 | 免费a视频在线观看 | 国产精品久久久久婷婷二区次 | 国产黄免费看 | 在线精品视频在线观看高清 | 久久国产一区 | 中文字幕视频观看 | 婷婷伊人五月天 | 毛片随便看| 欧美少妇xx | 欧美精品久久久久性色 | 一级免费黄视频 | 成人国产精品电影 | 国产一二三四在线观看视频 | 夜夜躁日日躁狠狠久久88av | 国产日产精品久久久久快鸭 | 99久久日韩精品免费热麻豆美女 | 2019中文字幕网站 | 亚洲国产成人高清精品 |