Docker實(shí)現(xiàn)Canal MySQL增量日志訂閱&消費(fèi)環(huán)境搭建

https://github.com/alibaba/canal

Canal:阿里巴巴mysql數(shù)據(jù)庫binlog的增量訂閱&消費(fèi)組件 。阿里云DRDS( https://www.aliyun.com/product/drds )胸蛛、阿里巴巴TDDL 二級(jí)索引委可、小表復(fù)制powerd by canal. Aliyun Data Lake Analytics https://www.aliyun.com/product/datalakeanalytics

目錄

開啟Canal之旅

Docker快速開始

MySQL要求

運(yùn)行Canal容器

錯(cuò)誤運(yùn)行方式

正確運(yùn)行方式一

正確運(yùn)行方式二

開啟服務(wù)器端口訪問

Java測(cè)試客戶端

錯(cuò)誤運(yùn)行容器測(cè)試結(jié)果

正常運(yùn)行容器測(cè)試結(jié)果

數(shù)據(jù)庫異常問題


開啟Canal之旅

Docker快速開始

https://github.com/alibaba/canal/wiki/Docker-QuickStart

MySQL要求

https://github.com/alibaba/canal/wiki/AdminGuide

a. 當(dāng)前的canal開源版本支持5.7及以下的版本(阿里內(nèi)部mysql 5.7.13, 5.6.10, mysql 5.5.18和5.1.40/48),ps. mysql4.x版本沒有經(jīng)過嚴(yán)格測(cè)試笼吟,理論上是可以兼容

b. canal的原理是基于mysql binlog技術(shù),所以這里一定需要開啟mysql的binlog寫入功能,并且配置binlog模式為row.

[mysqld] log-bin=mysql-bin #添加這一行就ok binlog-format=ROW #選擇row模式 server_id=1 #配置mysql replaction需要定義乏梁,不能和canal的slaveId重復(fù) 
數(shù)據(jù)庫重啟后, 簡(jiǎn)單測(cè)試 `my.cnf` 配置是否生效:
mysql> show variables like 'binlog_format';+---------------+-------+| Variable_name | Value |+---------------+-------+| binlog_format | ROW   |+---------------+-------+
mysql> show variables like 'log_bin';+---------------+-------+| Variable_name | Value |+---------------+-------+| log_bin       | ON    |+---------------+-------+
image

如果 my.cnf 設(shè)置不起作用,請(qǐng)參考:
https://stackoverflow.com/questions/38288646/changes-to-my-cnf-dont-take-effect-ubuntu-16-04-mysql-5-6
https://stackoverflow.com/questions/52736162/set-binlog-for-mysql-5-6-ubuntu16-4

c. canal的原理是模擬自己為mysql slave,所以這里一定需要做為mysql slave的相關(guān)權(quán)限

CREATE USER canal IDENTIFIED BY 'canal';    GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'canal'@'%';  -- GRANT ALL PRIVILEGES ON *.* TO 'canal'@'%' ;  FLUSH PRIVILEGES; 
 針對(duì)已有的賬戶可通過grants查詢權(quán)限:
show grants for 'canal' 

運(yùn)行Canal容器

注意:需要明確端口號(hào)和配置文件路徑关贵。

錯(cuò)誤運(yùn)行方式

錯(cuò)誤運(yùn)行是什么意思遇骑?即缺少一些基本的配置參數(shù),雖然有修改跟我們理解上還是有一定區(qū)別

#運(yùn)行canal容器 docker run -p 11111:11111 --name canal -d canal/canal-server #帶配置映射docker run -p 11111:11111 --name canal -v /usr/local/canal/canal.properties:/home/admin/canal-server/conf/canal.properties -d canal/canal-server

canal.properties配置:需要注意id和instance配置(真實(shí)情況Docker支持單個(gè)instance不需要修改canal.properties)

##########################################################      common argument     ############# ##################################################canal.manager.jdbc.url=jdbc:mysql://127.0.0.1:3306/canal_manager?useUnicode=true&characterEncoding=UTF-8#canal.manager.jdbc.username=root#canal.manager.jdbc.password=121212#id不能重復(fù)(默認(rèn)id=1)canal.id = 10002canal.ip =canal.port = 11111canal.metrics.pull.port = 11112canal.zkServers =# flush data to zkcanal.zookeeper.flush.period = 1000canal.withoutNetty = false# tcp, kafka, RocketMQcanal.serverMode = tcp# flush meta cursor/parse position to filecanal.file.data.dir = ${canal.conf.dir}canal.file.flush.period = 1000## memory store RingBuffer size, should be Math.pow(2,n)canal.instance.memory.buffer.size = 16384## memory store RingBuffer used memory unit size , default 1kbcanal.instance.memory.buffer.memunit = 1024 ## meory store gets mode used MEMSIZE or ITEMSIZEcanal.instance.memory.batch.mode = MEMSIZEcanal.instance.memory.rawEntry = true ## detecing configcanal.instance.detecting.enable = false#canal.instance.detecting.sql = insert into retl.xdual values(1,now()) on duplicate key update x=now()canal.instance.detecting.sql = select 1canal.instance.detecting.interval.time = 3canal.instance.detecting.retry.threshold = 3canal.instance.detecting.heartbeatHaEnable = false # support maximum transaction size, more than the size of the transaction will be cut into multiple transactions deliverycanal.instance.transaction.size =  1024# mysql fallback connected to new master should fallback timescanal.instance.fallbackIntervalInSeconds = 60 # network configcanal.instance.network.receiveBufferSize = 16384canal.instance.network.sendBufferSize = 16384canal.instance.network.soTimeout = 30 # binlog filter configcanal.instance.filter.druid.ddl = truecanal.instance.filter.query.dcl = falsecanal.instance.filter.query.dml = falsecanal.instance.filter.query.ddl = falsecanal.instance.filter.table.error = falsecanal.instance.filter.rows = falsecanal.instance.filter.transaction.entry = false # binlog format/image checkcanal.instance.binlog.format = ROW,STATEMENT,MIXED canal.instance.binlog.image = FULL,MINIMAL,NOBLOB # binlog ddl isolationcanal.instance.get.ddl.isolation = false # parallel parser configcanal.instance.parser.parallel = true## concurrent thread number, default 60% available processors, suggest not to exceed Runtime.getRuntime().availableProcessors()#canal.instance.parser.parallelThreadSize = 16## disruptor ringbuffer size, must be power of 2canal.instance.parser.parallelBufferSize = 256 # table meta tsdb infocanal.instance.tsdb.enable = truecanal.instance.tsdb.dir = ${canal.file.data.dir:../conf}/${canal.instance.destination:}canal.instance.tsdb.url = jdbc:h2:${canal.instance.tsdb.dir}/h2;CACHE_SIZE=1000;MODE=MYSQL;canal.instance.tsdb.dbUsername = canalcanal.instance.tsdb.dbPassword = canal# dump snapshot interval, default 24 hourcanal.instance.tsdb.snapshot.interval = 24# purge snapshot expire , default 360 hour(15 days)canal.instance.tsdb.snapshot.expire = 360 # aliyun ak/sk , support rds/mqcanal.aliyun.accessKey =canal.aliyun.secretKey = ##########################################################      destinations        ############# #################################################canal.destinations = example# conf root dircanal.conf.dir = ../conf# auto scan instance dir add/remove and start/stop instancecanal.auto.scan = truecanal.auto.scan.interval = 5 canal.instance.tsdb.spring.xml = classpath:spring/tsdb/h2-tsdb.xml#canal.instance.tsdb.spring.xml = classpath:spring/tsdb/mysql-tsdb.xml canal.instance.global.mode = springcanal.instance.global.lazy = false#canal.instance.global.manager.address = 127.0.0.1:1099#canal.instance.global.spring.xml = classpath:spring/memory-instance.xmlcanal.instance.global.spring.xml = classpath:spring/file-instance.xml#canal.instance.global.spring.xml = classpath:spring/default-instance.xml ###########################################################              MQ              ###############################################################canal.mq.servers = 127.0.0.1:6667canal.mq.retries = 0canal.mq.batchSize = 16384canal.mq.maxRequestSize = 1048576canal.mq.lingerMs = 100canal.mq.bufferMemory = 33554432canal.mq.canalBatchSize = 50canal.mq.canalGetTimeout = 100canal.mq.flatMessage = truecanal.mq.compressionType = nonecanal.mq.acks = all# use transaction for kafka flatMessage batch producecanal.mq.transaction = false#canal.mq.properties. =

正確運(yùn)行方式一

#帶配置映射docker run -p 11111:11111 --name canal -v  /usr/local/canal/example/instance.properties:/home/admin/canal-server/conf/example/instance.properties  -d canal/canal-server

instance.properties配置揖曾,只需要設(shè)置MySQL容器實(shí)例的地址: canal.instance.master.address=172.17.0.4:3306

################################################### mysql serverId , v1.0.26+ will autoGen# canal.instance.mysql.slaveId=0 # enable gtid use true/falsecanal.instance.gtidon=false # position infocanal.instance.master.address=172.17.0.4:3306canal.instance.master.journal.name=canal.instance.master.position=canal.instance.master.timestamp=canal.instance.master.gtid= # rds oss binlogcanal.instance.rds.accesskey=canal.instance.rds.secretkey=canal.instance.rds.instanceId= # table meta tsdb infocanal.instance.tsdb.enable=true#canal.instance.tsdb.url=jdbc:mysql://127.0.0.1:3306/canal_tsdb#canal.instance.tsdb.dbUsername=canal#canal.instance.tsdb.dbPassword=canal #canal.instance.standby.address =#canal.instance.standby.journal.name =#canal.instance.standby.position =#canal.instance.standby.timestamp =#canal.instance.standby.gtid= # username/passwordcanal.instance.dbUsername=canalcanal.instance.dbPassword=canalcanal.instance.connectionCharset = UTF-8# enable druid Decrypt database passwordcanal.instance.enableDruid=false#canal.instance.pwdPublicKey=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALK4BUxdDltRRE5/zXpVEVPUgunvscYFtEip3pmLlhrWpacX7y7GCMo2/JM6LeHmiiNdH1FWgGCpUfircSwlWKUCAwEAAQ== # table regexcanal.instance.filter.regex=.*\\..*# table black regexcanal.instance.filter.black.regex= # mq configcanal.mq.topic=example# dynamic topic route by schema or table regex#canal.mq.dynamicTopic=mytest1.user,mytest2\\..*,.*\\..*canal.mq.partition=0# hash partition config#canal.mq.partitionsNum=3#canal.mq.partitionHash=test.table:id^name,.*\\..*#################################################

正確運(yùn)行方式二

參考文章地址:https://my.oschina.net/amhuman/blog/1941540

采用如下方式可以直接運(yùn)行canal實(shí)現(xiàn)binlog的增量消費(fèi):

docker run --name canal -e canal.instance.master.address=192.168.1.111:3365 -e canal.instance.dbUsername=canal -e canal.instance.dbPassword=canal -p 11111:11111 -d canal/canal-server

開啟服務(wù)器端口訪問

#開啟端口訪問firewall-cmd --zone=public --add-port=11111/tcp --permanent #重載防火墻firewall-cmd --reload
image

Java測(cè)試客戶端

請(qǐng)使用canal提供的示例進(jìn)行測(cè)試落萎,https://github.com/alibaba/canal/wiki/ClientExample

package com.alibaba.otter; import java.net.InetSocketAddress;import java.util.List;import com.alibaba.otter.canal.client.CanalConnector;import com.alibaba.otter.canal.client.CanalConnectors;import com.alibaba.otter.canal.common.utils.AddressUtils;import com.alibaba.otter.canal.protocol.CanalEntry.Column;import com.alibaba.otter.canal.protocol.CanalEntry.Entry;import com.alibaba.otter.canal.protocol.CanalEntry.EntryType;import com.alibaba.otter.canal.protocol.CanalEntry.EventType;import com.alibaba.otter.canal.protocol.CanalEntry.RowChange;import com.alibaba.otter.canal.protocol.CanalEntry.RowData;import com.alibaba.otter.canal.protocol.Message;/** *  * @author PJL * * @note     功能描述:TODO增刪改查--事件捕捉 * @package  com.alibaba.otter * @filename SimpleCanalClientExample.java * @date     2019年4月16日 上午9:16:24 */public class SimpleCanalClientExample {       public static void main(String args[]) {        // 創(chuàng)建鏈接     CanalConnector connector = CanalConnectors.newSingleConnector(new InetSocketAddress("192.168.1.111"/*AddressUtils.getHostIp()*/,                                                                                            11111), "example", "canal", "canal");       int batchSize = 1000;       int emptyCount = 0;     try {           connector.connect();            connector.subscribe(".*\\..*");         connector.rollback();           int totalEmptyCount = 120;          while (emptyCount < totalEmptyCount) {              Message message = connector.getWithoutAck(batchSize); // 獲取指定數(shù)量的數(shù)據(jù)              long batchId = message.getId();             int size = message.getEntries().size();             if (batchId == -1 || size == 0) {                   emptyCount++;                   System.out.println("empty count : " + emptyCount);                  try {                       Thread.sleep(1000);                 } catch (InterruptedException e) {                  }               } else {                    emptyCount = 0;                 // System.out.printf("message[batchId=%s,size=%s] \n", batchId, size);                  printEntry(message.getEntries());               }               connector.ack(batchId); // 提交確認(rèn)             // connector.rollback(batchId); // 處理失敗, 回滾數(shù)據(jù)           }           System.out.println("empty too many times, exit");       } finally {         connector.disconnect();     }   }   private static void printEntry(List<Entry> entrys) {        for (Entry entry : entrys) {            if (entry.getEntryType() == EntryType.TRANSACTIONBEGIN || entry.getEntryType() == EntryType.TRANSACTIONEND) {               continue;           }           RowChange rowChage = null;          try {               rowChage = RowChange.parseFrom(entry.getStoreValue());          } catch (Exception e) {             throw new RuntimeException("ERROR ## parser of eromanga-event has an error , data:" + entry.toString(),                                        e);          }           EventType eventType = rowChage.getEventType();          // 可以獲取到數(shù)據(jù)庫實(shí)例名稱、日志文件翩肌、當(dāng)前操作的表以及執(zhí)行的增刪改查的操作         String logFileName= entry.getHeader().getLogfileName();         long logFileOffset= entry.getHeader().getLogfileOffset();           String dbName=entry.getHeader().getSchemaName();            String tableName=entry.getHeader().getTableName();          System.out.println(String.format("=======&gt; binlog[%s:%s] , name[%s,%s] , eventType : %s",                                             logFileName, logFileOffset,                                             dbName, tableName,                                          eventType));           for (RowData rowData : rowChage.getRowDatasList()) {                if (eventType == EventType.DELETE) {                    // 刪除                   printColumn(rowData.getBeforeColumnsList());                } else if (eventType == EventType.INSERT) {                 // 新增                   printColumn(rowData.getAfterColumnsList());             } else {                    System.out.println("-------&gt; before");                   printColumn(rowData.getBeforeColumnsList());                    System.out.println("-------&gt; after");                    printColumn(rowData.getAfterColumnsList());             }           }       }   }   private static void printColumn(List<Column> columns) {     for (Column column : columns) {         System.out.println(column.getName() + " : " + column.getValue() + "    update=" + column.getUpdated());     }   } }

錯(cuò)誤運(yùn)行容器測(cè)試結(jié)果

此處測(cè)試捕獲數(shù)據(jù)庫插入刪除事件模暗,不過未捕獲到,有待進(jìn)一步研究念祭!超時(shí)關(guān)閉機(jī)制:

empty count : 1empty count : 2empty count : 3empty count : 4empty count : 5empty count : 6empty count : 7empty count : 8empty count : 9empty count : 10empty count : 11empty count : 12empty count : 13empty count : 14empty count : 15empty count : 16empty count : 17empty count : 18empty count : 19empty count : 20empty count : 21empty count : 22empty count : 23empty count : 24empty count : 25empty count : 26empty count : 27empty count : 28empty count : 29empty count : 30empty count : 31empty count : 32empty count : 33empty count : 34empty count : 35empty count : 36empty count : 37empty count : 38empty count : 39empty count : 40empty count : 41empty count : 42empty count : 43empty count : 44empty count : 45empty count : 46empty count : 47empty count : 48empty count : 49empty count : 50empty count : 51empty count : 52empty count : 53empty count : 54empty count : 55empty count : 56empty count : 57empty count : 58empty count : 59empty count : 60empty count : 61empty count : 62empty count : 63empty count : 64empty count : 65empty count : 66empty count : 67empty count : 68empty count : 69empty count : 70empty count : 71empty count : 72empty count : 73empty count : 74empty count : 75empty count : 76empty count : 77empty count : 78empty count : 79empty count : 80empty count : 81empty count : 82empty count : 83empty count : 84empty count : 85empty count : 86empty count : 87empty count : 88empty count : 89empty count : 90empty count : 91empty count : 92empty count : 93empty count : 94empty count : 95empty count : 96empty count : 97empty count : 98empty count : 99empty count : 100empty count : 101empty count : 102empty count : 103empty count : 104empty count : 105empty count : 106empty count : 107empty count : 108empty count : 109empty count : 110empty count : 111empty count : 112empty count : 113empty count : 114empty count : 115empty count : 116empty count : 117empty count : 118empty count : 119empty count : 120empty too many times, exit

正常運(yùn)行容器測(cè)試結(jié)果

=======&gt; binlog[mysql-bin.000004:3504] , name[service_db,sys_user] , eventType : INSERTid : 52    update=truename : boonya    update=trueage : 28    update=trueempty count : 1empty count : 2empty count : 3empty count : 4empty count : 5empty count : 6empty count : 7empty count : 8empty count : 9empty count : 10empty count : 11empty count : 12empty count : 13empty count : 14empty count : 15=======&gt; binlog[mysql-bin.000004:3790] , name[service_db,sys_user] , eventType : INSERTid : 53    update=truename : boonya    update=trueage : 28    update=trueempty count : 1empty count : 2empty count : 3empty count : 4empty count : 5empty count : 6empty count : 7empty count : 8empty count : 9empty count : 10empty count : 11empty count : 12empty count : 13empty count : 14empty count : 15empty count : 16empty count : 17empty count : 18empty count : 19empty count : 20empty count : 21empty count : 22empty count : 23empty count : 24=======&gt; binlog[mysql-bin.000004:4076] , name[service_db,sys_user] , eventType : INSERTid : 54    update=truename : boonya    update=trueage : 28    update=true=======&gt; binlog[mysql-bin.000004:4362] , name[service_db,sys_user] , eventType : INSERTid : 55    update=truename : boonya    update=trueage : 28    update=trueempty count : 1=======&gt; binlog[mysql-bin.000004:4648] , name[service_db,sys_user] , eventType : INSERTid : 56    update=truename : boonya    update=trueage : 28    update=true=======&gt; binlog[mysql-bin.000004:4934] , name[service_db,sys_user] , eventType : INSERTid : 57    update=truename : boonya    update=trueage : 28    update=trueempty count : 1empty count : 2empty count : 3empty count : 4empty count : 5empty count : 6empty count : 7empty count : 8empty count : 9empty count : 10empty count : 11empty count : 12empty count : 13empty count : 14empty count : 15empty count : 16empty count : 17empty count : 18empty count : 19empty count : 20empty count : 21empty count : 22empty count : 23empty count : 24empty count : 25empty count : 26empty count : 27empty count : 28empty count : 29empty count : 30empty count : 31empty count : 32empty count : 33empty count : 34empty count : 35=======&gt; binlog[mysql-bin.000004:5220] , name[service_db,sys_user] , eventType : INSERTid : 58    update=truename : boonya    update=trueage : 28    update=true=======&gt; binlog[mysql-bin.000004:5506] , name[service_db,sys_user] , eventType : INSERTid : 59    update=truename : boonya    update=trueage : 28    update=trueempty count : 1=======&gt; binlog[mysql-bin.000004:5792] , name[service_db,sys_user] , eventType : INSERTid : 60    update=truename : boonya    update=trueage : 28    update=true=======&gt; binlog[mysql-bin.000004:6078] , name[service_db,sys_user] , eventType : INSERTid : 61    update=truename : boonya    update=trueage : 28    update=trueempty count : 1empty count : 2empty count : 3empty count : 4empty count : 5empty count : 6empty count : 7empty count : 8empty count : 9empty count : 10empty count : 11empty count : 12empty count : 13empty count : 14empty count : 15empty count : 16empty count : 17empty count : 18empty count : 19empty count : 20

數(shù)據(jù)庫異常問題

mysql5.7報(bào)錯(cuò):
[Err] 1055 - Expression #1 of ORDER BY clause is not in GROUP BY clause and contains nonaggregated column 'information_schema.PROFILING.SEQ' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

解決方法:

show variables like "sql_mode"; set sql_mode='';set sql_mode='NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES';
image

Canal只是一個(gè)基于增量日志的通道兑宇,如果需要數(shù)據(jù)庫實(shí)現(xiàn)備份還需要在Canal基礎(chǔ)上引入Otter,Otter定義了Channel粱坤、Pipleline隶糕、Node(機(jī)器節(jié)點(diǎn))、數(shù)據(jù)源站玄、目標(biāo)數(shù)據(jù)源枚驻、數(shù)據(jù)庫表、主備配置等等幫助實(shí)現(xiàn)數(shù)據(jù)庫增量備份機(jī)制株旷。

https://blog.csdn.net/boonya/article/details/89406067

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末再登,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子晾剖,更是在濱河造成了極大的恐慌锉矢,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,651評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件齿尽,死亡現(xiàn)場(chǎng)離奇詭異沽损,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)循头,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門绵估,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人卡骂,你說我怎么就攤上這事国裳。” “怎么了全跨?”我有些...
    開封第一講書人閱讀 162,931評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵躏救,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我螟蒸,道長(zhǎng)盒使,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,218評(píng)論 1 292
  • 正文 為了忘掉前任七嫌,我火速辦了婚禮少办,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘诵原。我一直安慰自己英妓,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評(píng)論 6 388
  • 文/花漫 我一把揭開白布绍赛。 她就那樣靜靜地躺著蔓纠,像睡著了一般。 火紅的嫁衣襯著肌膚如雪吗蚌。 梳的紋絲不亂的頭發(fā)上腿倚,一...
    開封第一講書人閱讀 51,198評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音蚯妇,去河邊找鬼敷燎。 笑死,一個(gè)胖子當(dāng)著我的面吹牛箩言,可吹牛的內(nèi)容都是我干的硬贯。 我是一名探鬼主播,決...
    沈念sama閱讀 40,084評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼陨收,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼饭豹!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起务漩,我...
    開封第一講書人閱讀 38,926評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤拄衰,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后菲饼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體肾砂,經(jīng)...
    沈念sama閱讀 45,341評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評(píng)論 2 333
  • 正文 我和宋清朗相戀三年宏悦,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了镐确。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,731評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡饼煞,死狀恐怖源葫,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情砖瞧,我是刑警寧澤息堂,帶...
    沈念sama閱讀 35,430評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響荣堰,放射性物質(zhì)發(fā)生泄漏床未。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評(píng)論 3 326
  • 文/蒙蒙 一振坚、第九天 我趴在偏房一處隱蔽的房頂上張望薇搁。 院中可真熱鬧,春花似錦渡八、人聲如沸啃洋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽宏娄。三九已至,卻和暖如春逮壁,著一層夾襖步出監(jiān)牢的瞬間孵坚,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工貌踏, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留十饥,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,743評(píng)論 2 368
  • 正文 我出身青樓祖乳,卻偏偏與公主長(zhǎng)得像逗堵,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子眷昆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容