20171116 Redis

  • NoSQL
  • Redis基础
  • Redis配置文件基础
  • Redis的持久化
  • Redis的复制
  • Redis的集群

一、NoSQL

(一)基本概念

  • NoSQL:Not Only SQL,非关系型、分布式、开源、水平可扩展的数据库
  • 特性:数据量大、数据变化非常快(数据增长快、流量分布变化大、数据间耦合结构变化快)、数据源很多

(二)设计原则

(1)CAP理论:
  • 一个分布式系统不可能同时满足C、A、P三个特性,最多可同时满足其中两者;对于分布式系统满足分区容错性几乎是必须的
  • C:Consistency,多个数据节点上的数据一致
  • A:Availablity,用户发出请求后的有限时间范围内返回结果
  • P:Partition tolerence,网络发生分区后(network partition),服务是否依然可用
(2)BASE:BA,S,E,基于CAP演化而来
  • BA:Basically Available,基本可用
  • S:Soft state,软状态/柔性事务,即状态可以在一个时间窗口内是不同步的
  • E:Eventually consistency,最终一致性

(三)分类和主流产品

  • Key Value / Tuple Store:键值存储,DynamoDB, redis
  • Wide Column Store / Column Families:列式数据库,hbase
  • Document Store:文档数据库,mongodb, Elastic
  • Graph Databases:图式数据库,Neo4j
  • Time Series / Streaming Databases:时间序列存储

二、Redis基础

(一)简介:

  • 开源、内存存储、数据结构存储
  • 可用作:数据库、缓存、消息队列
  • 数据结构:字符串、列表(数组)、hashes(关联数组)、集合、有序集合、bitmaps、hyperloglogs、空间索引

(二)程序环境:

  • 配置文件:/etc/redis.conf
  • 主程序:/usr/bin/redis-server
  • 端口:6379/tcp
  • 客户端:/usr/bin/redis-cli
  • Unit File:/usr/lib/systemd/system/redis.service
  • 数据目录:/var/lib/redis

(三)客户端的基本操作

(1)K/V 数据结构
  • key:直接ASCII字符串;
  • value:strings, lists, hashes, sets, sorted sets, bitmaps, hyperloglogs
(2)radis-cli工具的使用
  • 交互式界面:直接输入radis-cli进入

  • 帮助:输入HELP,按Tab键切换value类型

  • 数据库:只有0-15共16个数据库,使用SELECT #命令切换,默认为0数据库

  • @string
    SET:新增一条键值对
    GET:查看键对应的值
    EXISTS
    INCR:整数值自增1
    DECR:整数值自减1
    SETNX:只在没有此键时添加键值对
    SETEX:添加一条键值对并设定过期时间
    INCRBYFLOAT:按给定数值增加整数值
    MGET:查看多个键对应的值
    MSET:新增多条键值对

SET:新增,GET:查询,APPEND:添加,STRLEN:长度

SETNX:不存在时新增,INCR:自增1,INCRBY count 2:自增2,DEL:删除

  • @list:数组
    LPUSH:从左侧新增键值对
    RPUSH:从右侧新增键值对
    LPOP:从左侧移除键值对
    RPOP:从右侧移除键值对
    LPUSHX:仅当list存在时,从左侧新增键值对
    RPUSHX:仅当list存在时,从右侧新增键值对
    LRANGE:查看某个范围
    LINDEX:通过索引查看
    LSET:通过list的索引修改元素的值

LPUSH:从左侧添加,LINDEX weekdays 0:查看索引为0的元素值

LRANGE weekdays 0 4:查看索引0至4的元素值
LINSERT weekdays AFTER Tue Wed:在元素后Tue插入Wed

LPOP:左侧移除,RPOP:右侧移除,LLEN:list的长度

  • @set:集合
    SADD:集合中添加成员
    SPOP:从集合中随机删除成员
    SREM :从集合中删除成员
    SRANDMEMBER:随机查看集合中的成员
    SINTER:做交集
    SUNION:做并集

SADD:添加成员,SMEMBERS:查看成员

SINTER:查看交集结果,SUNION:查看并集结果

SREM:删除指定成员,SPOP:随机删除成员

  • @sorted_set:有序集合
    ZADD:从集合中添加成员,若存在则为更新成员的值
    ZCARD:查看有序集合成员数
    ZCOUNT:按照所赋予的值,输出指定排序范围的成员数
    ZRANK:按照所赋予的值,输出指定排序范围的成员

ZADD:添加有序集合的成员,ZSCORE:查看成员所赋予的值

ZRANK:查看指定成员的排序,ZRANGE:查看指定排序范围的成员,ZRANGEBYSCORE:查看指定排序范围的成员

  • @hash:关联数组
    HSET:新增包含一个键值对的关联数组
    HMSET:新增包含多个键值对的关联数组
    HGET:查看关联数组的一个键值对
    HMGET:查看关联数组的多个键值对
    HKEYS:查看关联数组的所有键
    HVALS:查看关联数组的所有值
    HDEL:删除关联数组的键值对
    HGETALL:查看关联数组的所有键和对应的值

HMSET:在一个hash中创建多个键值对,HKEYS:查看键,HVALS:查看键对应的值

HGETALL:查看hash的所有键值对,HDEL:删除键值对

  • @pubsub
    PUBLISH:向频道扇出一条信息
    SUBSCRIBE:订阅指定频道
    UNSUBSCRIBE:退订指定频道
    PSUBSCRIBE:按pattern规则订阅频道
    PUNSUBSCRIBE:按pattern规则退订频道

PUBLISH:扇出信息

SUBSCRIBE:订阅并接受信息

  • @geo:空间索引

  • @server
    Server相关的命令:
    CLIENT GETNAME:查询当前连接名称
    CLIENT KILL:杀死客户端的连接
    CLIENT KILL [ip:port] [ID client-id] [TYPE normal|master|slave|pubsub] [ADDR ip:port] [SKIPME yes/no]
    CLIENT LIST:列出客户端连接
    CLIENT PAUSE:暂停执行客户端指令一段时间
    CLIENT PAUSE timeout
    CLIENT REPLY:告诉服务器是否回应指令
    CLIENT SETNAME:设置当前连接名称
    SHUTDOWN [NOSAVE|SAVE]:关闭服务器
    CONFIG GET:查看配置参数
    CONFIG RESETSTAT:重置配置参数
    CONFIG REWRITE:将配置写入配置文件,实现运行时永久修改
    CONFIG SET:设置配置参

    INFO:INFO [section],服务器状态信息查看,可分为多个secion查看
    FLUSHDB:清空当前数据库
    FLUSHALL:清空所有数据库

CONFIG SET:实时修改配置

CONFIG REWRITE:配置文件中自动生成相应配置信息

INFO:服务器状态信息

三、Redis配置文件基础

  • 配置文件分为如下章节:
    INCLUDES:包含其他配置文件的路径
    NETWORK:网络配置项
    GENERAL:基本配置项
    SNAPSHOTTING:快照持久化相关配置
    REPLICATION:复制相关配置
    SECURITY:安全相关配置
    LIMITS:限制相关的配置
    SLOW LOG:慢日志相关的配置
    ADVANCED CONFIG:高级配置

  • 通用配置项:
    daemonize on
    supervised no
    loglevel notice:日志级别
    pidfile /var/run/redis/redis.pid:pid文件路径
    logfile /var/log/redis/redis.log:日志文件路径
    databases:设定数据库数量,默认为16个,每个数据库的名字均为整数,从0开始编号,默认操作的数据库为0

  • 网络配置项:
    bind IP:绑定IP
    port PORT:监听端口
    protected-mode yes:安全模式
    tcp-backlog 511:后援队列长度
    unixsocket:socket文件路径
    timeout:连接的空闲超时时长

  • 安全配置:
    requirepass <PASSWORD>
    rename-command <COMMAND> <NEW_CMND_NAME>:修改命令名称
    在AOF或Replication环境中,不推荐使用

设置密码后,在redis-cli中使用AUTH password命令验证密码

  • Limits相关的配置:
    maxclients 10000:并发客户端连接数
    maxmemory <bytes>:最大内存使用容量,超出时按照maxmemory-policy设置的策略删除键值
    maxmemory-policy noeviction:淘汰策略

    volatile-lru:从接近过期时间的键值中采用LRU算法淘汰
    allkeys-lru:从所有键值中采用LRU算法淘汰
    volatile-random:从接近过期时间的键值中随机淘汰
    allkeys-random:从全部键值中随机淘汰
    volatile-ttl:从最接近过期时间的键值开始淘汰 
    noeviction:不删除键值,写操作直接报错
    

    maxmemory-samples 5: 淘汰算法运行时的采样样本数

  • SlowLog相关的配置:
    slowlog-log-slower-than 10000:超过多少时间被记录进慢查询日志,单位是微秒
    slowlog-max-len 128:慢查询日志最大条目

  • Advanced配置:
    hash-max-ziplist-entries 512:设置ziplist的键数量最大值
    hash-max-ziplist-value 64:每个值的最大空间
    client-output-buffer-limit normal 0 0 0:普通客户端输出缓冲限制
    client-output-buffer-limit slave 256mb 64mb 60:从服务器客户端输出缓冲限制
    client-output-buffer-limit pubsub 32mb 8mb 60:队列客户端输出缓冲限制
    三个值的说明:<hard-limit> <soft-limit> <soft-limit seconds>,一般情况不能超过<soft-limit>,任何情况绝对不能超过<hard-limit>,超过<soft-limit>的部分在<soft-limit seconds>的宽限期后将被删除

四、Redis的持久化

(一)持久化的两种方式

  • RDB:snapshotting,二进制格式
    按事先定制的策略,周期性地将数据从内存同步至磁盘
    数据文件默认为dump.rdb
    客户端显式使用SAVE或BGSAVE命令来手动启动快照保存机制
    SAVE:同步,即在主线程中保存快照,此时会阻塞所有客户端请求
    BGSAVE:异步,后台执行

  • AOF:Append Only File, fsync
    记录每次写操作至指定的文件尾部实现的持久化
    当redis重启时,可通过重新执行文件中的命令在内存中重建出数据库
    BGREWRITEAOF:AOF文件重写,后台执行
    不会读取正在使用AOF文件,而是通过将内存中的数据以命令的方式保存至临时文件中,完成之后替换原来的AOF文件

  • RDB模式效率更高,AOF模式时间精度更高

(二)RDB相关的配置:

  • save <seconds> <changes>

    save 900 1
    save 300 10
    save 60 10000
    

    表示:三个策略满足其中任意一个均会触发SNAPSHOTTING操作,即:
    900s内至少有一个key有变化
    300s内至少有10个key有变化
    60s内至少有1W个key发生变化

  • stop-writes-on-bgsave-error yes
    dump操作出现错误时,是否禁止新的写入操作请求,默认yes

  • rdbcompression yes:复制时是否支持压缩,默认yes

  • rdbchecksum yes:复制时是否检验完整性,默认yes

  • dbfilename dump.rdb:指定rdb文件名

  • dir /var/lib/redis:rdb文件的存储路径

(三)AOF相关的配置

  • appendonly no:是否打开AOF模式,默认no

  • appendfilename "appendonly.aof":指定rof文件名

  • appendfsync:AOF同步模式,支持三种模式
    no:不执行主动同步操作,而是OS进行
    everysec:每秒一次
    always:每语句一次

  • no-appendfsync-on-rewrite no
    是否在后台执行aof重写期间不调用fsync,默认为no,表示调用

  • auto-aof-rewrite-percentage 100

  • auto-aof-rewrite-min-size 64mb
    上述两个条件同时满足时,方会触发重写AOF,即
    与上次aof文件大小相比,其增长量超过100%,且大小不少于64MB

  • aof-load-truncated yes

(四)其他

  • 注意:持久机制本身不能取代备份;应该制订备份策略,对redis库定期备份;

  • RDB与AOF同时启用:
    BGSAVE和BGREWRITEAOF不会同时进行
    Redis服务器启动时用持久化的数据文件恢复数据,会优先使用AOF

五、Redis的复制

(一)特点:

  • 一个Master可以有多个Slave主机,支持链式复制
  • Master以非阻塞方式同步数据至Slave主机

(二)方法一:配置slave节点

  • redis-cli> SLAVEOF <MASTER_IP> <MASTER_PORT>:指明主节点的IP和端口
  • redis-cli> CONFIG SET masterauth <PASSWORD>:主节点密码认证

(三)方法二:配置参数

(1)必须配置的参数
  • slaveof
  • masterauth
(2)其他视情况配置的参数
  • slave-serve-stale-data yes:从节点是否使用过时的数据提供服务,默认yes

  • slave-read-only yes:从节点是否只读,默认yes

  • repl-diskless-sync no:是否使用无盘方式复制,由以下三种模式
    no, Disk-backed, Diskless

    • 新的从节点或某较长时间未能与主节点进行同步的从节点重新与主节点通信,需要做"full synchronization",此时其同步方式有两种style:
    • Disk-backend:主节点新创建快照文件于磁盘中,而后将其发送给从节点
    • Diskless:主节点新创建快照后直接通过网络套接字文件发送给从节点
  • repl-diskless-sync-delay 5
    当使用Diskless模式时,为了实现并行复制,通常需要在复制启动前延迟一个时间段,默认5s

  • repl-ping-slave-period 10:从节点向主节点发送ping的间隔,默认10s

  • repl-timeout 60:复制超时时间,默认60s

  • repl-disable-tcp-nodelay no:是否禁用tcp延迟发送,默认不禁用

  • repl-backlog-size 1mb:消息队列长度

  • slave-priority 100
    复制集群中,主节点故障时,sentinel应用场景中的主节点选举时使用的优先级
    数字越小优先级越高,但0表示不参与选举

  • min-slaves-to-write 3
    主节点仅允许其能够通信的从节点数量大于等于此处的值时接受写操作

  • min-slaves-max-lag 10
    从节点延迟时长超出此处指定的时长时,主节点会拒绝写入操作

(四)实验1:实现Redis的复制

  • 实验环境:
    主节点IP:192.168.136.230
    从节点1的IP:192.168.136.130
    从节点2的IP:192.168.136.131
(1)编辑主从节点的配置文件,修改监听IP,配置密码认证
vim /etc/redis.conf
bind 0.0.0.0
requirepass centos
(2)编辑从节点1的配置文件
slaveof 192.168.136.230 6379     // 指向主节点的IP和端口
masterauth centos                // 主节点的认证密码
(3)通过redis-cli命令配置从节点2的设置
redis-cli -h 192.168.136.131
192.168.136.131:6379> AUTH centos
192.168.136.131:6379> SLAVEOF 192.168.136.230 6379     // 指向主节点的IP和端口
192.168.136.131:6379> CONFIG SET masterauth centos     // 主节点的认证密码
192.168.136.131:6379> CONFIG GET masterauth
192.168.136.131:6379> CONFIG GET slave-read-only
192.168.136.131:6379> CONFIG REWRITE                   // 写入配置文件
(4)启动主次节点的服务,测试配置

主节点上查看连接的从节点:127.0.0.1:6379> CLIENT LIST

主节点查看Replication章节的信息,可以看到从节点的相关信息

从节点1查看Replication章节的信息,可以看到主节点IP和当前连接状态

从节点2查看Replication章节的信息,可以看到主节点IP和当前连接状态

主节点查看所有键

从节点1查看所有键,成功同步

从节点2查看所有键,成功同步

(五)sentinel

(1)sentinel简介
  • 主要完成三个功能:监控、通知、自动故障转移
  • 选举:流言协议(向网络内多台主机确认主节点是否宕机)、投票协议(少数服从多数)
(2)配置项
  • 配置文件:/etc/redis.conf

  • port 26379:默认监听端口,26379

  • sentinel monitor <master-name> <ip> <redis-port> <quorum>
    主节点IP和端口
    <quorum>:表示sentinel集群的quorum机制,即至少有quorum个sentinel节点同时判定主节点故障时,才认为其是真的故障
    s_down: subjectively down,主观宕机,单个sentinel服务器独自判定主节点是否宕机
    o_down: objectively down,客观宕机,多个sentinel服务器投票决定主节点是否宕机

  • sentinel auth-pass <master-name> <password> :主节点认证

  • sentinel down-after-milliseconds <master-name> <milliseconds>
    监控到指定的集群的主节点异常状态持续多久方才将标记为“故障”

  • sentinel parallel-syncs <master-name> <numslaves>
    指在failover过程中,能够被sentinel并行配置的从节点的数量;

  • sentinel failover-timeout <master-name> <milliseconds>
    sentinel必须在此指定的时长内完成故障转移操作,否则,将视为故障转移操作失败

  • sentinel notification-script <master-name> <script-path>
    通知脚本,此脚本被自动传递多个参数

(3)命令行选项

redis-cli -h SENTINEL_HOST -p SENTINEL_PORT
SENTINEL masters:查看主节点
SENTINEL slaves <MASTER_NAME>:查看指定主节点的从节点
SENTINEL failover <MASTER_NAME>
SENTINEL get-master-addr-by-name <MASTER_NAME>

(六)实验2:实现sentinel监控主机状态,当主节点发生故障时自动转移

  • 实验环境:
    继承实验1的主从节点环境,为减少实验系统开销,主节点、从节点1、从节点2共三台主机全部兼任sentinel服务器
    根据quorum机制,只有大于过半数的节点认定主节点宕机才会视作主机宕机,故quorum值为2
(1)编辑三台主机的sentinel配置文件
vim /etc/redis-sentinel.conf
bind 0.0.0.0
sentinel monitor mymaster 192.168.136.230 6379 2
sentinel auth-pass mymaster centos
sentinel down-after-milliseconds mymaster 30000
(2)启动redis-sentinel服务,并测试
systemctl start redis-sentinel
登录sentinel服务器
redis-cli -h 192.168.136.230 -p 26379
SENTINEL masters             // 查询主节点信息
SENTINEL slaves mymaster     // 查询从节点信息

SENTINEL masters,查询主节点信息,当前为192.168.136.230,符合预期

SENTINEL slaves mymaster,查询从节点信息,当前为192.168.136.130和192.168.136.131,符合预期

(3)关闭主节点的redis服务,造成宕机状况,测试故障转移功能
systemctl stop redis         // 192.168.136.230主机上操作
redis-cli -h 192.168.136.131 -p 26379
SENTINEL masters             // 查询主节点信息
SENTINEL slaves mymaster     // 查询从节点信息

192.168.136.130已经变为主节点

192.168.136.230已经降为从节点,由于宕机目前不可用

192.168.136.131仍旧保持从节点的身份

(4)修复主机192.168.136.230,并重新上线
vim /etc/redis.conf
slaveof 192.168.136.130 6379     // 设置为新的主节点IP
masterauth centos
systemctl start redis

成功上线

六、Redis的集群

(一)redis的集群技术:

Twitter:twemproxy,Twitter已经不再使用
豌豆荚:codis
原生:redis cluster

(二)redis cluster集群相关的配置:

  • cluster-enabled
    是否开启集群配置
  • cluster-config-file
    集群节点集群信息配置文件,每个节点都有一个,由redis生成和更新,配置时避免名称冲突
  • cluster-node-timeout
    集群节点互连超时的阈值,单位毫秒
  • cluster-slave-validity-factor
    进行故障转移时,salve会申请成为master。有时slave会和master失联很久导致数据较旧,这样的slave不应该成为master。这个配置用来判断slave是否和master失联时间过长。

(三)实验3:实现redis集群

  • 提示:注意关闭之前实验的sentinel服务,将主从节点的相关配置恢复,然后重启redis服务
(1)设置配置文件,启用集群功能
vim /etc/redia.conf     // 每个节点都要如此设置
cluster-enabled yes
cluster-config-file nodes-6379.conf
systemctl restart redis
(2)启动redis后为每个节点分配slots
systemctl restart redis
redis-cli -h 192.168.136.230 -a centos CLUSTER ADDSLOTS {0..5461}
redis-cli -h 192.168.136.130 -a centos CLUSTER ADDSLOTS {5462..10923}
redis-cli -h 192.168.136.131 -a centos CLUSTER ADDSLOTS {10924..16383}

注意:每个slot要独立创建;可用范围是0-16383,共16384个

使用CLUSTER INFO查看集群信息,可以看到已经分配相应数量的slot,但是集群状态还是fail

(3)设定集群成员关系
redis-cli -h 192.168.136.230 -a centos
CLUSTER MEET 192.168.136.130 6379
CLUSTER MEET 192.168.136.131 6379
CLUSTER INFO

再次使用CLUSTER INFO查看集群信息,集群状态已经ok状态

(4)测试集群功能
redis-cli -h 192.168.136.230 -a centos
192.168.136.230:6379> SET testkey1 hi
OK
192.168.136.230:6379> SET testkey2 hello
(error) MOVED 14758 192.168.136.131:6379
// 返回结果要求到192.168.136.131的节点执行操作
redis-cli -h 192.168.136.131 -a centos
192.168.136.131:6379> SET testkey2 hello
OK
192.168.136.131:6379> SET testkey3 sayhello
(error) MOVED 10631 192.168.136.130:6379

192.168.136.230成功存储testkey1键值对,但是节点要求去192.168.136.131存储testkey2键值对

192.168.136.131成功存储testkey2键值对,但是节点要求去192.168.136.130存储testkey3键值对

注意:当对redis cluster中的某个节点写数据时,可能会要求存储至其他节点。即可以向任意一个节点发起请求,节点可能会接收请求,也可能返回去其他节点完成操作的结果。故实际使用中,redis cluster需要与智能客户端协同发挥功能。

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

推荐阅读更多精彩内容

  • 1.1 资料 ,最好的入门小册子,可以先于一切文档之前看,免费。 作者Antirez的博客,Antirez维护的R...
    JefferyLcm阅读 17,034评论 1 51
  • 大小固定//自定义一个Cell @interfaceMMCell:UITableViewCell @end @im...
    陈世美_阅读 580评论 0 2
  • 写在前面的话: 学英语挺难的,但是如果找到别有意义的方法去记住词汇,那么就不会太难。本文受到了一档英文脱口秀节目的...
    姚石之言阅读 38,797评论 5 26
  • 今天是团日活动,我们护理省内班的春游。 昨晚想定七点起床的,但小黄说七点半起 我带着讽刺的心情同意了。我觉得七点半...
    木刻茉莉阅读 256评论 0 0
  • 从20多年前刚刚开始工作起,为了看海就天南地北地跑了很多地方。好几次冒着被上司责怪的后果。终于有一天,对自...
    入流亡所阅读 360评论 0 2