.NetCore實(shí)踐篇:使用zipkin4net推送數(shù)據(jù)到分布式監(jiān)控zipkin(2)

前言

《牧神記》有一句話說的好,破心中神。當(dāng)不再對(duì)分布式飒箭,微服務(wù),CLR畏懼迷茫的時(shí)候蜒灰,你就破了心中神弦蹂。

zipkin復(fù)習(xí)

上篇NetCore實(shí)踐篇:分布式監(jiān)控客戶端ZipkinTracer從入門到放棄之路,我們提到了zipkin的原理和架構(gòu)說明,以及用zipkintracer實(shí)踐失敗的記錄强窖。
今天我們來復(fù)習(xí)下凸椿。

zipkin作用

全鏈路追蹤工具(根據(jù)依賴關(guān)系)

查看每個(gè)接口、每個(gè)service的執(zhí)行速度(定位問題發(fā)生點(diǎn)或者尋找性能瓶頸)

zipkin工作原理

創(chuàng)造一些追蹤標(biāo)識(shí)符(tracingId翅溺,spanId脑漫,parentId)髓抑,最終將一個(gè)request的流程樹構(gòu)建出來

zipkin架構(gòu)

Collector接收各service傳輸?shù)臄?shù)據(jù);

Cassandra作為Storage的一種窿撬,默認(rèn)存儲(chǔ)在內(nèi)存中启昧,也支持ElasticSearch和mysql用于生產(chǎn)落庫;

Query負(fù)責(zé)查詢Storage中存儲(chǔ)的數(shù)據(jù),提供簡(jiǎn)單的JSON API獲取數(shù)據(jù)劈伴,主要提供給web UI使用密末;

Web 提供簡(jiǎn)單的web界面;

zipkin分布式跟蹤系統(tǒng)的目的

zipkin為分布式鏈路調(diào)用監(jiān)控系統(tǒng)跛璧,聚合各業(yè)務(wù)系統(tǒng)調(diào)用延遲數(shù)據(jù)严里,達(dá)到鏈路調(diào)用監(jiān)控跟蹤;

zipkin通過采集跟蹤數(shù)據(jù)可以幫助開發(fā)者深入了解在分布式系統(tǒng)中某一個(gè)特定的請(qǐng)求時(shí)如何執(zhí)行的追城;

參考如下

zipkin參考

zipkin官網(wǎng)

zipkin4net簡(jiǎn)介

zipkin4net是.NET客戶端庫刹碾。

它為您提供:

  • Zipkin 原語(跨度,注釋座柱,二進(jìn)制注釋迷帜,......)【Zipkin primitives (spans, annotations, binary annotations, ...)】

  • 異步跟蹤發(fā)送

  • 跟蹤傳輸抽象

簡(jiǎn)單用法

var logger = CreateLogger(); //它應(yīng)該實(shí)現(xiàn)ILogger
var sender = CreateYourTransport(); //它應(yīng)該實(shí)現(xiàn)IZipkinSender

TraceManager.SamplingRate = 1.0f; //全監(jiān)控

var tracer = new ZipkinTracer(sender);
TraceManager.RegisterTracer(tracer);
TraceManager.Start(logger);

//運(yùn)行你的程序

//當(dāng)關(guān)閉時(shí)。
TraceManager.Stop();

簡(jiǎn)介到此為止色洞,剩余您可參考zipkin4net戏锹。

Show me the Code

廢話少說,一杯代碼為敬火诸。

進(jìn)入代碼之前锦针,我先來演示下代碼結(jié)構(gòu)。這個(gè)結(jié)構(gòu)對(duì)應(yīng)我之前的代碼實(shí)踐置蜀。內(nèi)存隊(duì)列奈搜,爬蟲在我的博客內(nèi)都能找到博客對(duì)應(yīng)。


演示結(jié)構(gòu)圖

今天我們只說zipkin4Net的實(shí)踐盯荤。為了測(cè)試查看zipkin是否能夠匯集不同的站點(diǎn),我特意建立了兩個(gè)站點(diǎn)Demo.ZipKinWeb和Demo.ZipKinWeb2馋吗。類似下圖:


image.png

為了能真實(shí)落庫,我創(chuàng)建了FanQuick.Repository,用于提供mongodb存儲(chǔ)幫助秋秤。IRepository泛型接口聲明如下

namespace FanQuick.Repository
{
    public interface IRepository<TDocument> where TDocument:EntityBase
    {
        IQueryable<TDocument> Queryable { get; }
        bool Any(Expression<Func<TDocument, bool>> filter);
        /// <summary>
        /// 刪除
        /// </summary>
        /// <param name="filter"></param>
        /// <returns></returns>
        bool Delete(Expression<Func<TDocument, bool>> filter);
        /// <summary>
        /// 查詢
        /// </summary>
        /// <param name="filter"></param>
        /// <returns></returns>
        IEnumerable<TDocument> Find(Expression<Func<TDocument, bool>> filter);
        /// <summary>
        /// 新增
        /// </summary>
        /// <param name="document"></param>
        void Insert(TDocument document);
        /// <summary>
        /// 批量插入
        /// </summary>
        /// <param name="documents"></param>
        void Insert(IEnumerable<TDocument> documents);
        /// <summary>
        /// 統(tǒng)計(jì)宏粤。
        /// </summary>
        /// <param name="filter"></param>
        /// <returns></returns>
        long Count(Expression<Func<TDocument, bool>> filter);

        TDocument FindOneAndDelete(Expression<Func<TDocument, bool>> filter);

        TDocument FindOneAndUpdate(FilterDefinition<TDocument> filter, UpdateDefinition<TDocument> update);
    }
}

為了兩個(gè)站點(diǎn)能夠復(fù)用調(diào)用zipkin4net的通知,我將代碼抽離出來放到了 Demo.ZipkinCommon航缀。
可復(fù)用的抽象類CommonStartUp,代碼如下:重點(diǎn)關(guān)注下調(diào)用zipkin4net的代碼堰怨。并將抽象Run方法暴漏給了子類芥玉,需要子類實(shí)現(xiàn)。要特別注意备图,appsettings.json需要設(shè)置applicationName,不然發(fā)送到zipkin就是未命名服務(wù)灿巧,這就不能區(qū)分站點(diǎn)了!

namespace Demo.ZipkinCommon
{
    public abstract class CommonStartup
    {
        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
        public abstract void ConfigureServices(IServiceCollection services);

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {

            var config = ConfigureSettings.CreateConfiguration();

            var applicationName = config["applicationName"];
            //if (env.IsDevelopment())
            //{
            //    app.UseDeveloperExceptionPage();
            //}
            //else
            //{
            //    app.UseExceptionHandler("/Home/Error");
            //    app.UseHsts();
            //}
            var lifetime = app.ApplicationServices.GetService<IApplicationLifetime>();
            lifetime.ApplicationStarted.Register(() =>
            {
                TraceManager.SamplingRate = 1.0f;
                var logger = new TracingLogger(loggerFactory, "zipkin4net");
                var httpSender = new HttpZipkinSender("http://weixinhe.cn:9411", "application/json");
                var tracer = new ZipkinTracer(httpSender, new JSONSpanSerializer());
                TraceManager.RegisterTracer(tracer);
                TraceManager.Start(logger);
            });
            lifetime.ApplicationStopped.Register(() => TraceManager.Stop());
            app.UseTracing(applicationName);
            Run(app, config);
        }

        protected abstract void Run(IApplicationBuilder app, IConfiguration configuration);
    }
}

讀取配置類赶袄,也獨(dú)立了出來,可支持讀取appsettings.json抠藕,每個(gè)站點(diǎn)需要把a(bǔ)ppsettings.json設(shè)置允許復(fù)制饿肺,不然會(huì)找不到文件!盾似!

namespace Demo.ZipkinCommon
{
    public class ConfigureSettings
    {
        public static IConfiguration CreateConfiguration()
        {
            var builder = new ConfigurationBuilder()
                .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                .AddEnvironmentVariables();

            return builder.Build();
        }
    }
}

公用部分完成了敬辣。我們看看站點(diǎn)Demo.ZipKinWeb代碼。Startup繼承抽象類CommonStartup零院,并利用.netCore內(nèi)置依賴注入溉跃,將Service和倉(cāng)儲(chǔ)注入進(jìn)來。由于不支持直接注入泛型告抄,但支持type類型的注入撰茎,間接也解決了泛型注入問題。關(guān)于依賴注入的講解打洼,你可以參考上篇文中依賴注入部分龄糊,加深理解。

namespace Demo.ZipKinWeb
{
    public class Startup : CommonStartup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public override void ConfigureServices(IServiceCollection services)
        {
            services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });

            services.AddScoped(typeof(IRepository<>), typeof(BaseRepository<>));
            services.AddScoped<IUserService, UserService>();
            services.AddScoped<IAddressService, AddressService>();
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
        }
        protected override void Run(IApplicationBuilder app, IConfiguration configuration)
        {

            app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseCookiePolicy();

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
        }

    }
}

為了實(shí)現(xiàn)聚合兩個(gè)站點(diǎn)的效果募疮,在Add的方法內(nèi)炫惩,特意調(diào)用一下另外個(gè)站點(diǎn)的get

 [HttpPost]
        public IActionResult Add([FromBody]User user)
        {
            _userService.AddUser(user);

            //模擬調(diào)用其他站點(diǎn)請(qǐng)求。
            var client = new RestClient($"{ConfigEx.WebSite}");
            var request = new RestRequest($"/user/get", Method.POST);
            request.AddParameter("id", user.Id); // adds to POST or URL querystring based on Method

            IRestResponse response = client.Execute(request);
            var content = response.Content;
            // return Json(new { data = content });
            return Content(content+_addressService.Test());
        }

建好必要的Controller和Action后酝锅,將兩個(gè)站點(diǎn)都設(shè)為已啟動(dòng)诡必。就可以查看效果了。
postman是個(gè)測(cè)試接口的好工具搔扁,點(diǎn)擊Send爸舒。


postman接口測(cè)試

打開我們的zipkin服務(wù)器鏈接,在WebUI上稿蹲,可以看到兩條請(qǐng)求數(shù)據(jù)扭勉。這是正確的,一條是Add,里面又調(diào)了另外一個(gè)站點(diǎn)的get,也能看到消耗的時(shí)間苛聘。


image.png

點(diǎn)擊去查看詳情涂炎,我們能看到更多數(shù)據(jù)。

請(qǐng)求詳情

然后繼續(xù)點(diǎn)擊 菜單中的Dependencies设哗,確發(fā)現(xiàn)是空值唱捣,按道理來講,請(qǐng)求了兩個(gè)站點(diǎn)网梢,又訪問了數(shù)據(jù)庫震缭。怎么會(huì)是空值呢?战虏?拣宰?
依賴

這個(gè)時(shí)候党涕,我只能又求助bing了。

zipkin Dependencies no data

果然網(wǎng)友是萬能的巡社。elasticsearch存儲(chǔ),zipkin依賴沒有數(shù)據(jù)
里面有位外國(guó)同仁提到了

當(dāng)你用你elasticsearch 或 Cassandra的時(shí)候膛堤,需要執(zhí)行zipkin-dependencies
(you need to run https://github.com/openzipkin/zipkin-dependencies when using elasticsearch or Cassandra)

zipkin-dependencies簡(jiǎn)介

這是一個(gè)Spark作業(yè),它將從您的數(shù)據(jù)存儲(chǔ)區(qū)收集跨度晌该,分析服務(wù)之間的鏈接肥荔,并存儲(chǔ)它們以供以后在Web UI中呈現(xiàn)(例如http://localhost:8080/dependency)。
什么是Spark?
Apache Spark 是專為大規(guī)模數(shù)據(jù)處理而設(shè)計(jì)的快速通用的計(jì)算引擎气笙。

此作業(yè)以UTC時(shí)間分析當(dāng)天的所有跟蹤次企。這意味著您應(yīng)該將其安排在UTC午夜之前運(yùn)行。

支持所有Zipkin 存儲(chǔ)組件潜圃,包括Cassandra缸棵,MySQL和Elasticsearch。

這真是一個(gè)弱雞的設(shè)計(jì)谭期,作為內(nèi)存運(yùn)行的演示堵第,竟然不提供及時(shí)匯總分析,還要跑定時(shí)任務(wù)
依據(jù)官方提示隧出,按最快的方式進(jìn)行踏志。

wget -O zipkin-dependencies.jar 'https://search.maven.org/remote_content?g=io.zipkin.dependencies&a=zipkin-dependencies&v=LATEST'
STORAGE_TYPE=cassandra3 java -jar zipkin-dependencies.jar

或者用Docker啟動(dòng)

docker run --env STORAGE_TYPE=cassandra3 --env CASSANDRA_CONTACT_POINTS=host1,host2 openzipkin/zipkin-dependencies

用法

默認(rèn)情況下,此作業(yè)解析自UTC午夜以來的所有跟蹤胀瞪。您可以通過YYYY-mm-dd格式的參數(shù)解析不同日期的跟蹤针余,如2016-07-16。

# ex to run the job to process yesterday's traces on OS/X
STORAGE_TYPE=cassandra3 java -jar zipkin-dependencies.jar `date -uv-1d +%F`
# or on Linux
STORAGE_TYPE=cassandra3 java -jar zipkin-dependencies.jar `date -u -d '1 day ago' +%F`

執(zhí)行失敗

STORAGE_TYPE=cassandra3 java -jar zipkin-dependencies.jar `date -u -d '1 day ago' +%F`
18/09/14 20:24:50 INFO CassandraDependenciesJob: Running Dependencies job for 2018-09-13: 1536796800000000 ≤ Span.timestamp 1536883199999999
18/09/14 20:24:50 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
18/09/14 20:24:51 ERROR SparkContext: Error initializing SparkContext.
java.lang.IllegalArgumentException: System memory 466288640 must be at least 471859200. Please increase heap size using the --driver-memory option or spark.driver.memory in Spark configuration.
    at org.apache.spark.memory.UnifiedMemoryManager$.getMaxMemory(UnifiedMemoryManager.scala:217)
    at org.apache.spark.memory.UnifiedMemoryManager$.apply(UnifiedMemoryManager.scala:199)
    at org.apache.spark.SparkEnv$.create(SparkEnv.scala:330)
    at org.apache.spark.SparkEnv$.createDriverEnv(SparkEnv.scala:175)
    at org.apache.spark.SparkContext.createSparkEnv(SparkContext.scala:256)
    at org.apache.spark.SparkContext.<init>(SparkContext.scala:423)
    at zipkin2.dependencies.cassandra3.CassandraDependenciesJob.run(CassandraDependenciesJob.java:181)
    at zipkin2.dependencies.ZipkinDependenciesJob.main(ZipkinDependenciesJob.java:57)
Exception in thread "main" java.lang.IllegalArgumentException: System memory 466288640 must be at least 471859200. Please increase heap size using the --driver-memory option or spark.driver.memory in Spark configuration.
    at org.apache.spark.memory.UnifiedMemoryManager$.getMaxMemory(UnifiedMemoryManager.scala:217)
    at org.apache.spark.memory.UnifiedMemoryManager$.apply(UnifiedMemoryManager.scala:199)
    at org.apache.spark.SparkEnv$.create(SparkEnv.scala:330)
    at org.apache.spark.SparkEnv$.createDriverEnv(SparkEnv.scala:175)
    at org.apache.spark.SparkContext.createSparkEnv(SparkContext.scala:256)
    at org.apache.spark.SparkContext.<init>(SparkContext.scala:423)
    at zipkin2.dependencies.cassandra3.CassandraDependenciesJob.run(CassandraDependenciesJob.java:181)
    at zipkin2.dependencies.ZipkinDependenciesJob.main(ZipkinDependenciesJob.java:57)

意思是系統(tǒng)內(nèi)存太小了凄诞。圆雁。。渣渣帆谍。
搜索到相關(guān)鏈接伪朽,如下:
Zipkin 使用api調(diào)用沒有數(shù)據(jù) Zipkin api traces為空
Zinkin進(jìn)階篇-Zipkin-dependencies的應(yīng)用

zipkin提供的接口標(biāo)準(zhǔn)
spark內(nèi)存介紹
更簡(jiǎn)易的格式顯示內(nèi)存錯(cuò)誤信息

ERROR SparkContext: Error initializing SparkContext.

System memory..must be at least ... Please use a larger heap

spark 內(nèi)存管理
如何設(shè)置spark.executor.memory和堆大小

Spark Misconceptions
如何在Eclispe環(huán)境中設(shè)置spark的堆大小汛蝙?

里面似乎有個(gè)有用的答案

您可以通過編輯“{SPARK_HOME} / conf /”中的“spark-defaults.conf”文件來設(shè)置“spark.driver.memory”選項(xiàng)烈涮。默認(rèn)情況下,沒有名為“spark-defaults.conf”的文件窖剑。目錄為“ {SPARK_HOME} / conf /”坚洽,但是有一個(gè)文件“spark-defaults.conf.template”,您可以使用以下命令創(chuàng)建“spark-defaults.conf”文件:

cp spark-defaults.conf.template spark-defaults.conf
然后西土,編輯它:

# Example:
# spark.master                     spark://master:7077
# spark.eventLog.enabled           true
# spark.eventLog.dir               hdfs://namenode:8021/directory
# spark.serializer                 org.apache.spark.serializer.KryoSerializer
# spark.driver.memory              5g
# spark.executor.extraJavaOptions  -XX:+PrintGCDetails -Dkey=value -Dnumbers="one two three"


spark.driver.memory      

但我沒查到SPARK_HOME的環(huán)境變量讶舰。
Linux下設(shè)置和查看環(huán)境變量
繼續(xù)調(diào)整工作重心。
java.lang.IllegalArgumentException:系統(tǒng)內(nèi)存
里面作者或網(wǎng)友提到:

gc是可選的JAVA_OPTS=-verbose:gc -Xms1G -Xmx1G,https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html#BABDJJFI

JAVA_OPTS的一些介紹

JAVA_OPTS設(shè)置
談一談JVM內(nèi)存JAVA_OPTS參數(shù)
Tomcat之——內(nèi)存溢出設(shè)置JAVA_OPTS
JAVA_OPTS參數(shù)說明與配置

Linux下vi查找關(guān)鍵字

按照以上操作修改仍未成功。绘雁。。有某位仁兄知道處理辦法援所,可否告知庐舟?

罷了,罷了住拭,不留個(gè)尾巴挪略,怎么能引起我的求知欲。原本只是想簡(jiǎn)簡(jiǎn)單單看看zipkin,卻邁向了Spark,JVM之路滔岳,留個(gè)問題待以后深思杠娱。

下篇將繼續(xù)zipkin熟悉之路,持久化mysql,還有今天未結(jié)束的主題谱煤,zipkin-dependencies

總結(jié)

標(biāo)題是.NetCore,大部分是在找java問題摊求,我也是醉了。沒辦法用的監(jiān)控是java開源的刘离,不要抱怨室叉,繼續(xù)研究。這應(yīng)該是個(gè)小問題硫惕。這就是寫博客擴(kuò)展的學(xué)習(xí)范圍茧痕,原本不在我的計(jì)劃之類。堅(jiān)持就有收獲恼除,至少我現(xiàn)在知道了Spark的一些介紹踪旷,jvm的一些參數(shù)。

感謝觀看豁辉,本篇結(jié)束令野。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市秋忙,隨后出現(xiàn)的幾起案子彩掐,更是在濱河造成了極大的恐慌,老刑警劉巖灰追,帶你破解...
    沈念sama閱讀 216,692評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件堵幽,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡弹澎,警方通過查閱死者的電腦和手機(jī)朴下,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來苦蒿,“玉大人殴胧,你說我怎么就攤上這事。” “怎么了团滥?”我有些...
    開封第一講書人閱讀 162,995評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵竿屹,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我灸姊,道長(zhǎng)拱燃,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,223評(píng)論 1 292
  • 正文 為了忘掉前任力惯,我火速辦了婚禮碗誉,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘父晶。我一直安慰自己哮缺,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,245評(píng)論 6 388
  • 文/花漫 我一把揭開白布甲喝。 她就那樣靜靜地躺著尝苇,像睡著了一般。 火紅的嫁衣襯著肌膚如雪埠胖。 梳的紋絲不亂的頭發(fā)上茎匠,一...
    開封第一講書人閱讀 51,208評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音押袍,去河邊找鬼诵冒。 笑死,一個(gè)胖子當(dāng)著我的面吹牛谊惭,可吹牛的內(nèi)容都是我干的汽馋。 我是一名探鬼主播,決...
    沈念sama閱讀 40,091評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼圈盔,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼豹芯!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起驱敲,我...
    開封第一講書人閱讀 38,929評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤铁蹈,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后众眨,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體握牧,經(jīng)...
    沈念sama閱讀 45,346評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,570評(píng)論 2 333
  • 正文 我和宋清朗相戀三年娩梨,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了沿腰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,739評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡狈定,死狀恐怖颂龙,靈堂內(nèi)的尸體忽然破棺而出习蓬,到底是詐尸還是另有隱情,我是刑警寧澤措嵌,帶...
    沈念sama閱讀 35,437評(píng)論 5 344
  • 正文 年R本政府宣布躲叼,位于F島的核電站,受9級(jí)特大地震影響企巢,放射性物質(zhì)發(fā)生泄漏押赊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,037評(píng)論 3 326
  • 文/蒙蒙 一包斑、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧涕俗,春花似錦罗丰、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,677評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至元镀,卻和暖如春绍填,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背栖疑。 一陣腳步聲響...
    開封第一講書人閱讀 32,833評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工讨永, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人遇革。 一個(gè)月前我還...
    沈念sama閱讀 47,760評(píng)論 2 369
  • 正文 我出身青樓卿闹,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親萝快。 傳聞我的和親對(duì)象是個(gè)殘疾皇子锻霎,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,647評(píng)論 2 354

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