Mycat知识精粹

  1. mycat是什么---作用:
    java应用程序与数据库紧耦合-----解耦application和db
    高访问量高并发对数据库压力----分库分表,多数据源整合
    读写请求数据量不一致---(双主双从)读写分离(基于mysql的主从复制)
    2.Mycat的安装
    需要事先安装jvm环境和安装mysql(jdk采用解压缩,mysql:sudo apt install mysql-server),Mycat压缩包:Mycat-server-1.6.7.1-release-20190627191042-linux.tar.gz,解压安装(安装包通常放在/opt路径下,解压后文件通常放在/usr/local路径下)
    windows文件拷贝到linux系统,pscp工具,对应命令:pscp 本地文件dir root@IP:/home/dir,随后mv移动文件到/opt路径下(pscp/scp时提示connection refused,原因可能目标linux中没有安装ssh-server或没有启动,sudo apt-get install openssh-server命令安装)
    linux解压命令 tar -zxvf Mycat-server-1.6.7.1-release-20190627191042-linux.tar,随后mv文件夹到/usr/local路径下
    3.mycat的配置
    备份config路径下server.xml,schema.xml,rule.xml文件
    修改配置文件server.xml
    mycat-server-config.png
    (vi模式下显示行号:set nu,删除多行是dnd,如d27d)修改配置文件schema.xml:
    mycat-schema-config.png
    4.Mysql远程访问验证
    Mycat作为数据库中间件,要和不同地址的数据库建立访问,准备3台虚拟机数据库地址
    mysql -uroot -p556600 -h 10.0.0.214 -P 3306
    mysql -uroot -p556600 -h 10.0.0.212 -P 3306
    mysql -uroot -p556600 -h 10.0.0.177 -P 3306
    如果无权远程访问,主机间授权:grant all privileges on . to root@被受限的主机IP identified by '556600';
    如果遇到报错:Can't connect to MySQL server on (111),修改mysql配置:/etc/mysql/mysql.cnf.d/mysqld.cnf,注释bind地址或者改成0.0.0.0,重启mysql服务:service mysql restart
    如果遇到报错Can't connect to MySQL server on (110),需关闭防火墙,ubuntu16.04 开启/关闭防火墙:sudo ufw enable/sudo ufw disable
    5.Mycat的启动/访问
    linux系统中6个任意目录都可以执行的路径:bin sbin usr/bin usr/sbin usr/local/bin usr/local/sbin
    控制台启动:mycat/bin目录下执行 ./mycat console(推荐)
    后台启动: mycat/bin目录下执行 ./mycat start
    运维登录方式访问:mysql -uuser1 -p556600 -h 10.0.0.162 -P9066
    数据查询方式访问:mysql -uuser1 -p556600 -h 10.0.0.162 -P8066
    注:大p和小p都要写,并且mycat服务器本分要开启远程访问,否则localhost方式只能适合访问本地mysql而不能访问mycat配置的数据库

6.mysql 一主一从搭建
1.不同于redis的主从复制,redis从头复制,替换rdb文件,而mysql从主从复制的切入点开始复制
2.从机读主机的binary log后写入自身的relay log,多次io操作,数据有延迟

主机配置-修改配置文件:vim /etc/mysql/mysql.conf.d/mysqld.cnf(提前备份)
1.主机唯一id server-id=1
2.启动二进制日志 log-bin=mysql-bin
3.设置需要复制的数据库 binlog-do-db=需要复制的主数据的名字
4.设置不需要复制的数据库 binlog-ignore-db=mysql binlog-ignore-db=information_schema
5.设置logbin格式 binlog_format=STATEMENT(默认)

从机配置-修改配置文件:vim /etc/mysql/mysql.conf.d/mysqld.cnf(提前备份)
1.从机唯一id server-id=2
2.启用中继日志
relay-log=mysql-relay

重启mysql主机从机的服务
主机从机关闭防火墙

在主机上以-hlocalhost而非主机ip方式登录,建立账户并授权salve,授权命令 GRANT REPLICATION SALVE ON . TO 'slave'@'可以以这个用户名密码访问主机的ip(%表示任意ip)' IDENTIFIED BY '556600';

查看主机状态
show master status;

从机复制主机的命令 CHANGE MASTER TO MASTER_HOST = '主机ip'
,MASTER_USER='slave'
,MASTER_PASSWORD='556600'
,MASTER_LOG_FILE='mysql-bin.具体数字'---show master status信息
,MASTER_LOG_POS=722;---show master status信息
(如果报错ERROR3021,表示已经启动了从机复制,需要stop slave(停止主从复制关系),然后reset master(重新配置主从),再执行上面的语句)

启动从机复制功能 start slave

查看从机状态
show slave status\G;---Slave_IO_Running和Slave_SQL_Running都是Yes表示主从复制搭建成功
如果MySQL报错:master and slave have equal MySQL server UUIDs 或者A slave with the same server_uuid/server_id as this slave has connected to the master,主要是因为两台虚拟服务器是经过链路复制生成的,导致auto.cnf中的UUID一样,此时vi /var/lib/mysql/auto.cnf修改auto.cnf中的UUID即可,如cd时permission denied,sudo su,cd openfiledir
注:从机一旦复制报错,就停止复制操作,即便stop后再start slave,目前验证下来有效的方式是删除库,stop slave后reset slave,start slave就可以了(实际生产环境可操作性待商榷)

验证读写分离
基于之前mycat的配置,启动mycat,进入配置的数据库TESTDB(逻辑库),use TESTDB,select * from mytbl可以查到数据
验证查询的配置的主机的数据还是从机的数据,方式:
分别在各机器的mysqll设置set @hostname=主机名,在写主机中执行insert into mytbl(1,@@hostname);在mycat中看插入数据的主机名---(@@系统变量)
结果:显然一定是查询的主机,因为需要更改<dataHost>的balance属性,通过此属性配置读写分离的类型,
为了能看到读写分离的效果,把balance设置成2,会在两个主机间切换查询,实际应用场景中使用1或者3,配置负载均衡类型,目前的取值有4 种:
(1)balance="0", 不开启读写分离机制,所有读操作都发送到当前可用的 writeHost 上。
(2)balance="1",全部的 readHost 与 stand by writeHost 参与 select 语句的负载均衡,简单的说,当双主双从模式(M1->S1,M2->S2,并且 M1 与 M2 互为主备),正常情况下,M2,S1,S2 都参与 select 语句的负载均衡。
(3)balance="2",所有读操作都随机的在 writeHost、readhost 上分发。
(4)balance="3",所有读请求随机的分发到 readhost 执行,writerHost 不负担读压力

7.mysql 双主双从搭建
基于前面的一主一从的环境,首先stop slave和reset master,删除已存在各个机器上的mycat库
注:提前确保都安装了ssh,命令sudo apt-get install openssh-server
参照一主一从设置权限配置,同上修改mysql配置和主机间访问权限,其次:
对于主机M1特殊配置增加:
log-slave-updates
auto-increment-increment = 2
auto-increment-increment = 1
对于主机M2特殊配置增加:
log-slave-updates
auto-increment-increment = 2
auto-increment-increment = 2

s1机器reset master to m1,s2机器reset master to m2,m1机器reset master to m2,m2机器reset master to m1,命令如change master to master_host = '192.168.0.11',master_user='slave',master_password='556600',master_log_file='mysql-bin.000001',master_log_pos=154;具体master_log_file和master_log_pos以主机show master status信息为准
各主机登录mysql,授权从机拷贝主机数据,命令grant replication slave on . to slave@从机IP identified by ‘556600’;
各从机start slave,查看slave状态

双主双重读写分离
修改schema.xml配置,其中
balance="1": 全部的readHost与stand by writeHost参与select语句的负载均衡
writeType="0": 所有写操作发送到配置的第一个writeHost,第一个挂了切到还生存的第二个
writeType="1",所有写操作都随机的发送到配置的 writeHost,1.5 以后废弃不推荐

switchType="1": 1 默认值,自动切换,-1 表示不自动切换,2 基于 MySQL 主从同步的状态决定是否切换
mycat-schema-double-config.png

启动mycat

分库(启动15,16两台机器,各权限和数据库配置等配置同上)

修改schema.xml配置
mycat-schema-splitdb.png
在15机器上创建库orderdb,16机器上创建库userdb,启动mycat并访问,分别创建表:

客户表 rows:20万
CREATE TABLE customers(
id INT AUTO_INCREMENT,
NAME VARCHAR(200),
PRIMARY KEY(id)
);
订单表 rows:600万
CREATE TABLE orders(
id INT AUTO_INCREMENT,
order_type INT,
customer_id INT,
amount DECIMAL(10,2),
PRIMARY KEY(id)
);
最后验证,只有customers表创建在了userdb,其余表创建在了orderdb,分库成功

分表-水平(启动15,16两台机器,各权限和数据库配置等配置同上,删除orders表)

修改schema.xml配置:为 orders 表设置数据节点为 dn1、dn2,并指定分片规则为 mod_rule(自定义的名字)
mycat-schema-splittb.png
mycat-rule-splittb.png

重启mycat并创建orders表
插入数据(插入字段必须写明):INSERT INTO orders(id,order_type,customer_id,amount) VALUES (1,101,100,100100);
INSERT INTO orders(id,order_type,customer_id,amount) VALUES(2,101,100,100300);
INSERT INTO orders(id,order_type,customer_id,amount) VALUES(3,101,101,120000);
INSERT INTO orders(id,order_type,customer_id,amount) VALUES(4,101,101,103000);
INSERT INTO orders(id,order_type,customer_id,amount) VALUES(5,102,101,100400);
INSERT INTO orders(id,order_type,customer_id,amount) VALUES(6,102,100,100020);
在mycat、dn1、dn2中查看orders表数据(插入的几条数据落在了dn1和dn2各自的orders表)
mycat查询验证:
select * from orders;发现结果不是有序的,原因数据落在不同的dn节点,分别查询不同节点后对结果集合并,需要写明order by

分表-水平-join操作
由于对orders表进行了水平分表,对其关联表orders_detail也要进行水平分表,否则分落在不同dn上的order的数据只能关联上某一个dn上的表数据,而关联不上的那部分order数据进行join orders_detail数据时报错

修改schema.xml文件
mycat-rule-splittb.png
重启mycat并创建订单详细表 rows:600万
CREATE TABLE orders_detail(

id INT AUTO_INCREMENT,
detail VARCHAR(2000),
order_id INT,
PRIMARY KEY(id));
插入数据INSERT INTO orders_detail(id,detail,order_id) values(1,'detail1',1);
INSERT INTO orders_detail(id,detail,order_id) VALUES(2,'detail1',2);
INSERT INTO orders_detail(id,detail,order_id) VALUES(3,'detail1',3);
INSERT INTO orders_detail(id,detail,order_id) VALUES(4,'detail1',4);
INSERT INTO orders_detail(id,detail,order_id) VALUES(5,'detail1',5);
INSERT INTO orders_detail(id,detail,order_id) VALUES(6,'detail1',6);
在mycat、dn1、dn2中运行两个表join语句
Select o.*,od.detail from orders o inner join orders_detail od on o.id=od.order_id;

分表-水平-全局表

修改schema.xml
mycat-schema-plittb-global.png
重启mycat并创建订单状态字典表 rows:20

CREATE TABLE dict_order_type(
id INT AUTO_INCREMENT,
order_type VARCHAR(200),
PRIMARY KEY(id)
);
然后插入数据:
INSERT INTO dict_order_type(id,order_type) VALUES(101,'type1');
INSERT INTO dict_order_type(id,order_type) VALUES(102,'type2');
在Mycat、dn1、dn2中查询表数据(dn1和dn2的dict_order_type都有数据且完全一致)

常用分片规则-枚举

修改schema和rule以及配置文件
mycat-schema-splittb-2.png
mycat-rule-splittb-2.png
mapFile:标识配置文件名称,type:0为int型、非0为String,defaultNode:默认节点:小于 0 表示不设置默认节点,大于等于 0 表示设置默认节点

修改partition-hash-int.txt
mycat-file-splittb-2.png

重启mycat并创建表CREATE TABLE orders_ware_info
(
id INT AUTO_INCREMENT comment '编号',
order_id INT comment '订单编号',
address VARCHAR(200) comment '地址',
areacode VARCHAR(20) comment '区域编号',
PRIMARY KEY(id)
);
插入数据
INSERT INTO orders_ware_info(id, order_id,address,areacode) VALUES (1,1,'北京','110');
INSERT INTO orders_ware_info(id, order_id,address,areacode) VALUES (2,2,'天津','120');
INSERT INTO orders_ware_info(id, order_id,address,areacode) VALUES (3,3,'苏州','130');
结果dn1存放北京数据,dn2存放天津数据,非配置的北京和天津的数据默认落在dn1(问题点:物理库还没有创建表的时候,虚拟库通过show tables可以看到配置的表信息)

常用分片规则-范围,此分片适用于,提前规划好分片字段某个范围属于哪个分片
修改schema,rule和配置文件

mycat-schema-splittb-3.png
mycat-rule-splittb-3.png
mycat-file-splittb-3.png

重启mycat并创建支付信息表
CREATE TABLE payment_info
(
id INT AUTO_INCREMENT comment '编号',
order_id INT comment '订单编号',
payment_status INT comment '支付状态',
PRIMARY KEY(id)
);
插入数据
INSERT INTO payment_info (id,order_id,payment_status) VALUES (1,101,0);
INSERT INTO payment_info (id,order_id,payment_status) VALUES (2,102,1);
INSERT INTO payment_info (id,order_id ,payment_status) VALUES (3,103,0);
INSERT INTO payment_info (id,order_id,payment_status) VALUES (4,104,1);
INSERT INTO payment_info (id,order_id,payment_status) VALUES (5,-1000,1);
INSERT INTO payment_info (id,order_id,payment_status) VALUES (6,1000,1);
结果dn1存放0-102数据,dn2存放102-200数据,非配置的区间段里的数据落到默认dn1(问题点:物理库还没有创建表的时候,虚拟库通过show tables可以看到配置的表信息)

常用分片规则-日期
修改schema,rule配置

mycat-schema-splittb-4.png

mycat-rule-splittb-4.png
sEndDate:结束日期,则代表数据达到了这个日期的分片后循环从开始分片插入
sPartionDay :分区天数,即默认从开始日期算起,分隔 2 天一个分区
重启mycat并创建login_info表
CREATE TABLE login_info
(
id INT AUTO_INCREMENT comment '编号',
user_id INT comment '用户编号',
login_date date comment '登录日期',
PRIMARY KEY(id)
);

插入数据:
INSERT INTO login_info(id,user_id,login_date) VALUES (1,101,'2019-01-01');
INSERT INTO login_info(id,user_id,login_date) VALUES (2,102,'2019-01-02');
INSERT INTO login_info(id,user_id,login_date) VALUES (3,103,'2019-01-03');
INSERT INTO login_info(id,user_id,login_date) VALUES (4,104,'2019-01-04');
INSERT INTO login_info(id,user_id,login_date) VALUES (5,105,'2019-01-05');
INSERT INTO login_info(id,user_id,login_date) VALUES (6,106,'2019-01-06');
INSERT INTO login_info(id,user_id,login_date) VALUES (7,107,'2019-01-07');
结果dn1存放1,2,5,6数据,dn2存放3,4,7数据(问题点:物理库还没有创建表的时候,虚拟库通过show tables可以看到配置的表信息)

全局序列--数据库方式
在 dn1 上创建全局序列表和创建全局序列所需函数(直接在dn1上操作,未验证配置mycat后重新,通过mycat创建是否有效)
CREATE TABLE MYCAT_SEQUENCE (NAME VARCHAR(50) NOT NULL,current_value INT NOT NULL,increment INT NOT NULL DEFAULT 100, PRIMARY KEY(NAME)) ENGINE=INNODB;

DELIMITER CREATE FUNCTION mycat_seq_currval(seq_name VARCHAR(50)) RETURNS VARCHAR(64) DETERMINISTIC BEGIN DECLARE retval VARCHAR(64); SET retval="-999999999,null"; SELECT CONCAT(CAST(current_value AS CHAR),",",CAST(increment AS CHAR)) INTO retval FROM MYCAT_SEQUENCE WHERE NAME = seq_name; RETURN retval; END

DELIMITER CREATE FUNCTION mycat_seq_setval(seq_name VARCHAR(50),VALUE INTEGER) RETURNS VARCHAR(64) DETERMINISTIC BEGIN UPDATE MYCAT_SEQUENCE SET current_value = VALUE WHERE NAME = seq_name; RETURN mycat_seq_currval(seq_name); END

DELIMITER CREATE FUNCTION mycat_seq_nextval(seq_name VARCHAR(50)) RETURNS VARCHAR(64) DETERMINISTIC BEGIN UPDATE MYCAT_SEQUENCE SET current_value = current_value + increment WHERE NAME = seq_name; RETURN mycat_seq_currval(seq_name); END

初始化序列表记录
INSERT INTO MYCAT_SEQUENCE(NAME,current_value,increment) VALUES ('ORDERS', 400000,100);

修改 Mycat 配置

server.xml:
mycat-server-sequence-config.png
全局序列类型:0-本地文件,1-数据库方式,2-时间戳方式

sequence_db_conf:
mycat-sequence-splittb.png
ORDERS这个序列在dn1这个节点上
插入数据:
insert into orders(id,amount,customer_id,order_type) values(next value for
MYCATSEQ_ORDERS,1000,101,102);验证id从400100开始

基于 HA 机制的 Mycat 高可用(4台机器,10,20,15,16)
15安装 HAProxy:
1准备好HAProxy安装包,传到/opt目录下
2解压到/usr/local/src
sudo tar -zxvf haproxy-1.5.18.tar.gz -C /usr/local/src
3进入解压后的目录,查看内核版本,进行编译
cd /usr/local/src/haproxy-1.5.18
uname -r
sudo make TARGET=linux310 PREFIX=/usr/local/haproxy ARCH=x86_64
TARGET=linux310,内核版本,使用uname -r查看内核,如:3.10.0-514.el7,此时该参数就为linux310;
ARCH=x86_64,系统位数;
PREFIX=/usr/local/haprpxy #/usr/local/haprpxy,为haprpxy安装路径
make视情况按需安装(sudo apt install make)
4编译完成后,进行安装
sudo make install PREFIX=/usr/local/haproxy
5安装完成后,创建目录、创建HAProxy配置文件
mkdir -p /usr/data/haproxy/
sudo vim /usr/local/haproxy/haproxy.conf
6向配置文件中插入以下配置信息,并保存
global
log 127.0.0.1 local0
maxconn 4096
chroot /usr/local/haproxy
pidfile /usr/data/haproxy/haproxy.pid
uid 99
gid 99
daemon
defaults
log global
mode tcp
option abortonclose
option redispatch
retries 3
maxconn 2000
timeout connect 5000
timeout client 50000
timeout server 50000
listen proxy_status
bind :48066
mode tcp
balance roundrobin
server mycat_1 192.168.0.10:8066 check inter 10s
server mycat_2 192.168.0.20:8066 check inter 10s
frontend admin_stats
bind :7777
mode http
stats enable
option httplog
maxconn 10
stats refresh 30s
stats uri /admin
stats auth admin:123123
stats hide-version
stats admin if TRUE
7启动HAProxy
sudo /usr/local/haproxy/sbin/haproxy -f /usr/local/haproxy/haproxy.conf
8查看haproxy进程 ps -ef|grep haproxy
9打开浏览器访问 http://192.168.0.15:7777/admin,在弹出框输入用户名:admin密码:123123
10验证mycat的高可用和haproxy负载均衡:通过HAProxy访问Mycat:mysql -uuser1 -p556600 -h192.168.0.15 -P 48066

安装配置keepalived此处暂时省略//todo

user 标签权限控制

server.xml配置
mycat-server-readonly-user.png
privileges 标签权限控制

在 user 标签下的 privileges 标签可以对逻辑库(schema)、表(table)进行精细化的 DML 权限控制
privileges 标签下的 check 属性,如为 true 开启权限检查,为 false 不开启,默认为 false
由于 Mycat 一个用户的 schemas 属性可配置多个逻辑库(schema) ,所以privileges 的下级

节点 schema 节点同样可配置多个,对多库多表进行细粒度的 DML 权限控制
mycat-server-privileges-dml.png
其中dml配置如下:
mycat-dml.png

SQL拦截
firewall 标签用来定义防火墙,其下
白名单:可以通过设置白名单,实现某主机某用户可以访问 Mycat,而其他主机用户禁止访问
黑名单;可以通过设置黑名单,实现 Mycat 对具体 SQL 操作的拦截,如增删改查等操作的拦截

Mycat-web 配置使用(10号机器)
1.Mycat-web 配置使用
下载安装包http://zookeeper.apache.org/,安装包拷贝到Linux系统/opt目录下,并解压tar -zxvf zookeeper-3.4.11.tar.gz到/usr/local路径下
进入ZooKeeper解压后的配置目录(conf),复制配置文件并改名
cp zoo_sample.cfg zoo.cfg
进入ZooKeeper的命令目录(bin),运行启动命令sudo ./zkServer.sh start
ZooKeeper服务端口为2181,查看服务已经启动
netstat -ant | grep 2181
如报错nohup: 无法运行命令'java': 没有那个文件或目录,把JAVA_HOME配置到zkEnv.sh文件里(JAVA_HOME="/usr/local/.....")
2.Mycat-web 安装
下载安装包http://www.mycat.io/,安装包拷贝到Linux系统/opt目录下,并解压
tar -zxvf Mycat-web-1.0-SNAPSHOT-20170102153329-linux.tar.gz到/usr/local目录下
进入mycat-web的目录下运行启动命令./start.sh &
Mycat-web服务端口为8082,查看服务已经启动
netstat -ant | grep 8082

通过地址访问服务
http://192.168.0.10:8082/mycat/

--最后插一句:如果schema配置文件没有配置表创建在哪个dn数据节点上,默认第一个,其他的不创建该表
---END

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,924评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,781评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,813评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,264评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,273评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,383评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,800评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,482评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,673评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,497评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,545评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,240评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,802评论 3 304
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,866评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,101评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,673评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,245评论 2 341

推荐阅读更多精彩内容