聶永的博客

          記錄工作/學(xué)習(xí)的點(diǎn)點(diǎn)滴滴。

          Tsung筆記之主從資源協(xié)調(diào)篇

          前言

          接著上文,tsung一旦啟動(dòng),主從節(jié)點(diǎn)之間需要協(xié)調(diào)分配資源,完成分布式壓測(cè)任務(wù)。

          如何啟動(dòng)Tsung壓測(cè)從機(jī)

          Erlang SDK提供了從機(jī)啟動(dòng)方式:

          slave:start(Host, Node, Opts)
          

          啟動(dòng)從機(jī)需要借助于免登陸形式遠(yuǎn)程終端,比如SSH(后續(xù)會(huì)討論SSH存在不足,以及全新的替代品),需要自行配置。

          <client host="client_100" maxusers="60000" weight="1">
              <ip value="10.10.10.100"/>
          </client>
          
          • host屬性對(duì)應(yīng)value為從機(jī)主機(jī)名稱:client_100
          • Node節(jié)點(diǎn)名稱由tsung_controller組裝,類似于 tsung10@client_100
          • Opts表示相關(guān)參數(shù)
          • 一個(gè)物理機(jī)器,可以存在多個(gè)tsung從機(jī)實(shí)例
          • 一個(gè)tsung從機(jī)實(shí)例對(duì)應(yīng)一個(gè)tsung client

          簡(jiǎn)單翻譯一下:slave:start(client_100, 'tsung10@client_100', Opts)

          從機(jī)需要關(guān)閉時(shí),就很簡(jiǎn)單了:

          slave:stop(Node)
          

          當(dāng)然若主機(jī)中途掛掉,從機(jī)也會(huì)自動(dòng)自殺掉自身。

          啟動(dòng)tsung client方式

          Tsung主機(jī)啟動(dòng)從機(jī)成功,從機(jī)和主機(jī)就可以Erlang節(jié)點(diǎn)進(jìn)程之間進(jìn)行方法調(diào)用和消息傳遞。潛在要求是,tsung編譯后beam文件能夠在Erlang運(yùn)行時(shí)環(huán)境中能夠訪問到,這個(gè)和Java Classpath一致原理。

          rpc:multicall(RemoteNodes,tsung,start,[],?RPC_TIMEOUT)
          

          到此為止,一個(gè)tsung client實(shí)例成功運(yùn)行。

          • tsung client實(shí)例生命周期結(jié)束,不會(huì)導(dǎo)致從機(jī)實(shí)例主動(dòng)關(guān)閉
          • tsung slave提供了運(yùn)行時(shí)環(huán)境,tsung client是業(yè)務(wù)
          • tsung slave和tsung client關(guān)系是1 : 1關(guān)系,很多時(shí)候?yàn)榱死斫夥奖悖粫?huì)進(jìn)行嚴(yán)格區(qū)分

          壓測(cè)目標(biāo)

          明白了主從啟動(dòng)方式,下面討論壓測(cè)目標(biāo),比如50萬用戶的量,根據(jù)給出的壓測(cè)從機(jī)列表,進(jìn)行任務(wù)分配。

          壓測(cè)目標(biāo)配置

          tsung壓測(cè)xml配置文件,load元素可以配置總體任務(wù)生成的信息。

          <load>
              <arrivalphase phase="1" duration="60" unit="minute">
                  <!--users maxnumber="500000" interarrival="0.004" unit="second"></users-->
                  <users maxnumber="500000" arrivalrate="250" unit="second"></users>
              </arrivalphase>
          </load>
          
          • 定義一個(gè)最終壓力產(chǎn)生可以持續(xù)60分鐘壓測(cè)場(chǎng)景, 上限用戶量為50萬
          • arrivalphase duration屬性持續(xù)時(shí)長(zhǎng)表示生成壓測(cè)用戶可消費(fèi)總體時(shí)間60分鐘,即為T1
          • users元素其屬性表示單位時(shí)間內(nèi)(這里單位時(shí)間為秒)產(chǎn)生用戶數(shù)為250個(gè)
          • 50萬用戶,將在2000秒(約34分鐘)內(nèi)生成,耗時(shí)時(shí)長(zhǎng)即為T2
          • T2小于arrivalphase定義的用戶生成階段持續(xù)時(shí)間T1
          • 若T2時(shí)間后(34分鐘)后因?yàn)楫a(chǎn)生用戶數(shù)已經(jīng)達(dá)到了上限,將不再產(chǎn)生新的用戶,知道整個(gè)壓測(cè)結(jié)束
          • 若 T1 小于 T2,則50萬用戶很難達(dá)到,因此T1時(shí)間要設(shè)置長(zhǎng)一些

          從節(jié)點(diǎn)信息配置

          所說從節(jié)點(diǎn)也是壓測(cè)客戶端,需要配置clients元素:

          <clients>
              <client host="client_100" maxusers="60000" weight="1">
                  <ip value="10.10.10.100"/>
              </client>
          
              ......
          
              <client host="client_109" maxusers="120000" weight="2">
                  <ip value="10.10.10.109"></ip>
                  <ip value="10.10.10.119"></ip>
              </client>
          </clients>
          
          1. 單個(gè)client支持多個(gè)IP,用于突破單個(gè)IP對(duì)外建立連接數(shù)的限制(后續(xù)會(huì)講到)
          2. xml所定義的一個(gè)cliet元素,可能被分裂出若干從機(jī)實(shí)例(即tsung client),1 : N

          根據(jù)CPU數(shù)量分裂tsung client實(shí)例情況

          在《Tsung Documentation》給出了建議,一個(gè)CPU一個(gè)tsung client實(shí)例:

          Note: Even if an Erlang VM is now able to handle several CPUs (erlang SMP), benchmarks shows that it’s more efficient to use one VM per CPU (with SMP disabled) for tsung clients. Only the controller node is using SMP erlang.
          Therefore, cpu should be equal to the number of cores of your nodes. If you prefer to use erlang SMP, add the -s option when starting tsung (and don’t set cpu in the config file).

          • 默認(rèn)策略, 一個(gè)tsung client對(duì)應(yīng)一個(gè)CPU,若不設(shè)置CPU屬性,默認(rèn)值就是1
          • 一個(gè)cpu對(duì)應(yīng)一個(gè)tsung client,N個(gè)CPU,N個(gè)tsung client
          • 共同分擔(dān)權(quán)重,每一個(gè)分裂的tsung client權(quán)重 Weight/N
          • 一旦設(shè)置cpu屬性,無論Tsung啟動(dòng)時(shí)是否攜帶-s參數(shù)設(shè)置共享CPU,都會(huì)
            • 自動(dòng)分裂CPU個(gè)tsung client實(shí)例
            • 每一個(gè)實(shí)例權(quán)重為Weight/CPU
          %% add a new client for each CPU
          lists:duplicate(CPU,#client{host     = Host,
                                      weight   = Weight/CPU,
                                      maxusers = MaxUsers})
          

          若要設(shè)置單個(gè)tsung client實(shí)例共享多個(gè)CPU(此時(shí)不要設(shè)置cpu屬性啦),需要在tsung啟動(dòng)時(shí)添加-s參數(shù),tsung client被啟動(dòng)時(shí),smp屬性被設(shè)置成auto:

          -smp auto +A 8
          

          這樣從機(jī)就只有一個(gè)tsung client實(shí)例了,不會(huì)讓人產(chǎn)生困擾。若是臨時(shí)租借從機(jī),建議啟動(dòng)時(shí)使用-s參數(shù),并且要去除cpu屬性設(shè)置,這樣才能夠自動(dòng)共享所有CPU核心。

          從機(jī)分配用戶過多,一樣會(huì)分裂新的tsung client實(shí)例

          假設(shè)client元素配置maxusers數(shù)量為1K,那么實(shí)際上被分配數(shù)量為10K(壓測(cè)人數(shù)多,壓測(cè)從機(jī)少)時(shí),那么tsung_controller會(huì)繼續(xù)分裂新的tsung client實(shí)例,直到10K用戶數(shù)量完成。

          <client host="client_98" maxusers="1000" weight="1">
              <ip value="10.10.10.98"></ip>
          </client>
          

          tsung client分配的數(shù)量超過自身可服務(wù)上限用戶時(shí)(這里設(shè)置的是1K)時(shí),關(guān)閉自身。

          launcher(_Event, State=#launcher{nusers = 0, phases = [] }) ->
              ?LOG("no more clients to start, stop  ~n",?INFO),
              {stop, normal, State};
          
          launcher(timeout, State=#launcher{nusers        = Users,
                                            phase_nusers  = PhaseUsers,
                                            phases        = Phases,
                                            phase_id      = Id,
                                            started_users = Started,
                                            intensity     = Intensity}) ->
              BeforeLaunch = ?NOW,
              case do_launch({Intensity,State#launcher.myhostname,Id}) of
                  {ok, Wait} ->
                      case check_max_raised(State) of
                          true ->
                              %% let the other beam starts and warns ts_mon
                              timer:sleep(?DIE_DELAY),
                              {stop, normal, State};
                          false->
                              ......
                      end;
                  error ->
                      % retry with the next user, wait randomly a few msec
                      RndWait = random:uniform(?NEXT_AFTER_FAILED_TIMEOUT),
                      {next_state,launcher,State#launcher{nusers = Users-1} , RndWait}
              end.
          

          tsung_controller接收從節(jié)點(diǎn)退出通知,但分配總數(shù)沒有完成,會(huì)啟動(dòng)新的tsung client實(shí)例(一樣先啟動(dòng)從節(jié)點(diǎn),然后再啟動(dòng)tsung client實(shí)例)。整個(gè)過程串行方式循環(huán),直到10K用戶數(shù)量完成:

          %% start a launcher on a new beam with slave module
          handle_cast({newbeam, Host, Arrivals}, State=#state{last_beam_id = NodeId, config=Config, logdir = LogDir}) ->
              Args = set_remote_args(LogDir,Config#config.ports_range),
              Seed = Config#config.seed,
              Node = remote_launcher(Host, NodeId, Args),
              case rpc:call(Node,tsung,start,[],?RPC_TIMEOUT) of
                  {badrpc, Reason} ->
                      ?LOGF("Fail to start tsung on beam ~p, reason: ~p",[Node,Reason], ?ERR),
                      slave:stop(Node),
                      {noreply, State};
                  _ ->
                      ts_launcher_static:stop(Node), % no need for static launcher in this case (already have one)
                      ts_launcher:launch({Node, Arrivals, Seed}),
                      {noreply, State#state{last_beam_id = NodeId+1}}
              end;
          

          tsung client分配用戶數(shù)

          一個(gè)tsung client分配的用戶數(shù),可以理解為會(huì)話任務(wù)數(shù)。Tsung以終端可以模擬的用戶為維度進(jìn)行定義壓測(cè)。

          所有配置tsung client元素(設(shè)置M1)權(quán)重相加之和為總權(quán)重TotalWeight,用戶總數(shù)為MaxMember,一個(gè)tsung client實(shí)例(總數(shù)設(shè)為M2)分配的模擬用戶數(shù)可能為:

          MaxMember*(Weight/TotalWeight)
          

          需要注意:
          - M2 >= M1
          - 若壓測(cè)階段<arrivalphase元素配置duration值過小,小于最終用戶50萬用戶按照每秒250速率耗時(shí)時(shí)間,最終分配用戶數(shù)將小于期望值

          只有一臺(tái)物理機(jī)的tsung master啟動(dòng)方式

          <clients>
            <client host="localhost" use_controller_vm="true"/>
          </clients>
          

          沒有物理從機(jī),主從節(jié)點(diǎn)都在一臺(tái)機(jī)器上,需要設(shè)置use_controller_vm="true"。相比tsung集群,單一節(jié)點(diǎn)tsung啟動(dòng)就很簡(jiǎn)單,主從之間不需要SSH通信,直接內(nèi)部調(diào)用。

          local_launcher([Host],LogDir,Config) ->
              ?LOGF("Start a launcher on the controller beam ~p~n", [Host], ?NOTICE),
              LogDirEnc = encode_filename(LogDir),
              %% set the application spec (read the app file and update some env. var.)
              {ok, {_,_,AppSpec}} = load_app(tsung),
              {value, {env, OldEnv}} = lists:keysearch(env, 1, AppSpec),
              NewEnv = [ {debug_level,?config(debug_level)}, {log_file,LogDirEnc}],
              RepKeyFun = fun(Tuple, List) ->  lists:keyreplace(element(1, Tuple), 1, List, Tuple) end,
              Env = lists:foldl(RepKeyFun, OldEnv, NewEnv),
              NewAppSpec = lists:keyreplace(env, 1, AppSpec, {env, Env}),
          
              ok = application:load({application, tsung, NewAppSpec}),
              case application:start(tsung) of
                  ok ->
                      ?LOG("Application started, activate launcher, ~n", ?INFO),
                      application:set_env(tsung, debug_level, Config#config.loglevel),
                      case Config#config.ports_range of
                          {Min, Max} ->
                              application:set_env(tsung, cport_min, Min),
                              application:set_env(tsung, cport_max, Max);
                          undefined ->
                              ""
                      end,
                      ts_launcher_static:launch({node(), Host, []}),
                      ts_launcher:launch({node(), Host, [], Config#config.seed}),
                      1 ;
                  {error, Reason} ->
                      ?LOGF("Can't start launcher application (reason: ~p) ! Aborting!~n",[Reason],?EMERG),
                      {error, Reason}
              end.
          

          用戶生成控制

          用戶和會(huì)話控制

          每一個(gè)tsung client運(yùn)行著一個(gè)ts_launch/ts_launch_static本地注冊(cè)模塊,掌控終端模擬用戶生成和會(huì)話控制。

          • 向主節(jié)點(diǎn)ts_config_server請(qǐng)求隸屬于當(dāng)前從機(jī)節(jié)點(diǎn)的會(huì)話信息
          • 啟動(dòng)模擬終端用戶ts_client
          • 控制下一個(gè)模擬終端用戶ts_client需要等待時(shí)間,也是控制從機(jī)用戶生成速度
          • 執(zhí)行是否需要切換到新的階段會(huì)話
          • 控制模擬終端用戶是否已經(jīng)達(dá)到了設(shè)置的maxusers上限
            • 到上限,自身使命完成,關(guān)閉自身
          • 源碼位于 tsung-1.6.0/src/tsung 目錄下

          主機(jī)按照xml配置生成全局用戶產(chǎn)生速率,從機(jī)按照自身權(quán)重分配的速率進(jìn)行單獨(dú)控制,這也是任務(wù)分解的具體呈現(xiàn)。

          用戶生成速度控制

          在Tsung中用戶生成速度稱之為強(qiáng)度,根據(jù)所配置的load屬性進(jìn)行配置

          <load>
              <arrivalphase phase="1" duration="60" unit="minute">
                  <users maxnumber="500000" arrivalrate="250" unit="second"></users>
              </arrivalphase>
          </load>
          

          關(guān)鍵屬性:

          • interarrival,生成壓測(cè)用戶的時(shí)間間隔
          • arrivalrate:?jiǎn)挝粫r(shí)間內(nèi)生成用戶數(shù)量
          • 兩者最終都會(huì)被轉(zhuǎn)換為生成用戶強(qiáng)度系數(shù)值是0.25
          • 這個(gè)是總的強(qiáng)度值,但需要被各個(gè)tsung client分解
          parse(Element = #xmlElement{name=users, attributes=Attrs},
                Conf = #config{arrivalphases=[CurA | AList]}) ->
          
              Max = getAttr(integer,Attrs, maxnumber, infinity),
              ?LOGF("Maximum number of users ~p~n",[Max],?INFO),
          
              Unit  = getAttr(string,Attrs, unit, "second"),
              Intensity = case {getAttr(float_or_integer,Attrs, interarrival),
                                getAttr(float_or_integer,Attrs, arrivalrate)  } of
                              {[],[]} ->
                                  exit({invalid_xml,"arrival or interarrival must be specified"});
                              {[], Rate}  when Rate > 0 ->
                                  Rate / to_milliseconds(Unit,1);
                              {InterArrival,[]} when InterArrival > 0 ->
                                  1/to_milliseconds(Unit,InterArrival);
                              {_Value, _Value2} ->
                                  exit({invalid_xml,"arrivalrate and interarrival can't be defined simultaneously"})
                          end,
              lists:foldl(fun parse/2,
                  Conf#config{arrivalphases = [CurA#arrivalphase{maxnumber = Max,
                                                                  intensity=Intensity}
                                         |AList]},
                          Element#xmlElement.content);
          

          tsung_controller對(duì)每一個(gè)tsung client生成用戶強(qiáng)度分解為 ClientIntensity = PhaseIntensity * Weight / TotalWeight,而1000 * ClientIntensity就是易讀的每秒生成用戶速率值。

          get_client_cfg(Arrival=#arrivalphase{duration = Duration,
                                               intensity= PhaseIntensity,
                                               curnumber= CurNumber,
                                               maxnumber= MaxNumber },
                         {TotalWeight,Client,IsLast} ) ->
              Weight = Client#client.weight,
              ClientIntensity = PhaseIntensity * Weight / TotalWeight,
              NUsers = round(case MaxNumber of
                                 infinity -> %% only use the duration to set the number of users
                                     Duration * ClientIntensity;
                                 _ ->
                                     TmpMax = case {IsLast,CurNumber == MaxNumber} of
                                                  {true,_} ->
                                                      MaxNumber-CurNumber;
                                                  {false,true} ->
                                                      0;
                                                  {false,false} ->
                                                      lists:max([1,trunc(MaxNumber * Weight / TotalWeight)])
                                              end,
                                     lists:min([TmpMax, Duration*ClientIntensity])
                             end),
              ?LOGF("New arrival phase ~p for client ~p (last ? ~p): will start ~p users~n",
                    [Arrival#arrivalphase.phase,Client#client.host, IsLast,NUsers],?NOTICE),
              {Arrival#arrivalphase{curnumber=CurNumber+NUsers}, {ClientIntensity, NUsers, Duration}}.
          

          前面講到每一個(gè)tsung client被分配用戶數(shù)公式為:min(Duration * ClientIntensity, MaxNumber * Weight / TotalWeight)

          • 避免總?cè)藬?shù)超出限制
          • 階段Phase持續(xù)時(shí)長(zhǎng)所產(chǎn)生用戶數(shù)和tsung client分配用戶數(shù)不至于產(chǎn)生沖突,一種協(xié)調(diào)策略

          再看一下launch加載一個(gè)終端用戶時(shí),會(huì)自動(dòng)根據(jù)當(dāng)前分配用戶生成壓力系數(shù)獲得ts_stats:exponential(Intensity)下一個(gè)模擬用戶產(chǎn)生等待生成的最長(zhǎng)時(shí)間,單位為毫秒。

          do_launch({Intensity, MyHostName, PhaseId})->
              %%Get one client
              %%set the profile of the client
              case catch ts_config_server:get_next_session({MyHostName, PhaseId} ) of
                  {'EXIT', {timeout, _ }} ->
                      ?LOG("get_next_session failed (timeout), skip this session !~n", ?ERR),
                      ts_mon:add({ count, error_next_session }),
                      error;
                  {ok, Session} ->
                      ts_client_sup:start_child(Session),
                      X = ts_stats:exponential(Intensity),
                      ?DebugF("client launched, wait ~p ms before launching next client~n",[X]),
                      {ok, X};
                  Error ->
                      ?LOGF("get_next_session failed for unexpected reason [~p], abort !~n", [Error],?ERR),
                      ts_mon:add({ count, error_next_session }),
                      exit(shutdown)
              end.
          

          ts_stats:exponential邏輯引入了指數(shù)計(jì)算:

          exponential(Param) ->
              -math:log(random:uniform())/Param.
          

          繼續(xù)往下看吧,隱藏了部分無關(guān)代碼:

          launcher(timeout, State=#launcher{nusers        = Users,
                                            phase_nusers  = PhaseUsers,
                                            phases        = Phases,
                                            phase_id      = Id,
                                            started_users = Started,
                                            intensity     = Intensity}) ->
              BeforeLaunch = ?NOW,
              case do_launch({Intensity,State#launcher.myhostname,Id}) of
                  {ok, Wait} ->
                                      ...
                                  {continue} ->
                                      Now=?NOW,
                                      LaunchDuration = ts_utils:elapsed(BeforeLaunch, Now),
                                      %% to keep the rate of new users as expected,
                                      %% remove the time to launch a client to the next
                                      %% wait.
                                      NewWait = case Wait > LaunchDuration of
                                                    true -> trunc(Wait - LaunchDuration);
                                                    false -> 0
                                                end,
                                      ?DebugF("Real Wait = ~p (was ~p)~n", [NewWait,Wait]),
                                      {next_state,launcher,State#launcher{nusers = Users-1, started_users=Started+1} , NewWait}
                                      ...
                  error ->
                      % retry with the next user, wait randomly a few msec
                      RndWait = random:uniform(?NEXT_AFTER_FAILED_TIMEOUT),
                      {next_state,launcher,State#launcher{nusers = Users-1} , RndWait}
              end.
          

          下一個(gè)用戶生成需要等待Wait - LaunchDuration毫秒時(shí)間。

          給出一個(gè)采樣數(shù)據(jù),只有一個(gè)從機(jī),并且用戶產(chǎn)生速度1秒一個(gè),共產(chǎn)生10個(gè)用戶:

          <load>
              <arrivalphase phase="1" duration="50" unit="minute">
                  <users maxnumber="10" interarrival="1" unit="second"/>
              </arrivalphase>
          </load>
          

          采集日志部分,記錄了Wait時(shí)間值,其實(shí)總體時(shí)間還需要加上LaunchDuration(雖然這個(gè)值很小):

          ts_launcher:(7:<0.63.0>) client launched, wait 678.5670934164623 ms before launching next client
          ts_launcher:(7:<0.63.0>) client launched, wait 810.2982455546687 ms before launching next client
          ts_launcher:(7:<0.63.0>) client launched, wait 1469.2208436232288 ms before launching next client
          ts_launcher:(7:<0.63.0>) client launched, wait 986.7202548184069 ms before launching next client
          ts_launcher:(7:<0.63.0>) client launched, wait 180.7484423006169 ms before launching next client
          ts_launcher:(7:<0.63.0>) client launched, wait 1018.9190235965457 ms before launching next client
          ts_launcher:(7:<0.63.0>) client launched, wait 1685.0156394273606 ms before launching next client
          ts_launcher:(7:<0.63.0>) client launched, wait 408.53992361334065 ms before launching next client
          ts_launcher:(7:<0.63.0>) client launched, wait 204.40900996137086 ms before launching next client
          ts_launcher:(7:<0.63.0>) client launched, wait 804.6040921461512 ms before launching next client
          

          總體來說,每一個(gè)用戶生成間隔間不是固定值,是一個(gè)大約值,有偏差,但接近于目標(biāo)設(shè)定(1000毫秒生成一個(gè)用戶標(biāo)準(zhǔn)間隔)。

          執(zhí)行模擬終端用戶會(huì)話流程

          關(guān)于會(huì)話的說明:

          • 一個(gè)session元素中的定義一系列請(qǐng)求-響應(yīng)等交互行為稱之為一次完整會(huì)話
          • 一個(gè)模擬用戶需要執(zhí)行一次完整會(huì)話,然后生命周期完成,然后結(jié)束

          模擬終端用戶模塊是ts_client(狀態(tài)機(jī)),掛載在ts_client_sup下,由ts_launcher/ts_launcher_static調(diào)用ts_client_sup:start_child(Session)啟動(dòng),是壓測(cè)任務(wù)的最終執(zhí)行者,承包了所有臟累差的活:

          • 所有下一步需要執(zhí)行的會(huì)話指令都需要向主機(jī)的ts_config_server請(qǐng)求
          • 執(zhí)行會(huì)話指令
          • 具體協(xié)議調(diào)用相應(yīng)協(xié)議插件,比如ts_mqtt組裝會(huì)話消息
          • 建立網(wǎng)絡(luò)Socket連接,封裝眾多網(wǎng)絡(luò)通道
          • 發(fā)送請(qǐng)求數(shù)據(jù),處理響應(yīng)
          • 記錄并發(fā)送監(jiān)控?cái)?shù)據(jù)和日志

          ts_client?

          小結(jié)

          簡(jiǎn)單梳理主從之間啟動(dòng)方式,從機(jī)數(shù)量分配策略,以具體壓測(cè)任務(wù)如何在從機(jī)上分配和運(yùn)行等內(nèi)容。

          posted on 2016-07-25 14:02 nieyong 閱讀(2628) 評(píng)論(1)  編輯  收藏 所屬分類: 壓測(cè)

          評(píng)論

          # re: Tsung筆記之主從資源協(xié)調(diào)篇 2016-07-26 17:28 yjj

          這么棒的博必須頂下!  回復(fù)  更多評(píng)論   

          公告

          所有文章皆為原創(chuàng),若轉(zhuǎn)載請(qǐng)標(biāo)明出處,謝謝~

          新浪微博,歡迎關(guān)注:

          導(dǎo)航

          <2016年7月>
          262728293012
          3456789
          10111213141516
          17181920212223
          24252627282930
          31123456

          統(tǒng)計(jì)

          常用鏈接

          留言簿(58)

          隨筆分類(130)

          隨筆檔案(151)

          個(gè)人收藏

          最新隨筆

          搜索

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 阿克苏市| 海安县| 晋州市| 潢川县| 美姑县| 广水市| 思茅市| 五大连池市| 仲巴县| 和林格尔县| 江西省| 泰顺县| 木兰县| 蛟河市| 麦盖提县| 改则县| 聂拉木县| 蓝山县| 宁化县| 正镶白旗| 读书| 新野县| 怀来县| 钦州市| SHOW| 桃江县| 湘阴县| 九江县| 克拉玛依市| 巴中市| 和顺县| 潍坊市| 南丹县| 伽师县| 铁岭县| 牡丹江市| 上思县| 营山县| 蓬溪县| 温宿县| 错那县|