第十四周《简述LVS调度方案....》

一、简述LVS调度方案及应用场景

Lvs的调度算法可分为静态调度和动态调度。
- 静态调度即根据算法本身的结果来进行调度,包括:

1、轮询调度算法(RR),轮询算法适用于所有服务器的处理性能相近的应用场景,因为轮询算法相对简单,其调度方式是不管服务器当前的连接数和响应速度如何的。因此当后端服务器的处理性能残次不齐,请求服务的时间变化较大时,轮询算法很容易导致服务器间的负载不均衡。因此轮询算法只适用于后端服务器性能相近,请求时间变化不大的场景使用。

2、加权轮询调度算法(WRR)可以理解为轮询算法的进阶版。通过设置权重来表示后端服务器的处理型男,权重越大表示服务器能的处理能力越强。但是当请求时间变化很大时,加权轮询算法依然会导致服务器间的负载不平滑。

3、目标地址哈希调度算法(DH)是指针对通过计算目前地址的散列(HASH)函数来将一个目标IP地址映射到一台服务器。DH算法首先根据请求的目标Ip地址作为散列键(Hask key),从静态分配的散列表中找出对应的服务器。若该服务器是可用且未超载,则将请求发送到该服务器,否则返回为空。此调度算法可保证用户访问同一个应用服务时,请求均被送往同一个后端服务器。典型应用场景为正向代理缓存场景中的负载均衡。

4、源地址散列调度算法(SH)是指根据请求的源Ip地址作为散列键(Hash key),从静态分配的散列表中找出其对应的服务器。若服务器是可能且未超载,否则将返回空。SH算法可将来自于同一个IP地址的请求始终发往同一个后端服务器,从而实现会话绑定。

- 动态调度算法即指结合算法及当前每个后端服务器的负载状态进行计算调整选出最优的后端服务器进行分配负载,其包括:

1、最小连接调度算法(LCS)是指把新的连接请求分配到当前连接数最小的服务器。调度器会记录各个服务器已建立连接的数目,当一个请求被调度分配到一个后端服务器,其连接数就加一;当连接超时或终止时,其连接数减一。LCS算法则会把新的连接请求到分分配到已建立连接数最小的服务器上,保证后端服务器,每一个都始终处于工作状态。此算法适用于后端服务器性能差不多,请求时间不一样的情况下使用。

2、加权最小连接调度算法(WLC)是在一个服务器性能差异较大的集群中,根据最小连接数及服务器的权重来分配新的连接请求。对比LCS算法来说,WLC可优化负载均衡的性能,使得具有较高权重的服务器承受较大比例的活动连接负载。
3、最小期望延迟调度算法(SED)是WLC算法的改进版,根据算法(active+1)*256/weight的结果,将请求分配给计算结果最小的服务器。

4、从不排队调度(NQ),增强改进的sed算法,即在sed算法结果之后增加了轮询的机制。如果有台real Server的连接数=0直接分配,不需要再进行sed运算,而是直接分配请求连接到指定的服务器。因此这种算法就会尽量不然请求出现排队的情况,即避免了某个节点非常繁忙而其他节点相对空闲的情况。避免了权重小的节点不会出现没有请求被调度的情况。

  1. 基于本地的LC(LBLC),其实就是动态的DH算法,考虑了服务器的负载;损失了命中率,提高了均衡性;
    针对目标IP地址的负载均衡,目前主要用于cache集群系统;该算法根据请求的目标IP地址找出该目标IP地址最近使用的服务器,若改服务器是可用的且没有超载,将请求发送到该服务器;若服务器不存在,或者该服务器超载且有服务器处于一半的工作负载,则用最少链接的原则选出一个可用的服务器,将请求发送到该服务器;

  2. 带复制的LBLC(LBLCR),也是针对目标IP地址的负载均衡,目前主要用于cache集群系统;它与LBLC算法的不同之处是它要维护从一个目标IP地址到一组服务器的映射,而LBLC算法维护从一个目标IP地址到一台服务器的映射;该算法根据请求的目标IP地址找出该目标IP地址对应的服务器组,按最小链接原则从服务器组中选出一台服务器,若服务器没有超载,将请求发往该服务器,若服务器超载,则按最小链接原则从这个集群中选出一台服务器,将该服务器加入到服务器组中,将请求发往该服务器;同时,当该服务器组有一段时间没有被修改,将最忙的服务器从服务器组中删除,以降低复制的程度;

二、详细描述nginx模块并举例说明

ngx_http_proxy_module模块
  • 1. proxyh_pass URL;

可实现动静分离;能够实现将请求发给后端URL指定的主机地址,这里之所以使用URL可以完成URL映射;例如前端的url为bbs,后端url可以是forum。

配置段:location, if in location, limit_except

通常其使用格式类似于:

proxy_pass [http://host[:port][/uri](http://host[:port][/uri)];

值得注意的是proxy_pass的路径后面有没有/uri是有区别的,当proxy_pass后面的路径不带uri时,其会将location的uri传递给后端主机;如:

server {

 ...

 server_name HOSTNAME;

 location /blog/ {

 proxy http://10.10.10.10;

 }

 ...

}

#上述location的/blog/会传递给10.10.10.10主机,实际代理访问的位置为http://10.10.10.10/blog/。

又如当proxy_pass后面的路径带有/uri时,其会将location的uri替换为proxy_pass的uri,如:

server {

 ...

 server_name www.a.com

 location /blog/ {

 proxy_pass http://10.10.10.10/news/;

 }

 ...

}

此时访问http://www.a.com/blog/实际上就是访问http://10.10.10.10/news/,/blog/被替换成了/news/。

此外还要注意点的是如果在location定义uri时使用了正则表达式匹配的模式,或在if语句或limt_execept中使用proxy_pass指令,则proxy_pass之后必须不能使用uri; 用户请求时传递的uri将直接附加代理到的服务的之后,如:

location ~* \.(jpg|png|gif)$ {

proxy_pass http://10.10.10.10;

}
    1. proxy_set_header field value;

设定向后端主机发送的请求报文的首部及其值;或是在原有首部后添加新值;

配置段:http, server, location

能抓取终端用户IP地址,field可自定义;默认为$proxy_host代理主机的IP地址;可以设定任何首部的值;

server {

 listen 80;

 server_name www.ilinux.io;

 location /blog/blog.html {

#在代理服务器上将远程客户端的Ip设置为X-Real-IP

 proxy_set_header X-Real-IP $remote_addr;

 proxy_pass http://10.10.10.11/news/news.html;

 }

}

#在后端服务器,设置access日志的格式,将原本的$remote_addr替换为$http_x_real_ip

log_format main '$http_x_real_ip - $remote_user [$time_local] "$request" '

 '$status $body_bytes_sent "$http_referer" '

 '"$http_user_agent" "$http_x_forwarded_for"';

#在测试访问几次后,查看后端服务器的access_log文件即可查看到相应的访问客户端IP

proxy_set_header X-Forwarded-For $proxy_add_x_forwared_for;

#表示如果X-Forwarded-For有首部值,会把$remote_addr的值补充在后面;为什么要补充,因为真正的代理费服务器是可以多级代理的;一个客户端可以有多级正向代理,反向代理也可有多级,这样在后端服务器日志记录的有可能不是最终用户的iP地址;所以像这种多级代理场景,每一个代理服务器都会附加一个新首部值,最终会知道最左侧的值是终端用户的iP地址;
    1. proxy_cache_path path
      只能用于http上下文;
      用于配置代理缓存的路径及其他参数,其完整使用格式如下:

proxy_cache_path path [levels=levels] [use_temp_path=on|off] keys_zone=name:size [inactive=time] [max_size=size] [manager_files=number] [manager_sleep=time] [manager_threshold=time] [loader_files=number] [loader_sleep=time] [loader_threshold=time] [purger=on|off] [purger_files=number] [purger_sleep=time] [purger_threshold=time];

levels参数定义了cache保留路径的层次结构,最多支持三层级结构。levels的值支持1或2,表示以多少个字符命名层级目录。如levels=1:2:3,表示缓存路径为三级目录结构,其中一级子目录以1个字符命名,二级子目录2个,三级子目录3个。
keys_zone参数用于定义cache zone的名称及分配的内存大小,如:keys_zone=cache1:100m。
max_size参数用于设置缓存zone的最大容量是多少;
inactive参数用于设置这个zone中的缓存文件如果在指定的时间内都没有被访问,则文件会被cache manager进程删除掉。

配置示例:

proxy_cache_path  /usr/local/nginx/proxy_cache_dir/cache1  levels=1:2 keys_zone=cache1:100m inactive=1d max_size=10g;
  • 4、proxy_cache zone_name | off;
    配置段:http, server, location
    用于指定要调用的缓存zone,或者关闭缓存机制。
    配置示例:
server {
    ...
    server_name HOSTNAME;
    location /uri/ {
        proxy http://hos[:port];
        proxy_cache cache1;
    }
    ...
}
  • 5.proxy_cache_key string;
    定义缓存键;
    proxy_cache_key $request_uri
    proxy_cache_key $scheme$proxy_host$request_uri
    多个变量的值作为一个字符串使用,这样,即便访问的是同一url,如果使用的协议不同,对应的缓存项也不一样;因此,key就决定了两个缓存项是否为同一个;
  • 6.proxy_cache_valid [code ...] time;
    为不同的响应码设定其缓存的时长;
    示例:
    proxy_cache_valid 200 303 10m;
    proxy_cache_valid 404 1m;

响应码没定义的表示不缓存;
实例:

定义缓存:
]# vim /etc/nginx/nginx.conf
在http中定义:
proxy_cache_path /var/cache/nginx/myproxy levels=2:1:1 keys_zone=mycache:10m max_size=1g;
表示:
/var/cache/nginx/myproxy:定义缓存保存路径,如果目录不存在,要事先创建;
levels=2:1:1 创建3级缓存目录,每一级用1个字符;
max_size=1g:缓存的文件可用空间大小为1G;
keys_zone=mycache:10m:缓存名为mycache,大小为10M;

]# 

还要在server中定义调用缓存的名称:
]# vim /etc/nginx/conf.d/default.conf
    location / {
       # root   /usr/share/nginx/html;
       proxy_cache mycache;
       proxy_cache_key $request_uri;
       proxy_cache_valid 200 302 10m;
       proxy_cache_valid 404 1m;
        proxy_pass http://192.168.1.3;
        index  index.html index.htm;
    }
其中:
proxy_cache mycache 调用缓存名称;
proxy_cache_key $request_uri 指定缓存中的key为请求的uri;
proxy_cache_valid 200 302 10m 缓存响应码为200,302的资源10分钟;
proxy_cache_valid 404 1m 缓存响应码为404的资源为1分钟;
  • 7、proxy_cache_use_stale error | timeout | invalid_header | updating | http_500 | http_502 | http_503 | http_504 | http_403 | http_404 | http_429 | off ...;
    配置段: http, server, location
    指明在什么情况下是否使用过期缓存;当代理服务器后后端主机通信发生错误时,在哪种错误情况下可以使用缓存中的内容,直接响应给客户端;
  • 8、proxy_cache_methods GET | HEAD | POST ...;
    配置段: http, server, location
    当客户端使用指定的请求方法发送请求时,该请求会被缓存下来。GET和HEAD是默认就被指定的缓存方法。
  • 9、proxy_hide_header field;
    配置段:http, server, location
    默认情况下,nginx不会将报文首部“Date”,“Server”等字段从代理服务器传递给客户端。而此指令,可让管理员设置额外的不进行传递的字段。
  • 10、proxy_connect_timeout time;
    配置段: http, server, location
    定义代理服务器的连接超时时长,默认为60s,最长不超过75s;
  • 11、proxy_read_timeout time;
    配置段: http, server, location、
    用于定义nginx会等待多长时间来获得请求的响应。这个时间不是获得整个response的时间,而是两次reading操作的时间。默认为60s。
  • 12、proxy_send_timeout time;
    配置段:http, server, location
    用于定义nginx发送请求给后端服务器的超时时间。这个时间不是获得整个response的时间,而是两次sending操作的时间。默认为60s。
gx_http_headers_module模块

此模块用于在代理服务器响应给客户端的响应报文中添加自定义首部或修改指定首部的值。

  • 1.add_header name value [always];
    向响应给客户端的报文添加自定义首部,并赋值;
    配置段http, server, location, if in location;
server {
        listen 80;
        server_name www.ilinux.io;
        location /blog/blog.html {
                proxy_set_header X-Real-IP  $remote_addr;
#添加自定义首部X-via表示代理服务器IP
                add_header X-Via  $server_addr;
#添加自定义首部X-Accel表示代理服务器的主机名
                add_header X-Accel $server_name;
                proxy_pass http://10.10.10.11/news/news.html;
        }
}
  • 2、expires [modified] time;
    expires epoch | max | off;
    配置段:http, server, location, if in location
    此指令用于定义客户端本地缓存超时时间或Cache-Control首部的值。
    示例:
#表示指定路径上的图片在客户端上缓存3天才失效
location ~* \.(gif|jpg|jpeg|png) {

root  /var/mywww/html/public/

expires 3d;

}
ngx_http_fastcgi_module模块
    1. fastcgi_pass address;
      配置段: location, if in location
      此指令用于指定一个fastcgi服务器的地址,可以服务器的主机名或IP+端口的方式指定。
      示例:
location ~* \.php$ {
        ....
        fastcgi_pass 10.10.10.13:9000;
        ...
}
  • 2、fastcgi_index name;
    配置段:http, server, location
    设置fastcgi的默认主页资源,如果URI以斜线结尾,文件名将追加到URI后面,这个值将存储在变量$fastcgi_script_name中。例如:
fastcgi_index  index.php;
fastcgi_param  SCRIPT_FILENAME  /home/www/scripts/php$fastcgi_script_name;
请求uri/page.php的参数SCRIPT_FILENAME将被设置为/home/www/scripts/php/page.php,但是"/"为"/home/www/scripts/php/index.php"。
  • 3、fastcgi_param parameter value [if_not_empty];
    配置段:http, server, location
    此指令用于指定要传递给FastCGI服务器的参数,参数可以为文本、变量和两者之间的组合。
    示例:
#将匹配的php内容送到fastcgi服务器的/usr/share/nginx/html目录下进行处理,即指定fastcgi服务器上用于存放PHP内容的目录
location ~* \.php$ {
    root           /usr/share/nginx/html;
    fastcgi_pass   127.0.0.1:9000;
    fastcgi_index  index.php;
    fastcgi_param  SCRIPT_FILENAME  /usr/share/nginx/html$fastcgi_script_name;
    include        fastcgi_params;  #调用nginx的变量定义;
}
  • 4、fastcgi_cache_path path [levels=levels] [use_temp_path=on|off] keys_zone=name:size [inactive=time] [max_size=size] [manager_files=number] [manager_sleep=time] [manager_threshold=time] [loader_files=number] [loader_sleep=time] [loader_threshold=time] [purger=on|off] [purger_files=number] [purger_sleep=time] [purger_threshold=time];
    配置段:http
    此指令用于定义fastcgi代理的缓存路径,缓存位置为nginx服务器上的文件路径。

levels=levels:缓存目录的层级数量,以及每一级的目录数量;格式为:levels=ONE:TWO:THREE,如:leves=1:2:2。
keys_zone=name:size:指定映射的内存空间的名称及大小
inactive=time:指定缓存文件如果在指定的时间内都没有被访问,则文件会被cache manager进程删除掉。
max_size=size:指定此缓存空间的大小上限。

示例:

fastcgi_cache_path /data/nginx/cache levels=1:2 keys_zone=one:10m;
  • 5、fastcgi_cache zone | off;
    配置段: http, server, location
    调用使用fastcgi_cache_path指定设置的缓存空间来缓存数据。
    示例:
fastcgi_cache one;
  • 6、fastcgi_cache_key string;
    配置段: http, server, location
    定义缓存的key字符串。

  • 7、fastcgi_cache_methods GET | HEAD | POST ...;
    配置段:http, server, location
    设置哪些请求方法能够使用fastcgi缓存。

  • 8、fastcgi_cache_min_uses number;
    配置段:http, server, location
    缓存空间中的缓存项在inactive定义的非活动时间内至少要被访问到此处所指定的次数方可被认作活动项;

  • 9、fastcgi_cache_valid [code ...] time;
    配置段: http, server, location
    根据不同的页面响应码设置不同的缓存时间。
    示例:

location ~* \.php$ {
    ...
    fastcgi_cache fcgi;
    fastcgi_cache_key $request_uri;
    fastcgi_cache_valid 200 302 10m;  #状态码为200和302的页面内容缓存10分钟
    fastcgi_cache_valid 301 1h;
    fastcgi_cache_valid any 1m; 
    ...
}
  • 10、fastcgi_keep_conn on | off;
    配置段:http, server, location
    用于开启fastcgi长连接机制。
综合示例
server {
        listen 80;
        server_name www.ilinux.io;
        index index.php index.html;
        location / {
                root /data/nginx/html;
                proxy_pass http://10.10.10.12:80; 
        }
        location ~* \.php$ {
                fastcgi_pass 10.10.10.11:9000;  #指定fastcgi服务器
                fastcgi_index index.php;  #指定默认的fastcgi主页
                include fastcgi_params;  #调用nginx的变量定义
                fastcgi_param   SCRIPT_FILENAME /data/apps/$fastcgi_script_name;  #指定fastcgi服务器上的php目录
                fastcgi_cache   fcache;  #调用fache缓存空间
                fastcgi_cache_key $request_uri;  #设置缓存的key为$request_uri
                fastcgi_cache_valid 200 302 10m;  #状态码为200和302的页面缓存10分钟
                fastcgi_cache_valid 301         1h;  #状态码为301的页面缓存1小时
                fastcgi_cache_valid any         1m;  #剩下的都缓存1分钟
                fastcgi_keep_conn on;  #开启长连接
        }
        location ~* ^/(status|ping)$ {
                fastcgi_pass 10.10.10.11:9000;
                include fastcgi_params;
                fastcgi_param   SCRIPT_FILENAME /data/apps/$fastcgi_script_name;
        }
}
ngx_http_upstream_conf_module模块

此模块用于定义能够被proxy_pass, fastcgi_pass, uwsgi_pass, scgi_pass和memcached_pass配置段所引用的服务器组。

  • 1、upstream name { ... }
    配置段:http
    此指令为一个上下文配置段,用于定义能后端服务器组,此服务器组能够被proxy_pass, fastcgi_pass, uwsgi_pass, scgi_pass和memcached_pass所调用。
    示例:
upstream httpdsrvs {
    server 10.10.10.11:80;
    server  10.10.10.12:80;
    ...
}
  • 2、server address [parameters];
    配置段: upstream
    此指定用于在上下文中定义后端服务器成员以及相关的参数。
    其中address的表示格式为可使用下列三种格式:

unix:/PATH/TO/SOME_SOCK_FILE
IP[:PORT]
HOSTNAME[:PORT]

parameters参数包括:

weight=number
    权重,默认为1;
max_fails=number
    失败尝试最大次数;超出此处指定的次数时,server将被标记为不可用,默认为1;
fail_timeout=time
    设置将服务器标记为不可用状态的超时时长;
max_conns=number
    当前的服务器的最大并发连接数;
backup
    将服务器标记为“备用”,即所有服务器均不可用时此服务器才启用;
down
    标记为“不可用”;
  • 3、least_conn;
    配置段: upstream
    在指定的服务器组中启动最少连接调度算法,请求被发送到激活连接数最少的服务器,当设置了权重时,相当于WLC加权最少连接调度算法;默认nginx负载均衡的调度算法为轮询。
    示例:
upstream backend {  
    least_conn;  
  
    server backend1.example.com;  
    server backend2.example.com;  
}  
  • 4、ip_hash;
    配置段: upstream
    在指定的服务器组中使用源地址hash调度方法;来自同一个IP地址的请求统一被分配到同一个server响应,相当于lvs的sh调度算法。
  • 5、hash key [consistent];
    配置段:upstream
    基于指定的key的hash表来实现对请求的调度,此处的key可以直接文本、变量或二者的组合;能够将请求分类,同一类请求将发往同一个后端服务器 。
    示例:
hash $request_uri consistent;
hash $remote_addr;
  • 6、keepalive connections;
    配置段:upstream
    设置为每个nginx worker进程保留的空闲的长连接数量。
    示例1:
upstream http_backend {
    server 127.0.0.1:8080;

    keepalive 16;
}

示例2:

#对于fastcgi服务器来说,keepalive要结合fastcgi_keep_conn指令一起使用才能生效
upstream fastcgi_backend {
    server 127.0.0.1:9000;

    keepalive 8;
}

server {
    ...

    location /fastcgi/ {
        fastcgi_pass fastcgi_backend;
        fastcgi_keep_conn on;
        ...
    }
}
upsteam模块的综合示例:
##在/etc/nginx/nginx.conf文件中配置:
    upstream websrvs {
            ip_hash;
            server 10.10.10.11:80 weight=2 down;
            server 10.10.10.12:80 weight=1 fail_timeout=1 max_fails=3;
            server 127.0.0.1:80 backup;
        }

#在server配置段:
server {
        listen 80;
        server_name www.ilinux.io;
        location / {
                root /data/nginx/html;
                proxy_pass http://websrvs;
        }
}
ngx_stream_core_module

此模块用于模拟反代基于tcp或udp的服务连接,即工作于四层传输层的反代或调度器。

  • 1、stream { ... }
    配置段:main
    用于定义与stream的相关服务。
    示例:
#可在一个stream中配置upstream服务器组和server配置段
stream {
    upstream sshsrvs {
        server 192.168.22.2:22; 
        server 192.168.22.3:22; 
        least_conn;
    }
    server {
        listen 10.1.0.6:22022;
        proxy_pass sshsrvs;
    }
}

其他的指令与其他模块所使用的指令类似。

详细的指令使用可参考链接:http://nginx.org/en/docs/stream/ngx_stream_core_module.html#proxy_protocol_timeout

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

推荐阅读更多精彩内容