External Shuffle Service 引起的NodeManager OOM問題分析

1 現(xiàn)象描述及初步分析

近期公司yarn集群中存在NodeManager因OOM 而掛掉的情況, 且發(fā)生OOM前存在大量的Spark Shuffle Services相關(guān)信息, 通過分析最近Crash的NodeManager進(jìn)程的dump信息發(fā)現(xiàn)存在大量的Finalizer,占用了大部分分的內(nèi)存資源,其中dump分析結(jié)果如下所示:


Dominator tree

Finalizer對(duì)象數(shù)量分析

附:NodeManager日志信息
java.lang.OutOfMemoryError: GC overhead limit exceeded

通過dump分析可知滨砍,OOM原因?yàn)椋篎ileInputStream引發(fā)的Finalizer對(duì)象堆集所致。

該對(duì)象為Shuffle Server在處理Shuffle Client數(shù)據(jù)請(qǐng)求時(shí)所創(chuàng)建捌省。 其中包含如下代碼部分(Spark1.6):

 /**
     * Sort-based shuffle data uses an index called "shuffle_ShuffleId_MapId_0.index" into a data file
     * called "shuffle_ShuffleId_MapId_0.data". This logic is from IndexShuffleBlockResolver,
     * and the block id format is from ShuffleDataBlockId and ShuffleIndexBlockId.
     */
    private ManagedBuffer getSortBasedShuffleBlockData(
            ExecutorShuffleInfo executor, int shuffleId, int mapId, int reduceId) {
        File indexFile = getFile(executor.localDirs, executor.subDirsPerLocalDir,
                "shuffle_" + shuffleId + "_" + mapId + "_0.index");

        DataInputStream in = null;
        try {
            in = new DataInputStream(new FileInputStream(indexFile));
            in.skipBytes(reduceId * 8);
            long offset = in.readLong();
            long nextOffset = in.readLong();
            return new FileSegmentManagedBuffer(
                    conf,
                    getFile(executor.localDirs, executor.subDirsPerLocalDir,
                            "shuffle_" + shuffleId + "_" + mapId + "_0.data"),
                    offset,
                    nextOffset - offset);
        } catch (IOException e) {
            throw new RuntimeException("Failed to open file: " + indexFile, e);
        } finally {
            if (in != null) {
                JavaUtils.closeQuietly(in);
            }
        }
    }


其中 創(chuàng)建FileInputStream的作用是為了拿到索引文件中的數(shù)據(jù)偏移量及文件長(zhǎng)度,用于讀取數(shù)據(jù)。(備注:讀取shuffle數(shù)據(jù)時(shí)也會(huì)創(chuàng)建FileInputStream對(duì)象,上述代碼供獻(xiàn)1/2的對(duì)象數(shù)量佑钾。)并且,該實(shí)現(xiàn)中每次數(shù)據(jù)請(qǐng)求都會(huì)創(chuàng)建一個(gè)FileInputStream對(duì)象用于讀取索引文件烦粒。

2 存在大量FileInputStream相關(guān)Fanalizer的原因

其FileInputStream自定義了finalize()方法,因此JVM會(huì)為每一個(gè)FileInputStream對(duì)象創(chuàng)建一個(gè)Finalizer引用對(duì)象,用于確保FileInputStream最終處理關(guān)閉狀態(tài)代赁。

    /**
     * Cleans up the connection to the file, and ensures that the
     * <code>close</code> method of this file output stream is
     * called when there are no more references to this stream.
     *
     * @exception  IOException  if an I/O error occurs.
     * @see        java.io.FileInputStream#close()
     */
    protected void finalize() throws IOException {
        if (fd != null) {
            if (fd == FileDescriptor.out || fd == FileDescriptor.err) {
                flush();
            } else {

                /*
                 * Finalizer should not release the FileDescriptor if another
                 * stream is still using it. If the user directly invokes
                 * close() then the FileDescriptor is also released.
                 */
                runningFinalize.set(Boolean.TRUE);
                try {
                    close();
                } finally {
                    runningFinalize.set(Boolean.FALSE);
                }
            }
        }
    }

所有的Finalizer組成一個(gè)雙向鏈表扰她,其共同維護(hù)一個(gè)ReferenceQueue,進(jìn)入隊(duì)列中的對(duì)象可以被gc回收芭碍。

同時(shí)徒役,JVM中存在一個(gè)守護(hù)線程:FinalizerThread 其優(yōu)先級(jí)為 8,用于從雙向鏈表中清除進(jìn)入ReferenceQueue中的Finalizer窖壕,以便在下次GC時(shí)回收這部分Finalizer忧勿。

資源充足的情況下,F(xiàn)inalizerThread線程可以被調(diào)度執(zhí)行瞻讽,從而ReferenceQueue中的Finalizer會(huì)很快被清理掉鸳吸,從而在GC時(shí)釋放占用內(nèi)存。

而在External Shuffle Services 場(chǎng)景中 Shuffle Server作為NodeManager進(jìn)程中的daemon線程執(zhí)行速勇,并且其創(chuàng)建了大量提供數(shù)據(jù)服務(wù) 的shuffle-server服務(wù)線程(數(shù)量默認(rèn)為NodeManager管理的cores * 2, 因此配制最低的機(jī)型擁有48個(gè)線程)晌砾, 該線程優(yōu)先級(jí)為5.

經(jīng)過上述分析,我們可知NodeManager中有

  • 一個(gè)消費(fèi)Finalizer的FinalizerThread線程烦磁,優(yōu)先級(jí)為8
  • 48 個(gè)用于生產(chǎn)Finalizer的shuffle-server線程养匈,優(yōu)先級(jí)為5
  • 其它大量線程(如Thread-7872425匿名線程等),此處不一一給出
    "Thread-7872425" #8190511 prio=5 os_prio=0 tid=0x00007f1aa8d51000 nid=0xc671 runnable [0x00007f1a83435000]
    java.lang.Thread.State: RUNNABLE
        at java.io.FileInputStream.readBytes(Native Method)
        at java.io.FileInputStream.read(FileInputStream.java:255)
    

在Java中線程優(yōu)先級(jí)的范圍是:1-10都伪,且數(shù)字越大優(yōu)先級(jí)越高呕乎,線程優(yōu)先級(jí)高僅僅表示線程獲取的 CPU時(shí)間片的幾率高。然而陨晶,由于shuffle-server線程數(shù)量較多猬仁,當(dāng)Shuffle Client端請(qǐng)求頻繁(大量reduce任務(wù)Fetch數(shù)據(jù))時(shí),shuffle-server線程被調(diào)度的機(jī)率會(huì)比Finalizer線程大,這會(huì)導(dǎo)致shuffle-server線程生產(chǎn)Finalizer的速率遠(yuǎn)大于FinalizerTread線程清理的速率逐虚,從而導(dǎo)致Finalizer堆集聋溜。

3 實(shí)驗(yàn)復(fù)現(xiàn)方案

其于如前所述的原因分析:Client端請(qǐng)求頻繁時(shí),會(huì)導(dǎo)致shuffle-server線程生產(chǎn)Finalizer的速率遠(yuǎn)大于FinalizerTread線程清理的速率叭爱,會(huì)導(dǎo)致Finalizer堆集撮躁。因此,可增加部分節(jié)點(diǎn)的shuffle-server線程买雾,使用問題更易復(fù)現(xiàn)把曼。

  • 調(diào)整實(shí)驗(yàn)集群中一個(gè)節(jié)點(diǎn)的NodeManager管理的Cores的數(shù)量
    操作方法:
    yarn.nodemanager.resource.cpu-vcore = 80 <更大的值>
    或 
    spark.shuffle.io.serverThreads=160
    

備注: 該問題會(huì)出現(xiàn)在Shuffle fetch密集的場(chǎng)景(即分布式任務(wù)并發(fā)度高的場(chǎng)景)。

3.1 模擬實(shí)驗(yàn)

復(fù)現(xiàn)方案中提出以調(diào)參的方式增加服務(wù)線程數(shù)量漓穿,從而增加shuffle-server線程被調(diào)度的機(jī)率嗤军。但復(fù)現(xiàn)的前提是要造出大量的密集的Fetch請(qǐng)求,然而晃危,目前測(cè)試集群規(guī)模無法與生產(chǎn)環(huán)境相提并論叙赚,不易造出上述場(chǎng)景;而且僚饭,用戶應(yīng)用負(fù)載及數(shù)據(jù)的獲取不易震叮。因此,進(jìn)行以下實(shí)驗(yàn)?zāi)M真實(shí)環(huán)境的執(zhí)行情況鳍鸵。

3.1.1 實(shí)驗(yàn)

  • 實(shí)驗(yàn)一
    50個(gè)線程創(chuàng)建FileInputStream

  • 實(shí)驗(yàn)二
    100個(gè)線程創(chuàng)建FileInputStream

    上述實(shí)驗(yàn)苇瓣,采用Java 8,采用JVM默認(rèn)配制偿乖,并在相同的節(jié)點(diǎn)中進(jìn)行击罪。

3.1.2 結(jié)果

  • 實(shí)驗(yàn)一
    Full GC時(shí),ParOldGen(老年代)可以正程靶剑回收媳禁。
  • 實(shí)驗(yàn)二
    Full GC時(shí),ParOldGen(老年代)幾乎不能回收,從而引發(fā)如下異常:
Exception in thread "shuffle-server-5" java.lang.OutOfMemoryError: GC overhead limit exceeded

異常發(fā)生時(shí)画切,Java Heap信息:

Heap
 PSYoungGen      total 465920K, used 226578K [0x0000000795580000, 0x00000007c0000000, 0x00000007c0000000)
  eden space 232960K, 97% used [0x0000000795580000,0x00000007a32c4bb0,0x00000007a3900000)
  from space 232960K, 0% used [0x00000007b1c80000,0x00000007b1c80000,0x00000007c0000000)
  to   space 232960K, 0% used [0x00000007a3900000,0x00000007a3900000,0x00000007b1c80000)
 ParOldGen       total 1398272K, used 1397883K [0x0000000740000000, 0x0000000795580000, 0x0000000795580000)
  object space 1398272K, 99% used [0x0000000740000000,0x000000079551ee20,0x0000000795580000)
 Metaspace       used 2718K, capacity 4486K, committed 4864K, reserved 1056768K
  class space    used 291K, capacity 386K, committed 512K, reserved 1048576K

3.1.3 實(shí)驗(yàn)結(jié)果分析

上述實(shí)驗(yàn)唯一區(qū)別為線程數(shù)量不同损话,即FileInputStream的生產(chǎn)線程與Finalizer線程競(jìng)爭(zhēng)執(zhí)行資源的激烈程度不同。

實(shí)驗(yàn)一 由于線程數(shù)量較少槽唾,競(jìng)爭(zhēng)激烈程度低丧枪,F(xiàn)inalizerThread線程可以被調(diào)度執(zhí)行,從而可以從Finalizer鏈表中清除無引用的對(duì)象庞萍,進(jìn)而在GC時(shí)回收掉Finalizer.

實(shí)驗(yàn)二 線程數(shù)量較大拧烦,競(jìng)爭(zhēng)激烈程度高,F(xiàn)inalizerThread線程被調(diào)度的機(jī)會(huì)少钝计,從而Finalizer鏈表(雙向鏈表)中的對(duì)象無法被回收恋博,只能在Heap的 from 區(qū) 及 to 區(qū)進(jìn)行拷貝齐佳,多個(gè)回合后進(jìn)入old區(qū)(老年代)。當(dāng)FinalizerThread持續(xù)被阻塞時(shí)债沮,就會(huì)發(fā)生Finalizer堆滿old區(qū)的情況炼吴。由于Finalizer對(duì)象在一個(gè)雙向鏈表中相互引用,F(xiàn)ull GC 依然會(huì)無法回收疫衩,最終會(huì)引發(fā):“java.lang.OutOfMemoryError: GC overhead limit exceeded”硅蹦。

在真實(shí)的NodeManager中,除了存在shuffle-server線程外闷煤,還存在大量其它大量線程(有些線程也會(huì)產(chǎn)生FileInputStream)童芹。在負(fù)載較高時(shí),這些線程都會(huì)與FinalizerThread發(fā)生競(jìng)爭(zhēng)鲤拿,從而降低FinalizerThread執(zhí)行的機(jī)率假褪。

  • 附1:GC overhead limit exceeded發(fā)生的原因

This message means that for some reason the garbage collector is taking an excessive amount of time (by default 98% of all CPU time of the process) and recovers very little memory in each run (by default 2% of the heap)

  • 附2:實(shí)驗(yàn)過程中jstack快照
"shuffle-server-28" #37 prio=5 os_prio=31 tid=0x00007faea901f000 nid=0x8503 waiting for monitor entry [0x000070000e6e7000]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at java.lang.ref.Finalizer.add(Finalizer.java:51)
    "- waiting to lock <0x000000074127c070> (a java.lang.Object)"
    at java.lang.ref.Finalizer.<init>(Finalizer.java:82)
    at java.lang.ref.Finalizer.register(Finalizer.java:87)
    at java.lang.Object.<init>(Object.java:37)
    at java.io.InputStream.<init>(InputStream.java:45)
    at java.io.FileInputStream.<init>(FileInputStream.java:123)
    at java.io.FileInputStream.<init>(FileInputStream.java:93)
    at TestThread.run(Test.java:32)
    
    
"shuffle-server-26" #35 prio=5 os_prio=31 tid=0x00007faea88c9800 nid=0x8103 waiting for monitor entry [0x000070000e4e1000]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at java.lang.ref.Finalizer.add(Finalizer.java:51)
    "- waiting to lock <0x000000074127c070> (a java.lang.Object)"
    at java.lang.ref.Finalizer.<init>(Finalizer.java:82)
    at java.lang.ref.Finalizer.register(Finalizer.java:87)
    at java.lang.Object.<init>(Object.java:37)
    at java.io.InputStream.<init>(InputStream.java:45)
    at java.io.FileInputStream.<init>(FileInputStream.java:123)
    at java.io.FileInputStream.<init>(FileInputStream.java:93)
    at TestThread.run(Test.java:32)
    
    ......
    
"Finalizer" #3 daemon prio=8 os_prio=31 tid=0x00007faeaa00d800 nid=0x3103 waiting for monitor entry [0x000070000c37e000]
   java.lang.Thread.State: BLOCKED (on object monitor)
    at java.lang.ref.Finalizer.remove(Finalizer.java:61)
    "- waiting to lock <0x000000074127c070> (a java.lang.Object)"
    at java.lang.ref.Finalizer.runFinalizer(Finalizer.java:93)
    - locked <0x00000007bacfba70> (a java.lang.ref.Finalizer)
    at java.lang.ref.Finalizer.access$100(Finalizer.java:34)
    at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:210)

4 結(jié)論

通過上述分析及實(shí)驗(yàn)可知,NodeManager發(fā)生OOM的主要原因?yàn)椋浩鋬?nèi)部線程生產(chǎn)Finalizer的速率大于FinalizerTread線程清理的速率近顷,從而使Finalizer鏈表(雙向鏈表)中無法回收的對(duì)象生音,只能在Heap的 from 區(qū) 及 to 區(qū)進(jìn)行拷貝,多個(gè)回合后進(jìn)入old區(qū)(老年代)窒升。當(dāng)FinalizerThread持續(xù)被阻塞時(shí)久锥,就會(huì)發(fā)生Finalizer堆滿old區(qū)的情況,由于Finalizer對(duì)象在一個(gè)雙向鏈表中相互引用异剥,F(xiàn)ull GC依然會(huì)無法回收,最終會(huì)引發(fā):“java.lang.OutOfMemoryError: GC overhead limit exceeded”絮重。

5 擬解決方案

shuffle-server線程存在為獲取得Shuffle IndexFile中reduce任務(wù)對(duì)應(yīng)數(shù)據(jù)的偏移量及數(shù)據(jù)長(zhǎng)度而創(chuàng)建FileInputStream的情況冤寿,且原有方案中每次獲取都重新打開一次文件,即創(chuàng)建一個(gè)FileInputStream對(duì)象青伤。 因此督怜,可以引入緩存機(jī)制減少讀取該文件的次數(shù)。

  1. 引入緩存機(jī)制減少讀取該文件的次數(shù)狠角。

    一個(gè)IndexFile中包含一個(gè)APP在該節(jié)點(diǎn)中的所有數(shù)據(jù)索引号杠,因此引入緩存具有
    較大收益。

    Spark-15074中已引入緩存特性丰歌,且#SPARK-21501對(duì)緩存方案進(jìn)行了完善姨蟋,
    因此可merge官方feature 達(dá)到緩解問題的目的。
    缺點(diǎn):緩存只能涵蓋讀取IndexFile時(shí)產(chǎn)生FileInputStream的場(chǎng)景立帖,僅覆蓋
    Shuffle Server中1/2的FileInputStream對(duì)象眼溶。

除此之外,還可以使用以下方式進(jìn)行調(diào)整:

  1. 使用Files NIO替換FileInputStream
    因?yàn)樵搯栴}主要是FileInputStream中實(shí)現(xiàn)了finalize()方法所置晓勇。
    缺點(diǎn):不能減少文件頻繁讀寫的開銷, 對(duì)Netty等的影響暫無法評(píng)估堂飞。

  2. 減少shuffle-server線程數(shù)量灌旧,降低FileInputStream產(chǎn)生速率,通過參數(shù)io.serverThreads調(diào)整绰筛。
    缺點(diǎn):機(jī)型較多枢泰,一種配制可能不能滿足三種機(jī)型, 且不合適的配制可能影響作業(yè)的執(zhí)行效率,目前缺少數(shù)據(jù)支撐铝噩。

綜上所述:為將風(fēng)險(xiǎn)降至最低衡蚂,可以先嘗試 1 或1、3結(jié)合的方案薄榛。最后嘗試1讳窟、2結(jié)合方案(事實(shí)證明1、2結(jié)合可以有效解決問題)敞恋。

文獻(xiàn):http://www.oracle.com/technetwork/java/javamail/finalization-137655.html 中提到Finalizer產(chǎn)生的原因及一些處理辦法丽啡。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市硬猫,隨后出現(xiàn)的幾起案子补箍,更是在濱河造成了極大的恐慌,老刑警劉巖啸蜜,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件坑雅,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡衬横,警方通過查閱死者的電腦和手機(jī)裹粤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蜂林,“玉大人遥诉,你說我怎么就攤上這事≡胄穑” “怎么了矮锈?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)睁蕾。 經(jīng)常有香客問我苞笨,道長(zhǎng),這世上最難降的妖魔是什么子眶? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任瀑凝,我火速辦了婚禮,結(jié)果婚禮上臭杰,老公的妹妹穿的比我還像新娘猜丹。我一直安慰自己,他們只是感情好硅卢,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布射窒。 她就那樣靜靜地躺著藏杖,像睡著了一般。 火紅的嫁衣襯著肌膚如雪脉顿。 梳的紋絲不亂的頭發(fā)上蝌麸,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音艾疟,去河邊找鬼来吩。 笑死,一個(gè)胖子當(dāng)著我的面吹牛蔽莱,可吹牛的內(nèi)容都是我干的弟疆。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼盗冷,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼怠苔!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起仪糖,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤柑司,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后锅劝,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體攒驰,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年故爵,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了玻粪。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡诬垂,死狀恐怖劲室,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情剥纷,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布呢铆,位于F島的核電站晦鞋,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏棺克。R本人自食惡果不足惜悠垛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望娜谊。 院中可真熱鬧确买,春花似錦、人聲如沸纱皆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至搀缠,卻和暖如春铛楣,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背艺普。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國打工簸州, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人歧譬。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓岸浑,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親瑰步。 傳聞我的和親對(duì)象是個(gè)殘疾皇子矢洲,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

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

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法面氓,內(nèi)部類的語法兵钮,繼承相關(guān)的語法,異常的語法舌界,線程的語...
    子非魚_t_閱讀 31,581評(píng)論 18 399
  • 從三月份找實(shí)習(xí)到現(xiàn)在掘譬,面了一些公司,掛了不少呻拌,但最終還是拿到小米葱轩、百度、阿里藐握、京東靴拱、新浪、CVTE猾普、樂視家的研發(fā)崗...
    時(shí)芥藍(lán)閱讀 42,184評(píng)論 11 349
  • 原文閱讀 前言 這段時(shí)間懈怠了袜炕,罪過! 最近看到有同事也開始用上了微信公眾號(hào)寫博客了初家,挺好的~給他們點(diǎn)贊偎窘,這博客我...
    碼農(nóng)戲碼閱讀 5,948評(píng)論 2 31
  • (一)Java部分 1、列舉出JAVA中6個(gè)比較常用的包【天威誠信面試題】 【參考答案】 java.lang;ja...
    獨(dú)云閱讀 7,071評(píng)論 0 62
  • 想辦法像滿足情人一樣,對(duì)待你的工作和生活掖肋,這種感覺就會(huì)很美妙仆葡。 生活上,總會(huì)遇到這樣那樣的問題志笼,比如和父母和愛人的...
    小琴晴閱讀 307評(píng)論 0 2