分布式配置中心介紹--Spring Cloud學(xué)習(xí)第六天(非原創(chuàng))

文章大綱

一、分布式配置中心是什么
二、配置基本實(shí)現(xiàn)
三、Spring Cloud Config服務(wù)端配置細(xì)節(jié)(一)
四、Spring Cloud Config服務(wù)端配置細(xì)節(jié)(二)
五、Spring Cloud Config客戶端配置細(xì)節(jié)
六、項(xiàng)目源碼與參考資料下載
七、參考文章

一、分布式配置中心是什么

??隨著我們的分布式項(xiàng)目越來越大,我們可能需要將配置文件抽取出來單獨(dú)管理,Spring Cloud Config對這種需求提供了支持。Spring Cloud Config為分布式系統(tǒng)中的外部配置提供服務(wù)器和客戶端支持。我們可以使用Config Server在所有環(huán)境中管理應(yīng)用程序的外部屬性,Config Server也稱為分布式配置中心,本質(zhì)上它就是一個獨(dú)立的微服務(wù)應(yīng)用,用來連接配置倉庫并將獲取到的配置信息提供給客戶端使用;客戶端就是我們的各個微服務(wù)應(yīng)用,我們在客戶端上指定配置中心的位置,客戶端在啟動的時(shí)候就會自動去從配置中心獲取和加載配置信息。Spring Cloud Config可以與任何語言運(yùn)行的應(yīng)用程序一起使用。服務(wù)器存儲后端的默認(rèn)實(shí)現(xiàn)使用git,因此它輕松支持配置信息的版本管理,當(dāng)然我們也可以使用Git客戶端工具來管理配置信息。本文我們就先來看下Spring Cloud Config的一個基本使用。

二、配置基本實(shí)現(xiàn)

1. 構(gòu)建配置中心

首先我們來構(gòu)建一個配置中心,方式很簡單,創(chuàng)建一個普通的Spring Boot項(xiàng)目,叫做config-server,創(chuàng)建好之后,添加如下依賴:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.7.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
    <spring-cloud.version>Dalston.SR3</spring-cloud.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-config-server</artifactId>
    </dependency>
</dependencies>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

然后在入口類上添加@EnableConfigServer注解,表示開啟配置中心服務(wù)端功能,如下:

@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConfigServerApplication.class, args);
    }
}

然后在application.properties中配置一下git倉庫的信息,為了簡單,我這里就不自己搭建git服務(wù)端了,直接使用GitHub(當(dāng)然也可以使用碼云),這里需要我首先在我的Github上創(chuàng)建一個名為scConfig的項(xiàng)目,創(chuàng)建好之后,再做如下配置:

spring.application.name=config-server
server.port=2007
spring.cloud.config.server.git.uri=https://github.com/lenve/scConfig.git
spring.cloud.config.server.git.search-paths=config-repo
spring.cloud.config.server.git.username=username
spring.cloud.config.server.git.password=password

前兩行配置的含義就不用我多說了,我說下后面四行配置的含義,如下:
(1)uri表示配置中心所在倉庫的位置
(2)search-paths表示倉庫下的子目錄
(3)username表示你的GitHub用戶名
(4)password表示你的GitHub密碼
做好這些之后我們的配置中心服務(wù)端就創(chuàng)建好了。

2. 構(gòu)建配置倉庫

接下來我們需要在github上設(shè)置好配置中心,首先我在本地找一個空文件夾,在該文件夾中創(chuàng)建一個文件夾叫config-repo,然后在config-repo中創(chuàng)建四個配置文件,如下:

四個文件中的內(nèi)容分別如下:

OK,然后回到test目錄下,依次執(zhí)行如下命令將本地文件同步到Github倉庫中,如下:

如此之后,我們的配置文件就上傳到GitHub上了。此時(shí)啟動我們的配置中心,通過/{application}/{profile}/{label}就能訪問到我們的配置文件了,其中application表示配置文件的名字,對應(yīng)我們上面的配置文件就是app,profile表示環(huán)境,我們有dev、test、prod還有默認(rèn),label表示分支,默認(rèn)我們都是放在master分支上,我們在瀏覽器上訪問結(jié)果如下:

OK,從這里我們看到了我們放在倉庫中的配置文件。JSON中的name表示配置文件名application的部分,profiles表示環(huán)境部分,label表示分支,多了一個version,實(shí)際上就是我們GitHub上提交信息時(shí)產(chǎn)生的版本號,當(dāng)我們訪問成功后,我們還可以看到控制臺打印了如下日志:

實(shí)際上是配置中心通過git clone命令將配置文件在本地保存了一份,這樣可以確保在git倉庫掛掉的時(shí)候我們的應(yīng)用還可以繼續(xù)運(yùn)行,此時(shí)我們斷掉網(wǎng)絡(luò),再訪問http://localhost:2007/app/prod/master,一樣還可以拿到數(shù)據(jù),此時(shí)的數(shù)據(jù)就是從本地獲取的。

3. 客戶端配置

服務(wù)端搞好了,接下來我們來看看怎么樣在客戶端使用。
首先創(chuàng)建一個普通的Spring Boot工程config-client,創(chuàng)建成功之后添加如下依賴:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.7.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
    <spring-cloud.version>Dalston.SR3</spring-cloud.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-config</artifactId>
    </dependency>
</dependencies>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

然后創(chuàng)建bootstrap.properties文件,來獲取配置信息,注意這些信息一定要放在bootstrap.properties文件中才有效,文件內(nèi)容如下:

spring.application.name=app
spring.cloud.config.profile=dev
spring.cloud.config.label=master
spring.cloud.config.uri=http://localhost:2007/
server.port=2008

這里的name對應(yīng)了配置文件中的application部分,profile對應(yīng)了profile部分,label對應(yīng)了label部分,uri則表示配置中心的地址。配置完成之后創(chuàng)建一個測試Controller,我們來看看效果:

@RestController
@RefreshScope
public class HelloController {
    @Value("${sang}")
    String sang;
    @Autowired
    Environment env;

    @RequestMapping("/sang")
    public String sang() {
        return this.sang;
    }
    @RequestMapping("/sang2")
    public String sang2() {
        return env.getProperty("sang", "未定義");
    }
}

我們可以直接注入值,也可以通過Environment來獲取值,訪問結(jié)果如下:

三、Spring Cloud Config服務(wù)端配置細(xì)節(jié)(一)

我們先通過下面一張圖來看看Config Server的一個大致工作過程:

說明
1.首先我們需要一個遠(yuǎn)程的Git倉庫,自己學(xué)習(xí)可以直接用GitHub,在在實(shí)際生產(chǎn)環(huán)境中,需要自己搭建一個Git服務(wù)器,遠(yuǎn)程Git倉庫的作用主要是用來保存我們的配置文件
2.除了遠(yuǎn)程Git倉庫之外,我們還需要一個本地Git倉庫,每當(dāng)Config Server訪問遠(yuǎn)程Git倉庫時(shí),都會保存一份到本地,這樣當(dāng)遠(yuǎn)程倉庫無法連接時(shí),就直接使用本地存儲的配置信息
3.至于微服務(wù)A、微服務(wù)B則是我們具體的應(yīng)用,這些應(yīng)用在啟動的時(shí)候會從Config Server中來加載相應(yīng)的配置信息
4.當(dāng)微服務(wù)A/B嘗試去從Config Server中加載配置信息的時(shí)候,Config Server會先通過git clone命令克隆一份配置文件保存到本地
5.由于配置文件是存儲在Git倉庫中,所以配置文件天然的具備版本管理功能,Git中的Hook功能可以實(shí)時(shí)監(jiān)控配置文件的修改

Git URI中的占位符
靈活的使用URI占位符,可以有效的減少我們的工作量。考慮這樣一個問題,我有ServerA、ServerB兩個服務(wù),兩個服務(wù)對應(yīng)的配置文件的存儲地址分別位于https://github.com/lenve/scConfig/sahttps://github.com/lenve/scConfig/sb,但是我的Config Server只有一個,那么當(dāng)我的ServerA和ServerB連接上Config Server時(shí),Config Server怎么知道去哪個地址下拿配置文件?這個時(shí)候就涉及到占位符的使用。
在上篇文章中我們已經(jīng)了解了Spring Cloud Config中的三種占位符,分別是{application}、{profile}和{label},這些占位符除了用來標(biāo)識配置文件的規(guī)則,還可以用在Config Server中對Git倉庫的URI配置,用在URI配置中時(shí),這三個占位符的含義分別如下所示:

1.{application}映射到客戶端的 spring.application.name
2.{profile}映射到客戶端上的 spring.profiles.active
3.{label}這是一個服務(wù)器端功能,標(biāo)記”版本”的配置文件集

此時(shí),假設(shè)我不同環(huán)境下的配置文件分別放在下面這些目錄下:

https://github.com/lenve/scConfig/app/dev
https://github.com/lenve/scConfig/app/prod
https://github.com/lenve/scConfig/app/test  

那么我的客戶端文件這樣配置:

spring.application.name=app
# dev根據(jù)具體情況來修改
spring.cloud.config.profile=dev
spring.cloud.config.label=master
spring.cloud.config.uri=http://localhost:2007/
server.port=2008

然后Config Server按下面這種方式配置即可:

spring.cloud.config.server.git.uri=https://github.com/lenve/scConfig.git
spring.cloud.config.server.git.search-paths={application}/{profile}

當(dāng)然這種存儲規(guī)劃不一定最佳,這里只是給小伙伴們演示占位符的用法。

默認(rèn)情況下,Config Server 克隆下來的文件保存在C:\Users<當(dāng)前用戶>\AppData\Local\Temp目錄下,我們可以通過如下配置來修改:

spring.cloud.config.server.git.basedir=E:\\111\\

健康監(jiān)測
默認(rèn)情況下Spring Cloud Config會為配置中心服務(wù)端創(chuàng)建一個健康監(jiān)測器,該檢測器默認(rèn)情況下是訪問的倉庫文件是{application}為app的配置文件,如果倉庫中不存在這個文件,健康顯示器就會顯示倉庫無法連接,此時(shí)我們有兩種解決方案:1.倉庫中添加相應(yīng)的配置文件;2.重新指定檢測的配置,重新指定方式如下:

spring.cloud.config.server.health.repositories.check.name=app
spring.cloud.config.server.health.repositories.check.label=master
spring.cloud.config.server.health.repositories.check.profiles=dev

此時(shí),系統(tǒng)回去訪問http://localhost:2007/app/dev/master地址,如果能夠訪問到,則顯示倉庫已連接,如下:

安全保護(hù)
開發(fā)環(huán)境中我們的配置中心肯定是不能隨隨便便被人訪問的,我們可以加上適當(dāng)?shù)谋Wo(hù)機(jī)制,由于微服務(wù)是構(gòu)建在Spring Boot之上,所以整合Spring Security是最方便的方式。

首先添加依賴:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

然后在application.properties中配置用戶名密碼:

security.user.name=sang
security.user.password=123

最后在配置中心的客戶端上配置用戶名和密碼即可,如下:

spring.cloud.config.username=sang
spring.cloud.config.password=123

四、Spring Cloud Config服務(wù)端配置細(xì)節(jié)(二)

1. 簡介

在微服務(wù)架構(gòu)中,由于獨(dú)立的服務(wù)個數(shù)眾多,加上前期測試工作量大,一些原本由運(yùn)維人員維護(hù)的敏感信息會被我們直接寫在微服務(wù)中,以提高開發(fā)效率,但是這種明文存儲方式顯然是非常危險(xiǎn)的,所以我們要對這些信息進(jìn)行加密,而Spring Cloud Config則提供了對稱加解密、非對稱加解密的功能來幫助我們完成這一需求。OK,本文我們就來看看如何實(shí)現(xiàn)配置信息的加解密。

2. 準(zhǔn)備工作

默認(rèn)情況下我們的JRE中自帶了JCE(Java Cryptography Extension),但是默認(rèn)是一個有限長度的版本,我們這里需要一個不限長度的JCE,這個JCE我們可以直接百度然后在Oracle官網(wǎng)下載,下載之后解壓,我們可以看到如下三個文件:

我們需要將這里的兩個jar包拷貝到我們的jdk安裝目錄下,我的是%JAVA_HOME%\jre\lib\security,覆蓋該目錄下原有的文件。

如此之后,我們的準(zhǔn)備工作就完成了。

3. 對稱加解密

對稱加解密比較簡單,直接配置密鑰就可以了,在我們前文創(chuàng)建出來的config-server中配置密鑰,但是注意這個密鑰需要配置在bootstrap.properties中,另外這里還有非常重要一點(diǎn):Spring Cloud的Dalston.SR3和Dalston.SR2版本在這個問題上是有BUG的,如果用這兩個版本在這里測試會沒有效果,應(yīng)該避開使用這兩個版本,我這里使用的是Dalston.SR4版本,配置如下:

encrypt.key=sang

配置完成之后,啟動我們的config-server工程,然后訪問如下地址http://localhost:2007/encrypt/status,如果看到如下訪問結(jié)果,表示環(huán)境搭建成功了:

此時(shí)我們就可以通過第三方工具如POSTMAN、RestClient等來訪問/encrypt和/decrypt接口,比如說我要給dev這個字符加密,方式如下(我這里以POSTMAN為例,注意是POST請求):

解密方式如下:

OK,拿到加密的字符串之后,我們就可以在配置文件中使用了,還是我們昨天的配置文件,這次我這樣來寫:

image

小伙伴們注意,配置文件的值如果是以{cipher}開頭,表示該值是一個加密字符,配置中心config-server在獲取到這個值之后會先對值進(jìn)行解密,解密之后才會返回給客戶端使用。

4. 非對稱加解密

上文我們使用了對稱加解密的方式來確保配置文件的安全性,如果使用非對稱加解密的方式,我們的安全性將會得到進(jìn)一步的提高。使用非對稱加密的話需要我們先生成密鑰對,生成密鑰對可以直接使用jdk中自帶的keytool工具,方式如下:

keytool -genkeypair -alias config-server -keyalg RSA -keystore config-server.keystore

執(zhí)行效果如圖:

執(zhí)行成功之后,會在命令執(zhí)行目錄下生成一個名為config-server.keystore的文件,將該文件拷貝到config-server的src\main\resources目錄下,然后做如下配置:

encrypt.key-store.location=config-server.keystore
encrypt.key-store.alias=config-server
encrypt.key-store.password=111111
encrypt.key-store.secret=111111

OK,如此之后我們的非對稱加密就配置好了,測試方式和對稱加密的測試方式一致,我這里就不再演示了。

五、Spring Cloud Config客戶端配置細(xì)節(jié)

服務(wù)化配置中心

在前面幾篇關(guān)于Spring Cloud Config配置中心的文章中,我們在config-client中配置config-server地址的時(shí)候都是直接將地址寫死,這種方式顯然不夠靈活,有的小伙伴可能已經(jīng)想到了,這里我們可以結(jié)合eureka注冊中心,然后在配置的時(shí)候直接使用服務(wù)名即可,OK,那我們對之前的項(xiàng)目稍加改造吧。

config-server改造

這里的改造都是非常簡單的,服務(wù)端改造和客戶端改造都是分三步走:1.添加依賴;2.添加注解;3.修改application.properties.

首先我們在config-server中添加如下依賴:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>

然后在config-server的入口類上添加@EnableDiscoveryClient注解,表示這是一個Eureka客戶端,如下:

@SpringBootApplication
@EnableConfigServer
@EnableDiscoveryClient
public class ConfigServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConfigServerApplication.class, args);
    }
}

最后在application.properties中配置eureka注冊中心地址:

eureka.client.service-url.defaultZone=http://localhost:1111/eureka/

至此,我們的config-server就配置成功了。

config-client改造

config-client改造第一步也是先添加依賴,如下:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>

然后入口類添加@EnableDiscoveryClient注解,如下:

@SpringBootApplication
@EnableDiscoveryClient
public class ConfigClientApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConfigClientApplication.class, args);
    }
}

最后修改配置文件,如下:

spring.application.name=app
# dev根據(jù)具體情況來修改
spring.cloud.config.profile=dev
spring.cloud.config.label=master
eureka.client.service-url.defaultZone=http://localhost:1111/eureka/
spring.cloud.config.discovery.enabled=true
spring.cloud.config.discovery.service-id=config-server
server.port=2008

關(guān)于這個配置文件我說如下三點(diǎn):

1.eureka.client.service-url.defaultZone設(shè)置了注冊中心的地址,將config-client注冊到eureka注冊中心中去
2.spring.cloud.config.discovery.enabled表示開啟通過服務(wù)名來訪問config-server
3.spring.cloud.config.discovery.service-id=config-server則表示config-server的服務(wù)名

測試

OK,經(jīng)過以上的改造之后,此時(shí)我們分別啟動eureka服務(wù)注冊中心、config-server、config-client,然后訪問http://localhost:1111,可以看到兩個應(yīng)用都已經(jīng)注冊成功了:

然后繼續(xù)測試config-client的/sang接口,結(jié)果如下:

沒問題。

好了,服務(wù)化配置中心構(gòu)建成功。

失敗快速響應(yīng)

不作任何額外配置的情況下,失敗響應(yīng)有點(diǎn)遲鈍,舉個簡單的例子,關(guān)掉config-server,我們直接啟動config-client,此時(shí)啟動會報(bào)錯,但是報(bào)錯時(shí)間較晚,報(bào)錯的時(shí)候系統(tǒng)已經(jīng)打印了許多啟動日志了,如果我們希望在啟動失敗時(shí)能夠快速響應(yīng),方式很簡單,config-client中添加如下配置即可:

spring.cloud.config.fail-fast=true

此時(shí)不啟動config-server直接啟動config-client依然會報(bào)錯,但是我們看到報(bào)錯時(shí)間較早,系統(tǒng)都沒打印幾條啟動日志。

重試機(jī)制

如果由于網(wǎng)絡(luò)抖動等原因?qū)е耤onfig-client在啟動時(shí)候訪問config-server沒有訪問成功從而報(bào)錯,這顯然是不劃算的,遇到這種情況我們希望config-client最好能重試幾次,重試機(jī)制在這里也是受支持的,添加重試機(jī)制的方式很簡單,引入如下兩個依賴:

<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

引入依賴就OK了,不用做任何額外配置(當(dāng)然要確保失敗快速響應(yīng)已開啟),此時(shí)我們再嘗試不啟動config-server直接啟動config-client,得到的啟動日志如下:

我們看到,config-client一共嘗試了六次去訪問config-server,六次都失敗了才拋異常。

和重試機(jī)制相關(guān)的配置有如下四個:

# 配置重試次數(shù),默認(rèn)為6
spring.cloud.config.retry.max-attempts=6
# 間隔乘數(shù),默認(rèn)1.1
spring.cloud.config.retry.multiplier=1.1
# 初始重試間隔時(shí)間,默認(rèn)1000ms
spring.cloud.config.retry.initial-interval=1000
# 最大間隔時(shí)間,默認(rèn)2000ms
spring.cloud.config.retry.max-interval=2000

動態(tài)刷新配置

有的時(shí)候,我動態(tài)的更新了Git倉庫中的配置文件,那么我如何讓我的config-client能夠及時(shí)感知到呢?方式很簡單,首先在config-client中添加如下依賴:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

該依賴中包含了/refresh端點(diǎn)的實(shí)現(xiàn),我們將利用這個端點(diǎn)來刷新配置信息。然后需要在application.properties中配置忽略權(quán)限攔截:

management.security.enabled=false

OK,配置好之后,啟動eureka注冊中心,config-server和config-client,訪問http://localhost:2008/sang,結(jié)果如下:

此時(shí)我利用Git客戶端工具,將app-dev.properties中的內(nèi)容修改一下,修改成功之后,先用POST請求訪問http://localhost:2008/refresh地址,結(jié)果如下:

然后再訪問http://localhost:2008/sang,結(jié)果如下:

我們看到配置文件已經(jīng)更新了。

六、項(xiàng)目源碼與參考資料下載

鏈接:https://pan.baidu.com/s/1WgA85ExFsQQlU7Ek1Rvf6w
提取碼:p7qn

七、參考文章

https://www.cnblogs.com/lenve/p/7985943.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,702評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,143評論 3 415
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,553評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,620評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,416評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,940評論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,024評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,170評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,709評論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,597評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,784評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,291評論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,029評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,407評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,663評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,403評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,746評論 2 370

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