2.nacos服務(wù)配置中心

下面將研究以下幾個問題:

  1. nacos的角色: nacos是如何工作的? 在集群中扮演什么樣的角色?
  2. 修改nacos配置數(shù)據(jù)庫: 我們在控制臺配置的信息, 默認(rèn)是寫到nacos的默認(rèn)數(shù)據(jù)庫中, 不方便管理, 因此我們設(shè)置一個自己的數(shù)據(jù)庫, 進行管理操作
  3. 在控制臺配置nacos配置
  4. nacos配置管理的模型: 基本概念,namespace, group, data id及其用法
  5. 命名空間的管理, namespace的使用
  6. Nacos配置管理應(yīng)用于分布式系統(tǒng)
  7. 7.Nacos集群部署

一. nacos的角色
在這里插入圖片描述

這張圖說明了nacos是一個單獨的服務(wù)器, 用戶修改或者發(fā)布配置信息, 會通知下游的服務(wù)器. 下游的服務(wù)器也可以根據(jù)一定的規(guī)則讀取配置中心的配置信息.

讓nacos成為spring cloud集群的一部分

  1. 啟動nacos服務(wù)

  2. 將nacos納為spring cloud微服務(wù)的一部分

  3. 將spring cloud其他應(yīng)用服務(wù)注冊到nacos上.

二. 修改nacos配置數(shù)據(jù)庫

下面驗證服務(wù)的可用性

1. 啟動nacos

./startup.sh -m standalone

注意: 這里一定要單機模式啟動, 默認(rèn)是集群模式, 我們現(xiàn)在沒有在集群中, 會報異常.

2 往配置中心發(fā)布配置

nacos是一個服務(wù), 他對外也提供了很多接口, 其中一個是添加配置的接口. 我們模擬這個接口進行配置:

curl -X POST "http://localhost:8848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test&content=HelloWorld"

看到返回結(jié)果是true. 然后刷新控制臺, 可以看到如下


在這里插入圖片描述

3. 從配置中心獲取配置

curl -X GET "http://localhost:8848/nacos/v1/cs/configs?dataId=nacos.cfg.dataId&group=test"
這個命令就是獲取配置

在這里插入圖片描述

獲取helloworld內(nèi)容

4. 改變nacos配置數(shù)據(jù)的存儲位置

我們把配置信息添加到nacos, 那么,他是如何保存的呢? nacos某一個默認(rèn)的自帶數(shù)據(jù)庫, 這個數(shù)據(jù)庫不方便操作和查找. 因此我們將其替換為自己的mysql數(shù)據(jù)庫

1. 準(zhǔn)備一個mysql數(shù)據(jù)庫

因為mysql比較大, 所以,我使用的是docker安裝的mysql

下載mysql

docker pull mysql:5.7.15

啟動mysql

docker run -p 3306:3306 --name MySQLDocker -v PWD/conf/my.cnf:/etc/mysql/conf.d/my.cnf -vPWD/logs:/var/log/mysql -v $PWD/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7.15

2. 創(chuàng)建一個nacos_config的數(shù)據(jù)庫

在這里插入圖片描述

3. 初始化nacos_config表結(jié)構(gòu)

在這里找到配置文件: ${nacosHome}/conf/nacos-mysql.

4. 修改application.properties配置文件

在這里插入圖片描述

然后重新啟動.

在執(zhí)行上面的寫配置

數(shù)據(jù)庫里生成了一條配置信息:


在這里插入圖片描述

三. nacos配置

1. 在控制臺添加配置

Data ID: nacos-simple-demo.yaml
Group: DEFAULT_GROUP
配置格式: YAML
配置內(nèi)容: 
common
  config: something

將以上信息在控制臺配置好了


在這里插入圖片描述

以上就是在nacos服務(wù)端建好了配置信息

2. 模擬nacos客戶端--獲取nacos服務(wù)端配置

public class DemoTest {

    public static void main(String[] args) throws NacosException {
        String dataId = "test.demo.yml";
        String group = "DEFAULT_GROUP";
        String serverAddr = "localhost:8848";

        Properties properties = new Properties();
        properties.setProperty("serverAddr", serverAddr);
        // 和nacos服務(wù)建立連接
        ConfigService configService = NacosFactory.createConfigService(properties);
        String config = configService.getConfig(dataId, group, 10);
        System.out.println(config);

    }
}

ok, 就可以獲取nacos的配置信息了

四. nacos配置管理的模型

對于nacos配置管理, 通過namespace, group, dataId能夠定位到一個配置集.

在這里插入圖片描述

nacos的配置管理模型包含三部分: namespace, group, service/data Id. 通過配置管理模型, 我們可以定位到所需要的配置文件

其中service/data Id中. server是服務(wù)發(fā)現(xiàn), dataId是配置管理.

1. 配置集(DataId)

配置集就是上圖的DataId

在系統(tǒng)中, 通常一個配置文件, 就是一個配置集. 一個配置集可以包含系統(tǒng)的各種配置信息. 例如:一個配置集可能包含系統(tǒng)的數(shù)據(jù)源万伤、連接池, 日志等級的配置信息申窘。每個配置集都可以定義一個有意義的名稱, 就是配置集的Id, 即Data Id

2. 配置項

配置集中包含的一個個配置內(nèi)容, 就是配置項. 他代表具體的可配置的參數(shù). 通常以key=value的形式存在.

3. 配置分組(Group)

配置分組就是上圖中的Group. 配置分組是對配置集進行分組. 通過一個有意義的字符串(如: buy, trade)來表示. 不同的配置分組下可以有相同的配置集(Data ID). 當(dāng)您在nacos上創(chuàng)建一個配置的時候, 如果未填寫配置分組的名稱, 則采用默認(rèn)名稱DEFAULT_GROUP.

配置分組的常見場景有: 可用于區(qū)分不同的項目或應(yīng)用. 例如: 學(xué)生管理系統(tǒng)的配置集可以定義一個group為:STUDENT_GROUP.

4 命名空間(Namespace)

命名空間(namespace)可用于對不同的環(huán)境進行配置隔離. 例如: 可以隔離開發(fā)環(huán)境, 測試環(huán)境, 生成環(huán)境. 因為他們的配置可能各不相同. 或者是隔離不同的用戶, 不同的開發(fā)人員使用同一個nacos管理各自的配置, 可通過namespace進行隔離. 不同的命名空間下, 可以存在相同名稱的配置分組(Group)或配置項(Data Id)

最佳實踐
通常我們可以這樣定義namespace, group, dataid

  1. Namespace: 代表不同的環(huán)境, 如: 開發(fā)、測試曙旭, 生產(chǎn)等

  2. Group: 可以代表某個項目, 如XX醫(yī)療項目, XX電商項目

  3. DataId: 每個項目下往往有若干個工程, 每個配置集(DataId)是一個工程的主配置文件

在這里插入圖片描述

結(jié)合已有的項目, 進行分析

五. 命名空間的管理

我們先來回顧一下上面的客戶端實現(xiàn). 在上面的客戶端實現(xiàn)中,我們是沒有定義命名空間的. 那么他會采用默認(rèn)的命名空間public.


在這里插入圖片描述

1. namespace的隔離設(shè)計

  • 按照環(huán)境來設(shè)計namespace: 開發(fā), 測試, 生產(chǎn)
      
    這樣不同的環(huán)境的配置是相互隔離開的, 互不影響


    在這里插入圖片描述
  • 還可以按照多用戶的方式來設(shè)計. 比如, 張三, 李四,王五, 他們看到的自己的內(nèi)容是不一樣的.

2. 命名空間的管理

創(chuàng)建命名空間


在這里插入圖片描述

界面操作比較簡單,不都說了

下面我創(chuàng)建了4個命名空間. 其中public和dev都有一個Data Id叫做test.demo.yml. 我要通過程序代碼獲取dev下的test.demo.yml配置文件.


在這里插入圖片描述

模擬客戶端獲取nacos的命名空間為dev下的配置信息:

package com.lxl.org;

import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.exception.NacosException;

import java.util.Properties;

public class DemoTest {

    public static void main(String[] args) throws NacosException, InterruptedException {
        String dataId = "test.demo.yml";
        // 注意: 這里填的是命名空間的id
        String namespace = "dev";
        String group = "DEFAULT_GROUP";
        String serverAddr = "localhost:8848";

        Properties properties = new Properties();
        properties.setProperty("serverAddr", serverAddr);
        properties.setProperty("namespace", namespace);
        // 和nacos服務(wù)建立連接
        ConfigService configService = NacosFactory.createConfigService(properties);
        String config = configService.getConfig(dataId, group, 10);
        System.out.println(config);


        Thread.sleep(1000);
    }
}

需要指定要獲取的配置是哪個命名空間下面的.

3. 查看歷史版本

歷史版本這里就說一點, 那就是可以回滾. 點擊回滾, 就回滾到了某個版本的配置

4. 監(jiān)聽查詢

在這里插入圖片描述

想要監(jiān)聽開發(fā)環(huán)境下, 某個配置文件. 則課一下監(jiān)聽查詢中查看哪些配置文件被監(jiān)聽了.

比如: 我們寫一個demo, 監(jiān)聽dev下的test.demo.yaml配置文件

public static void main(String[] args) throws NacosException, InterruptedException {
       String dataId = "test.demo.yml";
       // 注意: 這里填的是命名空間的id
       String namespace = "a127e7f7-e37e-48fb-9968-cca7ef7c9f26";
       String group = "DEFAULT_GROUP";
       String serverAddr = "localhost:8848";

       Properties properties = new Properties();
       properties.setProperty("serverAddr", serverAddr);
       properties.setProperty("namespace", namespace);
       // 和nacos服務(wù)建立連接
       ConfigService configService = NacosFactory.createConfigService(properties);
       String config = configService.getConfig(dataId, group, 10);
       System.out.println(config);


       configService.addListener(dataId, group, new Listener() {
           @Override
           public Executor getExecutor() {
               return null;
           }

           @Override
           public void receiveConfigInfo(String s) {
               // 接收監(jiān)聽到的返回的配置信息
               System.out.println(s);
           }
       });

       Thread.sleep(1000000);
   }

寫一個監(jiān)聽程序, 不停的進行監(jiān)聽. 一旦有配置發(fā)生變化, 立刻就可以通知過來.

5. 登錄管理

nacos支持簡單的登錄功能, 默認(rèn)的用戶名/密碼是: nacos/nacos.

修改默認(rèn)用戶名和密碼的方法:

通過看源碼可以知道, nacos用戶加密使用的是BCrypt加密的方式. 因此,我們可以模擬一個BCrypt方法進行修改密碼

  • 在項目中引入BCrypt 的jar包
 <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-core</artifactId>
            <version>5.1.4.RELEASE</version>
        </dependency>
 

然后寫一個修改密碼的方法

package com.lxl.org;

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

public class PasswordHandler {
    public static void main(String[] args) {
        String encode = new BCryptPasswordEncoder().encode("123");
        System.out.println(encode);
    }
}

輸出結(jié)果替換數(shù)據(jù)庫中的密碼即可

$2a$10$LW/6RKgceuALErDPcU8THOT5V1Ajc98jgo6N38oOX0Tvmce39hP4a

新加用戶, 需要設(shè)置用戶的用戶名和角色

insert into users(username, password, enabled) VALUES ("lxl", "$2a$10$LW/6RKgceuALErDPcU8THOT5V1Ajc98jgo6N38oOX0Tvmce39hP4a", 1);
insert into roles(username, role) VALUES ('lxl', 'ROLE_ADMIN')

也可以在控制臺修改

六. Nacos配置管理應(yīng)用于分布式系統(tǒng)

下圖展示了nacos集中管理多個配置服務(wù)的流程


在這里插入圖片描述
  1. 用戶通過nacos 服務(wù)的控制臺對配置文件進行集中管理

  2. 各服務(wù)統(tǒng)一從nacos中獲取各自的配置, 并監(jiān)聽配置的變化.


1. 模擬兩個微服務(wù)請求一個注冊中心的場景.

1. 在dev環(huán)境下, 新建兩個配置文件. server1, server2

在這里插入圖片描述

2. 創(chuàng)建一個簡單的微服務(wù)架構(gòu). 采用spring cloud微服務(wù)架構(gòu).
創(chuàng)建一個parent工程, 引入公共的配置. 在創(chuàng)建兩個微服務(wù)server1, server2
創(chuàng)建一個parent maven工程, 引入maven包

<dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.1.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Greenwich.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.1.3.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

創(chuàng)建一個service1. 然后添加nacos的maven管理. 在添加bootstrap.yml配置文件, 最后增加啟動類

<dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

配置文件bootstrap.yml. 這里需要注意的是默認(rèn)查找的data Id是應(yīng)用面+擴展名

server:
  port: 56010

spring:
  application:
    name: service1
  cloud:
    nacos:
      config:
        server-addr: localhost:8848
        file-extension: yaml
        namespace: dev
        group: TEST_GROUP
        # 查找默認(rèn)的data Id --> 應(yīng)用名 + 文件擴展名-->service1.yaml

最后增加啟動類, 里面直接定義了一個controller, 獲取配置信息

package com.lxl.www.service1;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
public class BootStrapApplication {
    public static void main(String[] args) {
        SpringApplication.run(BootStrapApplication.class, args);
    }

    /**
     *  采用注解的方式讀取nacos配置信息
     */
    @Value("${common.config}")
    private String config1;


    /**
     * 定義一個controller
     */
    @GetMapping(value = "/config")
    public String getNacosConfig() {
        return config1;
    }
}

service2也是如此.

注意: nacos發(fā)布的時候, 要打開日志文件, 看看是否發(fā)布成功. 如果報異常, 可能發(fā)布不成功. 項目獲取配置文件失敗
在這里插入圖片描述

這里客戶端使用的是阿里提供的nacos客戶端: spring-cloud-starter-alibaba-nacos-config

存在的問題:

當(dāng)使用spring的注解@Value的時候, 我們發(fā)現(xiàn), 在配置中心修改了配置文件的內(nèi)容, 但是通過注解讀取出來的內(nèi)容沒變. 這是什么愿意鬧呢?其實, 配置文件修改了內(nèi)容以后, 他是通知了服務(wù)端的, 之所以沒改, 是因為@Value屬性的原因, 他應(yīng)該是有緩存了. 那么如果想動態(tài)獲取修改后的配置文件, 有兩種方式:

方式一: 使用properties.

獲取配置的方式, 修改如下:

   @Autowired
    private ConfigurableApplicationContext applicationContext;

    /**
     * 定義一個controller
     */
    @GetMapping(value = "/config")
    public String getNacosConfig() {
        return applicationContext.getEnvironment().getProperty("common.config");
    }

方式二: @NacosValue

注意事項:

  • nacos的配置信息要寫在bootstrap.yml中. 讓其配置信息優(yōu)先加載. (bootstrap.yml加載的時間要比application.yml早)

2. 擴展DataId, 多配置處理

如果有多個配置文件, 我們可以使用擴展配置的方式, 添加多個配置文件

擴展配置id, 第一個擴展的配置id
ext-config[0]:
    data-id: ext-config-common01.yml

ext-config[1]:
    data-id: ext-config-common02.yml
    group: GLOBAL_GROUP

ext-config[2]:
    data-id: ext-config-common03.yml
    group: REFRESH_GROUP
    refresh: true #配置修改, 是否刷新          

第一個配置, 只有一個data-id. 沒有g(shù)roup, 采用默認(rèn)的DEFAULT_GROUP.

第二個擴展配置. 定義了一個GLOBAL_GROUP. 全局配置

第三個擴展配置: 定義為一個自動刷新的GROUP, 并設(shè)置自動刷新屬性為true
接下來我們在控制臺添加這三個文件


在這里插入圖片描述

在這里插入圖片描述

在這里插入圖片描述

修改接口獲取配置信息

    /**
     * 定義一個controller
     */
    @GetMapping(value = "/config")
    public String getNacosConfig() {
        String p1 = applicationContext.getEnvironment().getProperty("common.config");
        String p2 = applicationContext.getEnvironment().getProperty("common.ext1");
        String p3 = applicationContext.getEnvironment().getProperty("common.ext2");
        String p4 = applicationContext.getEnvironment().getProperty("common.ext3");
        return p1 + "+" + p2 + "+" + p3 + "+" + p4;
    }

我們可以看到打印出來的效果


在這里插入圖片描述

這時, 在控制臺修改配置文件, 我們發(fā)現(xiàn)common.config會改變. common.ext3會改變. 其他兩個不會自動更新

總結(jié): 默認(rèn)配置是可以自動刷新的. 在擴展配置中, 只有增加了屬性refresh:true, 才會自動刷新

3. 共享Data Id

我們可以設(shè)置共享data id, 設(shè)置方法如下:

在這里插入圖片描述

設(shè)置共享的data id. 我們設(shè)置了三個文件. 啟動項目, 運行結(jié)果如下

在這里插入圖片描述

我們發(fā)現(xiàn), 有兩個是null. 為什么是null呢? 因為使用這種方式配置, 只能第一個文件生效, 因此, 如果想要配置多個擴展文件, 還要使用擴展dataId的方式.

4. 配置Data Id的優(yōu)先級

目前有三種設(shè)置Data Id的方式

  • 默認(rèn)的data id. 項目名+擴展名的方式.
  • 使用ext-config[0] 設(shè)置擴展配置
  • 使用shared-dataids: 設(shè)置共享配置.

那么, 他們?nèi)齻€的優(yōu)先級是什么樣的呢?

默認(rèn)配置 > ext-config > shared-dataids
如果有多個ext-config擴展配置, 誰的優(yōu)先級高呢? n的個數(shù)越大, 優(yōu)先級越高.....

ext-config[n] > ext-config[2] > ext-config[1] > ext-config[0]

5. 關(guān)閉Nacos配置

如果不想要使用nacos配置了, 那么可以使之enable屬性為false

七. Nacos集群部署

通常我們在生成環(huán)境不可能只有一臺nacos. 為了保證高可用性, 我們會配置多臺nacos.

要求: 配置3臺或以上nacos服務(wù)

下面我們來模擬三臺nacos服務(wù)集群

第一步: 解壓三個nacos服務(wù)


在這里插入圖片描述

第二步: 修改配置文件

  1. 修改端口號. 分別設(shè)置為8848, 8849, 8850
在這里插入圖片描述
在這里插入圖片描述

在這里插入圖片描述

2. 添加本地服務(wù)的ip地址

給三個服務(wù)都增加下面這個配置內(nèi)容: 設(shè)置本機的ip地址

nacos.inetutils.ip-address=127.0.0.1

3. 設(shè)置三個nacos的集群關(guān)系

修改cluster.conf.example文件為cluster.conf

并在里面添加如下內(nèi)容


在這里插入圖片描述

第四步: 啟動三臺服務(wù)器. 以集群的模式啟動
./start.sh -m cluster
然后, 在控制他查看集群, 有一臺主, 兩臺從

在這里插入圖片描述

第五步 在項目中配置nacos集群

在這里插入圖片描述

注意: 多個配置之間不能帶空格.

重啟項目. 訪問接口返回內(nèi)容


在這里插入圖片描述

這里面, 我們可以停掉任何一臺nacos服務(wù). 只要還有一個能運行, 服務(wù)就可以訪問通

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末茧球,一起剝皮案震驚了整個濱河市涯贞,隨后出現(xiàn)的幾起案子枪狂,更是在濱河造成了極大的恐慌,老刑警劉巖宋渔,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件州疾,死亡現(xiàn)場離奇詭異,居然都是意外死亡皇拣,警方通過查閱死者的電腦和手機孝治,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來审磁,“玉大人,你說我怎么就攤上這事岂座√伲” “怎么了?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵费什,是天一觀的道長钾恢。 經(jīng)常有香客問我手素,道長,這世上最難降的妖魔是什么瘩蚪? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任泉懦,我火速辦了婚禮,結(jié)果婚禮上疹瘦,老公的妹妹穿的比我還像新娘崩哩。我一直安慰自己,他們只是感情好言沐,可當(dāng)我...
    茶點故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布邓嘹。 她就那樣靜靜地躺著,像睡著了一般险胰。 火紅的嫁衣襯著肌膚如雪汹押。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天起便,我揣著相機與錄音棚贾,去河邊找鬼。 笑死榆综,一個胖子當(dāng)著我的面吹牛妙痹,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播奖年,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼细诸,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了陋守?” 一聲冷哼從身側(cè)響起震贵,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎水评,沒想到半個月后猩系,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡中燥,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年寇甸,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片疗涉。...
    茶點故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡拿霉,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出咱扣,到底是詐尸還是另有隱情绽淘,我是刑警寧澤,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布闹伪,位于F島的核電站沪铭,受9級特大地震影響壮池,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜杀怠,卻給世界環(huán)境...
    茶點故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一椰憋、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧赔退,春花似錦橙依、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至卵渴,卻和暖如春慧域,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背浪读。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工昔榴, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人碘橘。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓互订,卻偏偏與公主長得像,于是被迫代替她去往敵國和親痘拆。 傳聞我的和親對象是個殘疾皇子仰禽,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,914評論 2 355

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