Systemd 日常使用介绍

tl;dr
应用场景:对日常系统启动过程进行管理,优化启动速度。


1. systemd原理

Systemd概述
systemd系统架构图

1.1 基础概念-Unit

Systemd将系统初始化过程中所有的操作步骤都被抽象为Unit 对应于之前SysVinit时代的Daemon的超集 ,根据不同的操作内容,Unit被细分为多个分类:

  • service :类似于SysVinit时代的Daemon,代表一个后台服务进程,比如 mysqld。这是最常用的一类。
  • target :Unit组。此类配置单元为其他配置单元进行逻辑分组。它们本身实际上并不做什么,只是引用其他配置单元而已。这样便可以对配置单元做一个统一的控制。这样就可以实现大家都已经非常熟悉的运行级别概念。比如想让系统进入图形化模式,需要运行许多服务和配置命令,这些操作都由一个个的配置单元表示,将所有这些配置单元组合为一个目标(target),就表示需要将这些配置单元全部执行一遍以便进入目标所代表的系统运行状态。 (例如:multi-user.target 相当于在传统使用 SysV 的系统中运行级别 5)
  • 其他Unit
  • timer:定时器配置单元用来定时触发用户定义的操作,这类配置单元取代了 atd、crond 等传统的定时服务。
  • snapshot :与 target 配置单元相似,快照是一组配置单元。它保存了系统当前的运行状态。
  • socket :此类配置单元封装系统和互联网中的一个 套接字 。当下,systemd 支持流式、数据报和连续包的 AF_INET、AF_INET6、AF_UNIX socket 。每一个套接字配置单元都有一个相应的服务配置单元 。相应的服务在第一个"连接"进入套接字时就会启动(例如:nscd.socket 在有新连接后便启动 nscd.service)。
  • device :此类配置单元封装一个存在于 Linux 设备树中的设备。每一个使用 udev 规则标记的设备都将会在 systemd 中作为一个设备配置单元出现。
  • mount :此类配置单元封装文件系统结构层次中的一个挂载点。Systemd 将对这个挂载点进行监控和管理。比如可以在启动时自动将其挂载;可以在某些条件下自动卸载。Systemd 会将/etc/fstab 中的条目都转换为挂载点,并在开机时处理。
  • automount :此类配置单元封装系统结构层次中的一个自挂载点。每一个自挂载配置单元对应一个挂载配置单元 ,当该自动挂载点被访问时,systemd 执行挂载点中定义的挂载行为。
  • swap: 和挂载配置单元类似,交换配置单元用来管理交换分区。用户可以用交换配置单元来定义系统中的交换分区,可以让这些交换分区在启动时被激活。

Unit落地到实体就是Unit配置文件,文件名后缀就是该Unit的类型名字。

1.2 相关目录和文件

  • /etc/systemd/ 开机启动的unit配置文件们,一般都是符号连接到/lib/systemd/
  • /lib/systemd/ 所有的unit配置文件们

1.3 Systemd做了那些牛逼的事情

  1. 提高并发启动能力,加快了系统启动时间


    SysVinit -> UpStart

    Systemd
  2. 按需启动服务

Systemd 可以提供按需启动的能力,只有在某个服务被真正请求的时候才启动它。当该服务结束,systemd 可以关闭它,等待下次需要时再次启动它。

  1. System解决Unit依赖和事物处理

每个Unit的配置文件都会指定其运行所需的依赖关系(Unit配置文件中[Unit]字段描述),依赖关系有两种:

  • Requires 强依赖,依赖的Unit如果不能正常启动,则配置的这个Unit也启动失败
  • Wants 弱依赖,依赖的Unit如果不能正常启动,则不影响这个Unit的启动
    Unit一旦形成循环依赖,systemd 将尝试去掉 wants 关键字指定的依赖看看是否能打破循环。如果无法修复,systemd 会报错:


    Unit循环依赖

Unit配置文件强弱依赖示例:

$ systemctl cat sshd.service
[Unit]
Before=a.service  指定启动顺序,在之前启动
After=network.target sshd-keygen.service  指定启动顺序,在之后启动
Wants=sshd-keygen.service  指定弱依赖关系
Requires=bb.service  指定强依赖关系

Unit配置文件所在的同目录下,有可能会有同名的.wants子目录,该子目录下的文件等同于Unit配置文件的Wants字段,指定弱依赖关系需要的Unit:

ray@ray-ThinkPad-X250:/lib/systemd/system$ ls -al | grep .wants -C 2
-rw-r--r--  1 root root   879 Oct  2 16:33 basic.target
drwxr-xr-x  2 root root  4096 Oct 14 23:09 basic.target.wants
-rw-r--r--  1 root root   358 Oct  2 16:33 busnames.target
drwxr-xr-x  2 root root  4096 Oct 14 23:05 busnames.target.wants
-rw-r--r--  1 root root   585 Oct  2 16:33 system-update.target
drwxr-xr-x  2 root root  4096 Oct 14 23:13 system-update.target.wants
-rw-r--r--  1 root root   405 Oct  2 16:33 timers.target
drwxr-xr-x  2 root root  4096 Oct 14 23:05 timers.target.wants

2. Systemd的日常使用

2.1 systemd的使用效果

ray@ray-ThinkPad-X250:/etc/systemd$ ps -ef | head
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 Oct17 ?        00:00:02 /sbin/init splash
root         2     0  0 Oct17 ?        00:00:00 [kthreadd]
root         3     2  0 Oct17 ?        00:00:00 [ksoftirqd/0]
root         5     2  0 Oct17 ?        00:00:00 [kworker/0:0H]
root         7     2  0 Oct17 ?        00:00:08 [rcu_sched]
root         8     2  0 Oct17 ?        00:00:00 [rcu_bh]
root         9     2  0 Oct17 ?        00:00:00 [migration/0]
root        10     2  0 Oct17 ?        00:00:00 [lru-add-drain]
root        11     2  0 Oct17 ?        00:00:00 [watchdog/0]
ray@ray-ThinkPad-X250:/etc/systemd$ ls -al /sbin/init
lrwxrwxrwx 1 root root 20 Oct  2 16:33 /sbin/init -> /lib/systemd/systemd
ray@ray-ThinkPad-X250:/etc/systemd$ 

2.2 systemctl 命令

1. 查看指定Unit状态

鳥哥的 Linux 私房菜

Unit开机启动状态(对应Loaded行)

  • enabled:开机启动
  • disabled:开机不启动
  • static:静态被动服务,不能被设置为enable和disable,只能被其他enabled的服务调用
  • mask:隐藏状态,不能被启动(开机自动、人工操作)。可透過 systemctl unmask 命令将其回复正常状态

Unit当前运行状态(对应Active行)

  • active (running):Unit正在运行。
  • active (exited):Unit运行一次,且正常结束。如Bash脚本,无需常驻内存的Unit。
  • active (waiting):Unit正在运行,且正在等候其他事物的交互。如打印机。
  • inactive:Unit没有在运行。

disabled状态和mask状态区别

disabled示例:


Paste_Image.png

mask示例:


Paste_Image.png

Paste_Image.png

2. 查看所有Unit状态

  • systemctl list-units [--type=TYPE] [--all] 列出所有加载的Unit
ray@ray-ThinkPad-X250:~$ systemctl list-units | head
UNIT                                                                                      LOAD   ACTIVE SUB       DESCRIPTION
proc-sys-fs-binfmt_misc.automount                                                         loaded active running   Arbitrary Executable File Formats File System Automount Point
sys-devices-pci0000:00-0000:00:02.0-drm-card0-card0\x2deDP\x2d1-intel_backlight.device    loaded active plugged   /sys/devices/pci0000:00/0000:00:02.0/drm/card0/card0-eDP-1/intel_backlight
sys-devices-pci0000:00-0000:00:03.0-sound-card0.device                                    loaded active plugged   Broadwell-U Audio Controller
sys-devices-pci0000:00-0000:00:14.0-usb2-2\x2d7-2\x2d7:1.0-bluetooth-hci0.device          loaded active plugged   /sys/devices/pci0000:00/0000:00:14.0/usb2/2-7/2-7:1.0/bluetooth/hci0
sys-devices-pci0000:00-0000:00:19.0-net-enp0s25.device                                    loaded active plugged   Ethernet Connection (3) I218-LM
sys-devices-pci0000:00-0000:00:1b.0-sound-card1.device                                    loaded active plugged   Wildcat Point-LP High Definition Audio Controller
sys-devices-pci0000:00-0000:00:1c.1-0000:03:00.0-net-wlp3s0.device                        loaded active plugged   Wireless 7265 (Wireless-N 7265)
sys-devices-pci0000:00-0000:00:1f.2-ata1-host0-target0:0:0-0:0:0:0-block-sda-sda1.device  loaded active plugged   SanDisk_SDSSDXPS480G 1
sys-devices-pci0000:00-0000:00:1f.2-ata1-host0-target0:0:0-0:0:0:0-block-sda-sda2.device  loaded active plugged   SanDisk_SDSSDXPS480G 2
ray@ray-ThinkPad-X250:~$ 
  • systemctl list-unit-files [--type=TYPE] 列出所有安装的Unit
ray@ray-ThinkPad-X250:~$ systemctl list-unit-files | head
UNIT FILE                                  STATE    
proc-sys-fs-binfmt_misc.automount          static   
-.mount                                    generated
boot.mount                                 generated
dev-hugepages.mount                        static   
dev-mqueue.mount                           static   
proc-sys-fs-binfmt_misc.mount              static   
snap-ubuntu\x2dcore-216.mount              enabled  
snap-ubuntu\x2dcore-352.mount              enabled  
snap-ubuntu\x2dcore-423.mount              enabled  
ray@ray-ThinkPad-X250:~$ 
ray@ray-ThinkPad-X250:~$ systemctl list-unit-files --type=socket
UNIT FILE                       STATE   
acpid.socket                    enabled 
apport-forward.socket           enabled 
avahi-daemon.socket             enabled 
cups.socket                     enabled 
dbus.socket                     static  
dm-event.socket                 enabled 
lvm2-lvmetad.socket             enabled 
lvm2-lvmpolld.socket            enabled 
saned.socket                    disabled
snapd.socket                    enabled 
syslog.socket                   static  
systemd-fsckd.socket            static  
systemd-initctl.socket          static  
systemd-journald-audit.socket   static  
systemd-journald-dev-log.socket static  
systemd-journald.socket         static  
systemd-networkd.socket         disabled
systemd-rfkill.socket           static  
systemd-udevd-control.socket    static  
systemd-udevd-kernel.socket     static  
uuidd.socket                    enabled 
21 unit files listed.
ray@ray-ThinkPad-X250:~$ 

3. 查看target(Unit组)的状态及切换

systemd将多个Unit归类到target,以方便实现批量的操作。
在启动阶段的target对应于SysVinit里的init 1/2/3/5等模式下的一些列操作。
查看启动的target:

ray@ray-ThinkPad-X250:~$ systemctl list-units --type=target
UNIT                   LOAD   ACTIVE SUB    DESCRIPTION
basic.target           loaded active active Basic System
cryptsetup.target      loaded active active Encrypted Volumes
getty.target           loaded active active Login Prompts
graphical.target       loaded active active Graphical Interface
local-fs-pre.target    loaded active active Local File Systems (Pre)
local-fs.target        loaded active active Local File Systems
multi-user.target      loaded active active Multi-User System
network.target         loaded active active Network
nss-user-lookup.target loaded active active User and Group Name Lookups
paths.target           loaded active active Paths
remote-fs.target       loaded active active Remote File Systems
slices.target          loaded active active Slices
sockets.target         loaded active active Sockets
sound.target           loaded active active Sound Card
swap.target            loaded active active Swap
sysinit.target         loaded active active System Initialization
time-sync.target       loaded active active System Time Synchronized
timers.target          loaded active active Timers

LOAD   = Reflects whether the unit definition was properly loaded.
ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
SUB    = The low-level unit activation state, values depend on unit type.

18 loaded units listed. Pass --all to see loaded but inactive units, too.
To show all installed unit files use 'systemctl list-unit-files'.
ray@ray-ThinkPad-X250:~$ 

target为了实现与SysVinit的兼容,建立了一些runlevel的target,与init对应:

ray@ray-ThinkPad-X250:~$ ll -d /lib/systemd/system/runlevel*.target
lrwxrwxrwx 1 root root 15 Oct  2 16:33 /lib/systemd/system/runlevel0.target -> poweroff.target
lrwxrwxrwx 1 root root 13 Oct  2 16:33 /lib/systemd/system/runlevel1.target -> rescue.target
lrwxrwxrwx 1 root root 17 Oct  2 16:33 /lib/systemd/system/runlevel2.target -> multi-user.target
lrwxrwxrwx 1 root root 17 Oct  2 16:33 /lib/systemd/system/runlevel3.target -> multi-user.target
lrwxrwxrwx 1 root root 17 Oct  2 16:33 /lib/systemd/system/runlevel4.target -> multi-user.target
lrwxrwxrwx 1 root root 16 Oct  2 16:33 /lib/systemd/system/runlevel5.target -> graphical.target
lrwxrwxrwx 1 root root 13 Oct  2 16:33 /lib/systemd/system/runlevel6.target -> reboot.target
ray@ray-ThinkPad-X250:~$ 

切换target:

systemctl isolate multi-user.target
systemctl isolate graphical.target

获取、设置默认的target

ray@ray-ThinkPad-X250:~$ systemctl get-default 
graphical.target
ray@ray-ThinkPad-X250:~$ systemctl set-default multi-user.target

4. 查看Unit依赖关系

systemctl list-dependencies [unit] [--reverse]

ray@ray-ThinkPad-X250:~$ systemctl get-default 
graphical.target
ray@ray-ThinkPad-X250:~$ 
ray@ray-ThinkPad-X250:~$ systemctl list-dependencies 
default.target
● ├─accounts-daemon.service
● ├─apport.service
● ├─grub-common.service
● ├─irqbalance.service
● ├─lightdm.service
● ├─speech-dispatcher.service
● ├─systemd-update-utmp-runlevel.service
● ├─ureadahead.service
● └─multi-user.target
●   ├─anacron.service
●   ├─apport.service
●   ├─avahi-daemon.service
ray@ray-ThinkPad-X250:~$ systemctl list-dependencies multi-user.target 
multi-user.target
● ├─anacron.service
● ├─apport.service
● ├─avahi-daemon.service
● ├─binfmt-support.service
● ├─cgmanager.service
● ├─cgproxy.service
● ├─click-system-hooks.service
● ├─cron.service
● ├─cups-browsed.service
ray@ray-ThinkPad-X250:~$ systemctl list-dependencies multi-user.target --reverse 
multi-user.target
● ├─failsafe-graphical.target
● └─graphical.target
ray@ray-ThinkPad-X250:~$ 

2.3 systemd-analyze命令

systemd-analyze 启动时间汇总信息
systemd-analyze blame 启动时间列表信息
systemd-analyze critical-chain 启动时间列表信息(以依赖方式组织)
systemd-analyze critical-chain atd.service

ray@ray-ThinkPad-X250:~$ systemd-analyze
Startup finished in 5.189s (kernel) + 7.155s (userspace) = 12.344s
ray@ray-ThinkPad-X250:~$ systemd-analyze blame 
          5.153s nmbd.service
          3.725s snapd.refresh.service
          1.014s apt-daily.service
           798ms dev-mapper-ubuntu\x2d\x2dvg\x2droot.device
           644ms user@1000.service
           630ms click-system-hooks.service
           477ms lightdm.service
           474ms networking.service
           459ms plymouth-quit-wait.service
           318ms snapd.firstboot.service
           304ms lvm2-monitor.service
           267ms systemd-udev-trigger.service
           248ms dev-loop1.device
           245ms dev-loop0.device
           233ms vboxdrv.service
           228ms dev-loop2.device
           205ms apparmor.service
           187ms systemd-resolved.service
           152ms winbind.service
           135ms keyboard-setup.service
           132ms systemd-timesyncd.service
           130ms irqbalance.service
           116ms systemd-tmpfiles-setup.service
           110ms binfmt-support.service
           108ms thermald.service
           107ms speech-dispatcher.service
           105ms systemd-logind.service
            97ms apport.service
            94ms smbd.service
            82ms grub-common.service
ray@ray-ThinkPad-X250:~$ systemd-analyze critical-chain 
The time after the unit is active or started is printed after the "@" character.
The time the unit takes to start is printed after the "+" character.

graphical.target @7.121s
└─multi-user.target @7.121s
  └─nmbd.service @1.967s +5.153s
    └─network.target @1.949s
      └─wpa_supplicant.service @2.650s +10ms
        └─basic.target @1.477s
          └─sockets.target @1.476s
            └─snapd.socket @1.449s +26ms
              └─sysinit.target @1.448s
                └─apparmor.service @1.243s +205ms
                  └─local-fs.target @1.178s
                    └─boot.mount @1.166s +11ms
                      └─systemd-fsck@dev-disk-by\x2duuid-256c30d5\x2d2af9\x2d41c
                        └─dev-disk-by\x2duuid-256c30d5\x2d2af9\x2d41ca\x2d971d\x

2.4 systemd中其他好用的命令集

ray@ray-ThinkPad-X250:~$ hostnamectl

   Static hostname: ray-ThinkPad-X250
         Icon name: computer-laptop
           Chassis: laptop
        Machine ID: 0f17fde0902045bcbe0695d043c66c95
           Boot ID: f0058c222353453f84a33e925e145263
  Operating System: Ubuntu 16.10
            Kernel: Linux 4.8.0-25-generic
      Architecture: x86-64
ray@ray-ThinkPad-X250:~$ 
ray@ray-ThinkPad-X250:~$ 
ray@ray-ThinkPad-X250:~$ hostnamectl
   Static hostname: ray-ThinkPad-X250
         Icon name: computer-laptop
           Chassis: laptop
        Machine ID: 0f17fde0902045bcbe0695d043c66c95
           Boot ID: f0058c222353453f84a33e925e145263
  Operating System: Ubuntu 16.10
            Kernel: Linux 4.8.0-25-generic
      Architecture: x86-64
ray@ray-ThinkPad-X250:~$ 
ray@ray-ThinkPad-X250:~$ localectl
   System Locale: LANG=en_US.UTF-8
                  LC_NUMERIC=zh_CN.UTF-8
                  LC_TIME=zh_CN.UTF-8
                  LC_MONETARY=zh_CN.UTF-8
                  LC_PAPER=zh_CN.UTF-8
                  LC_NAME=zh_CN.UTF-8
                  LC_ADDRESS=zh_CN.UTF-8
                  LC_TELEPHONE=zh_CN.UTF-8
                  LC_MEASUREMENT=zh_CN.UTF-8
                  LC_IDENTIFICATION=zh_CN.UTF-8
       VC Keymap: us
      X11 Layout: us
       X11 Model: pc105
ray@ray-ThinkPad-X250:~$ 
ray@ray-ThinkPad-X250:~$ timedatectl
      Local time: Tue 2016-10-18 15:51:42 CST
  Universal time: Tue 2016-10-18 07:51:42 UTC
        RTC time: Tue 2016-10-18 07:51:42
       Time zone: Asia/Shanghai (CST, +0800)
 Network time on: yes
NTP synchronized: yes
 RTC in local TZ: no
ray@ray-ThinkPad-X250:~$ 
ray@ray-ThinkPad-X250:~$ loginctl
   SESSION        UID USER             SEAT            
        c2       1000 ray              seat0           

1 sessions listed.
ray@ray-ThinkPad-X250:~$ 
ray@ray-ThinkPad-X250:~$ 
ray@ray-ThinkPad-X250:~$ loginctl list-sessions 
   SESSION        UID USER             SEAT            
        c2       1000 ray              seat0           

1 sessions listed.
ray@ray-ThinkPad-X250:~$ 
ray@ray-ThinkPad-X250:~$ loginctl list-users 
       UID USER            
      1000 ray             

1 users listed.
ray@ray-ThinkPad-X250:~$ 
ray@ray-ThinkPad-X250:~$ who
ray      tty7         2016-10-17 21:19 (:0)
ray@ray-ThinkPad-X250:~$ 
ray@ray-ThinkPad-X250:~$ who -a
           system boot  2016-10-17 21:19
LOGIN      tty1         2016-10-17 21:19              1272 id=tty1
           run-level 5  2016-10-17 21:19
ray      + tty7         2016-10-17 21:19 18:32        2017 (:0)
ray@ray-ThinkPad-X250:~$ 
ray@ray-ThinkPad-X250:~$ 

2.5 Systemd和SysVinit对应关系表

Systemd和SysVinit对应关系表

参考URL

systemd 官方wiki
SysVinit to Systemd Cheatsheet
IBM 浅析 Linux 初始化 init 系统,第 3 部分: Systemd

The Self-Explanatory Boot
鳥哥的 Linux 私房菜 第十七章、認識系統服務 (daemons)
鳥哥的 Linux 私房菜 第十九章、開機流程、模組管理與 Loader
Linux 守护进程的启动方法
Systemd 入门教程:命令篇
Systemd 入门教程:实战篇
理解Systemd单元和单元文件
systemd详解

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

推荐阅读更多精彩内容