`
阿尔萨斯
  • 浏览: 4106886 次
社区版块
存档分类
最新评论

网络游戏性能测试一步曲:如何规划游戏产品性能测试(草稿)

 
阅读更多
<iframe align="center" marginwidth="0" marginheight="0" src="http://www.zealware.com/csdnblog336280.html" frameborder="0" width="336" scrolling="no" height="280"></iframe>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type"> <meta content="Word.Document" name="ProgId"> <meta content="Microsoft Word 11" name="Generator"> <meta content="Microsoft Word 11" name="Originator"> <link href="file:///C:/DOCUME~1/ADMINI~1.B27/LOCALS~1/Temp/msohtml1/01/clip_filelist.xml" rel="File-List"> <link href="file:///C:/DOCUME~1/ADMINI~1.B27/LOCALS~1/Temp/msohtml1/01/clip_editdata.mso" rel="Edit-Time-Data"> <!--[if !mso]><style>v/:* {behavior:url(#default#VML);}o/:* {behavior:url(#default#VML);}w/:* {behavior:url(#default#VML);}.shape {behavior:url(#default#VML);}</style><![endif]--><smarttagtype name="chmetcnv" namespaceuri="urn:schemas-microsoft-com:office:smarttags"></smarttagtype><!--[if gte mso 9]><xml><w:WordDocument><w:View>Normal</w:View><w:Zoom>0</w:Zoom><w:PunctuationKerning /><w:DrawingGridVerticalSpacing>7.8 磅</w:DrawingGridVerticalSpacing><w:DisplayHorizontalDrawingGridEvery>0</w:DisplayHorizontalDrawingGridEvery><w:DisplayVerticalDrawingGridEvery>2</w:DisplayVerticalDrawingGridEvery><w:ValidateAgainstSchemas /><w:SaveIfXMLInvalid>false</w:SaveIfXMLInvalid><w:IgnoreMixedContent>false</w:IgnoreMixedContent><w:AlwaysShowPlaceholderText>false</w:AlwaysShowPlaceholderText><w:Compatibility><w:SpaceForUL /><w:BalanceSingleByteDoubleByteWidth /><w:DoNotLeaveBackslashAlone /><w:ULTrailSpace /><w:DoNotExpandShiftReturn /><w:AdjustLineHeightInTable /><w:BreakWrappedTables /><w:SnapToGridInCell /><w:WrapTextWithPunct /><w:UseAsianBreakRules /><w:DontGrowAutofit /><w:UseFELayout /></w:Compatibility><w:BrowserLevel>MicrosoftInternetExplorer4</w:BrowserLevel></w:WordDocument></xml><![endif]--><!--[if gte mso 9]><xml><w:LatentStyles DefLockedState="false" LatentStyleCount="156"></w:LatentStyles></xml><![endif]--><!--[if !mso]><objectclassid="clsid:38481807-CA0E-42D2-BF39-B33AF135CC4D" id=ieooui></object><style>st1/:*{behavior:url(#ieooui) }</style><![endif]--><style type="text/css"><!-- /* Font Definitions */ @font-face {font-family:宋体; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-alt:SimSun; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;}@font-face {font-family:"Lucida Console"; panose-1:2 11 6 9 4 5 4 2 2 4; mso-font-charset:0; mso-generic-font-family:modern; mso-font-pitch:fixed; mso-font-signature:-2147482993 6144 0 0 31 0;}@font-face {font-family:"/@宋体"; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-parent:""; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; mso-pagination:none; font-size:10.5pt; mso-bidi-font-size:12.0pt; font-family:"Times New Roman"; mso-fareast-font-family:宋体; mso-font-kerning:1.0pt;} /* Page Definitions */ @page {mso-page-border-surround-header:no; mso-page-border-surround-footer:no;}@page Section1 {size:612.0pt 792.0pt; margin:72.0pt 90.0pt 72.0pt 90.0pt; mso-header-margin:36.0pt; mso-footer-margin:36.0pt; mso-paper-source:0;}div.Section1 {page:Section1;} /* List Definitions */ @list l0 {mso-list-id:234053461; mso-list-type:hybrid; mso-list-template-ids:719878502 67698703 67698713 67698715 67698703 67698713 67698715 67698703 67698713 67698715;}@list l0:level1 {mso-level-tab-stop:84.0pt; mso-level-number-position:left; margin-left:84.0pt; text-indent:-21.0pt;}@list l1 {mso-list-id:364214825; mso-list-type:hybrid; mso-list-template-ids:1925771092 67698703 67698713 67698715 67698703 67698713 67698715 67698703 67698713 67698715;}@list l1:level1 {mso-level-tab-stop:21.0pt; mso-level-number-position:left; margin-left:21.0pt; text-indent:-21.0pt;}@list l1:level2 {mso-level-number-format:alpha-lower; mso-level-text:"%2/)"; mso-level-tab-stop:42.0pt; mso-level-number-position:left; margin-left:42.0pt; text-indent:-21.0pt;}@list l1:level3 {mso-level-number-format:roman-lower; mso-level-tab-stop:63.0pt; mso-level-number-position:right; margin-left:63.0pt; text-indent:-21.0pt;}@list l2 {mso-list-id:1039088775; mso-list-type:hybrid; mso-list-template-ids:-2065007962 67698703 67698713 67698715 67698703 67698713 67698715 67698703 67698713 67698715;}@list l2:level1 {mso-level-tab-stop:27.0pt; mso-level-number-position:left; margin-left:27.0pt; text-indent:-21.0pt;}@list l3 {mso-list-id:1563833133; mso-list-type:hybrid; mso-list-template-ids:-1714643386 67698703 67698713 67698715 67698703 67698713 67698715 67698703 67698713 67698715;}@list l3:level1 {mso-level-tab-stop:84.0pt; mso-level-number-position:left; margin-left:84.0pt; text-indent:-21.0pt;}@list l3:level2 {mso-level-number-format:alpha-lower; mso-level-text:"%2/)"; mso-level-tab-stop:105.0pt; mso-level-number-position:left; margin-left:105.0pt; text-indent:-21.0pt;}@list l4 {mso-list-id:1973948706; mso-list-type:hybrid; mso-list-template-ids:256423466 67698703 67698713 -267909320 67698703 67698713 67698715 67698703 67698713 67698715;}@list l4:level1 {mso-level-tab-stop:21.0pt; mso-level-number-position:left; margin-left:21.0pt; text-indent:-21.0pt;}@list l4:level2 {mso-level-number-format:alpha-lower; mso-level-text:"%2/)"; mso-level-tab-stop:42.0pt; mso-level-number-position:left; margin-left:42.0pt; text-indent:-21.0pt;}@list l4:level3 {mso-level-text:%3); mso-level-tab-stop:60.0pt; mso-level-number-position:left; margin-left:60.0pt; text-indent:-18.0pt;}ol {margin-bottom:0cm;}ul {margin-bottom:0cm;}--></style> <!--[if gte mso 10]><style>/* Style Definitions */table.MsoNormalTable{mso-style-name:普通表格;mso-tstyle-rowband-size:0;mso-tstyle-colband-size:0;mso-style-noshow:yes;mso-style-parent:"";mso-padding-alt:0cm 5.4pt 0cm 5.4pt;mso-para-margin:0cm;mso-para-margin-bottom:.0001pt;mso-pagination:widow-orphan;font-size:10.0pt;font-family:"Times New Roman";mso-ansi-language:#0400;mso-fareast-language:#0400;mso-bidi-language:#0400;}table.MsoTableGrid{mso-style-name:网格型;mso-tstyle-rowband-size:0;mso-tstyle-colband-size:0;border:solid windowtext 1.0pt;mso-border-alt:solid windowtext .5pt;mso-padding-alt:0cm 5.4pt 0cm 5.4pt;mso-border-insideh:.5pt solid windowtext;mso-border-insidev:.5pt solid windowtext;mso-para-margin:0cm;mso-para-margin-bottom:.0001pt;text-align:justify;text-justify:inter-ideograph;mso-pagination:none;font-size:10.0pt;font-family:"Times New Roman";mso-ansi-language:#0400;mso-fareast-language:#0400;mso-bidi-language:#0400;}</style><![endif]-->

题记:什么是性能?什么是一个产品性能?什么是一个网络游戏产品的性能?带着这一连串递进式的思索,我们展开今日的话题。首先,我们需要做的是理解这个标题的意思?整理这个字符串的关键字索引,于是我们得到下面这个字典(参考python):

规划=[“如何游戏产品”,“如何性能测试”]

规划.keys=[“如何”]

怎么做、如何做,成为本篇话题的索引。接下来,让我们来分析剩下的一个数组,即我们需要做什么?也是本篇帖子所要讨论的目标所在。

规划.values=[“游戏产品”,“性能测试”]

这个Values包含了两层意思,第一层意思:即是产品;第二层意思:即是侧重产品的规划。

由此,我们深入到下一个话题,即是针对产品的规划,游戏性能亦是如此。很多人发帖子来问我,如何来做一个游戏产品的性能规划。他们所在公司从来没有规划这样的测试内容,但实际产品研发过程中,除了游戏设计初期的测试模型外(姑且,定义为设计测试),游戏持续研发过程很难在涉及相关内容。在开始谈论游戏产品之前,让我们先来看看一些软件产品的特点(以下我只是分析这个产品的特点,若有冒犯之处敬请谅解)

第一款产品:财务报表系统,这是本人在上海实习的第一家公司产品:作为一款财务报表系统,其核心在于复杂的业务报表处理。对于这样系统,我们必须关注以下几个方面:

<!--[if !supportLists]-->1. <!--[endif]-->数据安全性:大数据量传输溢出;修改索引是否导致数据紊乱。

<!--[if !supportLists]-->2. <!--[endif]-->数据一致性:保证大数据量传输条件下,数据的一致性(/)

<!--[if !supportLists]-->3. <!--[endif]-->报表分级查询:数据呈现(分布/异步),是否会导致客户端涌于,数据呈现混乱。(权限树、权限树的展开、数据权限呈现)

<!--[if !supportLists]-->4. <!--[endif]-->数据行为模型:系统登录对象、查询时间(峰值)、系统最大注册人数、系统预测模型(硬件预测、软件预测)

第二款产品OA系统,这是本人毕业后签的第一家公司的产品:作为一款政务的OA系统,其核心在于Work Flow的业务流转。而业务流转驱动的核心在于表单控件数据与需求流程捆绑(业内暂时有两种模式)。对于这样系统,我们必须关注以下几个方面:

<!--[if !supportLists]-->1. <!--[endif]-->数据安全性:复杂表单与业务流程数据传输(附件、表单权限)

<!--[if !supportLists]-->2. <!--[endif]-->数据一致性:保证数据在(//)下的流转的正确性,特别是发文与收文中的附件问题。

<!--[if !supportLists]-->3. <!--[endif]-->数据量查询:数据呈现(分布/异步),是否会导致客户端涌于,数据解析混乱(数据库)

(如:代办公务的呈现时间、业务表单流转的时间、部门和集团权限树展开的时间、中间件处理分发的时间、网络通道及硬件设备延迟等等)

<!--[if !supportLists]-->4. <!--[endif]-->数据行为模型:系统登录对象、权限划分、查询时间(峰值)、查询数据量、表单和控件比例、表单附近大小、系统最大注册用户人数、系统年数据量大小、系统瓶颈预测(软件、硬件两部分)

第三款产品:加入成都金山后本人接触的第一款网络游戏产品:作为一款MMORPG游戏,其核心定位的玩家群体在于XX-XX岁。那么我们首先要了解,这部分人消费习惯和他们的作息时间。金山在这方面处理的很好,给了很多细节数据(当然是策划所用,本人也拿了一部分来研究)。有关网络游戏产品规划的基调,就是从这个模型上展开的。既然,我们去做这样的测试,首先我们应该了解的是产品、产品的特点、产品的定位、产品的对象以及产品对象的需求。在这个大前提下,我们对这样的系统做出以下的规划及需要关注之处。对于游戏产品而言什么才是关键呢?

<!--[if !supportLists]-->1. <!--[endif]-->游戏稳定性:服务器的稳定性(宕机、维护)、客户端的稳定性(操作、宕机、行为)、数据传输稳定性(同步、客户端解析)

<!--[if !supportLists]-->2. <!--[endif]-->系统稳定性:这里特别提到任务系统和活动规划,我们所要关注的,首先是实现(机制特性、程序算法)、次重则是客户端玩家的感受(数据量、峰值点击数、网络带宽消耗等等)。这里,我们又一次提到了用户体验。因为我们知道对于一个游戏产品而言,用户体验是至关重要的。除了游戏性方面,我们的客户唯一能够读懂、能够体味的便是整个系统的框架易用性操作行为和顺畅的消费性体验。它不仅是一个游戏产品的灵魂,也是一个游戏产品的核心基调。因为对于游戏产品而言,所有操作体现在1024*768这样一个狭小的空间中。界面中蕴涵着太多Button、太多框架、太多的下拉界面,有时你甚至以为我们不是在做一个游戏。因为我们所涉及的功能、我们的需求远比一个ERP系统来的复杂,与其说我们是在制造一款游戏产品,不如说我们在构建一个分布式的应用架构来的贴切。以上这些体验,我们所需要关注的不仅是每一层用户感受,可能我们即将要去做的是每个节点返回速度。对于应用产品整体而言,细节的得失与规划,体现了游戏人对于玩家服务的思考与探索。这些优势将是我们建立快乐体验的关键因素,特别是对于一款MMORPG产品而言。

<!--[if !supportLists]-->3. <!--[endif]-->数据量查询:这里特别提到排名算法、家族系统(和一些即时性数据交互系统)。对于即时的数据交换部分,这里举个例子:对于一个家族系统而言其核心的内容在于玩家对于家族的贡献程度,而对于这部分的设计要求上来看,我们需要它是即时的计算并反馈到其它客户端上。由此,这种数据交互过程就不是简单的同步响应请求,而是一种异步传输机制。与Ajax一样,我们需要程序的反应时间与处理效率是高效而稳定的,因为我们最终目的是保证目标用户能够舒适的体验服务,而不是打开客户端死等那些该死的数据。那么这样的需求,我们应该怎样来规划性能测试呢?首先是模型的算法,这个算法会记录程序模型的处理效率的物理时间(这里,我们姑且定义为一个基线时间)。根据模型需求标准进行模拟,如果这个模型时间是可以接受的(假设的行为:如插入一个队列并排序的有效时间是3)。则我们以此作为数据基线,但是我们要知道有关这个时间的问题,这并不是客户端感受的体验。作为性能测试的另一部分是提供更好数据片段,帮助程序组进行需求改进与定位。所以这里我们需要更佳关注的是客户端的呈现时间,而这个时间的计算必须依靠我们对客户行为数据的分析和建模。在之后的文章中,我会抽专题来介绍,这个业务模型的建模方法和数据评估方式。

<!--[if !supportLists]-->4. <!--[endif]-->数据行为模型:针对游戏产品的玩家行为模型范畴太大了,这里仅仅是对相关性能需求部分一些数据简单的列举一下:

<!--[if !supportLists]-->a) <!--[endif]-->登录行为:登录模型反应了服务器在一个阶段的压力大小与资源分配情况。同时,在一定程度上反应了客户端玩家体验和流畅度反馈。首先,我们必须明确一个概念,即什么是对服务器的压力?我们认为玩家登录行为对服务器的压力一般可以分为两个部分,第一是短期的,第二是持续的。而对于登录行为这样的操作,对于ERP系统或者其它企业应用系统而言,它的特点可能是短期+持续的一个过程。那么对于一个游戏产品而言呢?我们首先要明确的是整个过程的执行周期,它到底有多长?它的行为特点是什么?它的请求分为哪几个部分?登录过程需要请求哪些数据资源?请求断开和重链接这样操作过程需要消耗多大的代价?这些都是我们需要考虑的,单纯的业务模型仅仅是一个简单的登录操作。而作为一个性能测试模型,我们不仅仅需了解是结构、设计过程、实现机制、功能需求,更需要关注的是一个业务整体的关联因素。这里需要强调的是,与软件产品一样,游戏产品也存在最大峰值在线、最大在线人数、最佳在线人数、最大并发人数、最佳并发人数等。这里展示一个阶段性游戏人数的抽象模型:

<!--[if gte vml 1]><v:shapetypeid="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t"path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"><v:stroke joinstyle="miter" /><v:formulas><v:f eqn="if lineDrawn pixelLineWidth 0" /><v:f eqn="sum @0 1 0" /><v:f eqn="sum 0 0 @1" /><v:f eqn="prod @2 1 2" /><v:f eqn="prod @3 21600 pixelWidth" /><v:f eqn="prod @3 21600 pixelHeight" /><v:f eqn="sum @0 0 1" /><v:f eqn="prod @6 1 2" /><v:f eqn="prod @7 21600 pixelWidth" /><v:f eqn="sum @8 21600 0" /><v:f eqn="prod @7 21600 pixelHeight" /><v:f eqn="sum @10 21600 0" /></v:formulas><v:path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect" /><o:lock v:ext="edit" aspectratio="t" /></v:shapetype><v:shape id="_x0000_i1026" type="#_x0000_t75" style='width:314.25pt;height:222pt'><v:imagedata src="file:///C:/DOCUME~1/ADMINI~1.B27/LOCALS~1/Temp/msohtml1/01/clip_image001.png"o:title="" /></v:shape><![endif]--><!--[if !vml]--><!--[endif]-->

<!--[if !supportLists]-->b) <!--[endif]-->业务行为:与软件系统相同,业务行为是整个软件产品的核心部分。游戏产品的业务行为相对而言更加复杂,包含的行为特色也更加多样。这里,不得不又提到金山在这方面的优势,日志系统详细记录了玩家行为的抽象部分。我们从容的分析这些业务数据,便可以很直观的知道玩家日常行为模型。这个部分的测试,我们从规划上分成两个部分,一是提供机器的人行为模型需求;二是建立特殊需求的行为性能模型。这里顺带提一下日常行为模型涉及到行为片段,举一些例子:客户登录、行走、跑步、聊天、明暗Trace点,飞行(gm指令)、简单的数据包等。那么有了简单这些行为模型,我们需要控制哪些条件尝试预测服务器的版本性能呢?这里,简单的讲一些,当然不说所有的细节(传说是算商业机密的)。比如:发包这个操作,我们模拟操作的目的是什么呢?我们从产品的结构上来看,发包过程相当于玩家数据通过正常的业务逻辑行为,请求Web Service或者中间件的过程。当然,这个被抽象的部分,远比我所描述的复杂。但是从产品架构上看,我们还是可以把游戏产品的架构模型,看作一个分离较好的MVC。这样看来,问题简单了。我们把中间件前的数据看作输入部分而通过中间件分离的数据看作是输出部分。我们所需要关注的性能变成为几个过程时间总和,第一个过程为数据请求部分、第二个过程为数据处理部分、第三个部分为数据响应部分。当然,这里是可以细化的,总的来说可以细化到6个过程。好,话题转回来,这个业务底层发包行为就相当于加入逻辑处理的insert的过程,除了数据层的传输以外,综合的这部分处理间正是我们需要关注的。而另一部分,相对于特殊需求的测试,我们如何来提取这部分的行为模型呢?首先,您需要清楚与了解的部分仍然是,什么是我们需要的数据?玩家行为特点?这些行为关系哪些数据?业务逻辑与程序逻辑等。举个例子:假设游戏近期推出一个杀Boss的活动,预计在每晚900-1000的时间,提供服务器所有40级以上玩家,进入战斗区域。进入战斗区域的条件:1.需要10个牌子价值量等于<chmetcnv w:st="on" tcsc="0" numbertype="1" negative="False" hasspace="False" sourcevalue="10000" unitname="C"><span lang="EN-US" style="font-family: " lucida console>10000c</span></chmetcnv>2.必须以队伍的形式进入战斗区域;3.玩家的战斗状态和模式。首先,我们来看第一个准备条件,其关键字为“40”“10”“10000”。这里我们需要关注的对象是牌子的获取途径及玩家的需求等级,这里需要提到的是有关牌子的一个规划:系统产出与系统上限,针对牌子的获取途径以及玩家的需求等级,我们可以推论出本次活动大致的参加人数。其次,我们来分析第二个判断条件,以队伍形式进入战斗区域?队伍形式,我们做出以下推想,计算8人为最大收益团队,则这一点我们可以知道参加活动可能的队伍数量(最大人数/8)。但是这里,我们需要指出的是,当前的数据只是我们的假想的数据基础。根据实际的业务模型,我们做了以下这个表:

等级超过

40级的玩家

拥有10

个牌子的玩家

预计任务人数

预计队伍数

修正值(0.7)

600

50%

300()

37()

25()

由上表我们可以得到25*8=200人,将参与到这个任务游戏中。

下面我们需要根据这个任务的地图模型,来设计我们的测试案例(以下我们虚拟了一个地图模型)

<!--[if gte vml 1]><v:shapeid="_x0000_i1025" type="#_x0000_t75" style='width:297pt;height:172.5pt'><v:imagedata src="file:///C:/DOCUME~1/ADMINI~1.B27/LOCALS~1/Temp/msohtml1/01/clip_image003.jpg"o:title="地图怪物分布" /></v:shape><![endif]--><!--[if !vml]-->请输入大于10个字符的资源描述请输入大于10个字符的资源描述<!--[endif]-->

我们根据地图模型怪物摆放区域,规划5个不同的区域玩家人数。由此,来模拟这个活动性能数据。其次,怪物的数量是我们关心的下个话题。除了游戏玩家以外,造成服务器压力的因素,决定于两个方面:

<!--[if !supportLists]-->1. <!--[endif]-->怪物的数量-预测和瓶颈计算

<!--[if !supportLists]-->2. <!--[endif]-->刷怪的频度-控制死亡和重生的时间

针对以上两个方面因素,首先,我需要考虑的问题是服务器所能承受的最大瓶颈人数、刷挂时间、刷挂的频率;第二层,在满足最大瓶颈条件下,我们需要游戏策划预想的一个设计效果。当然,这个效果是有限度的,除非我们更改一些机制。但这样,也许成本太大了。于是,我们设计以下几组数据进行测试:

<!--[if !supportLists]-->1. <!--[endif]-->第一组数据:

<!--[if !supportLists]-->a) <!--[endif]-->活动人数200人,分布如地图所示。

<!--[if !supportLists]-->b) <!--[endif]-->怪物数2000,分布如地图所示。

<!--[if !supportLists]-->c) <!--[endif]-->刷挂频度,5(虚拟测试值,怪物死亡时间)

<!--[if !supportLists]-->d) <!--[endif]-->其它压力人数800人,持续加压每30分钟登录100人,外部活跃人数1000人。

<!--[if !supportLists]-->2. <!--[endif]-->第二组数据:

<!--[if !supportLists]-->a) <!--[endif]-->活动人数200人,分布如地图所示。

<!--[if !supportLists]-->b) <!--[endif]-->怪物数1500,分布如地图所示。

<!--[if !supportLists]-->c) <!--[endif]-->刷挂频度,5(虚拟测试值,怪物死亡时间)

<!--[if !supportLists]-->d) <!--[endif]-->其它压力人数800人,持续加压每30分钟登录100人,外部活跃人数1000人。

<!--[if !supportLists]-->3. <!--[endif]-->第三组数据:

<!--[if !supportLists]-->a) <!--[endif]-->活动人数200人,分布如地图所示。

<!--[if !supportLists]-->b) <!--[endif]-->怪物数1000,分布如地图所示。

<!--[if !supportLists]-->c) <!--[endif]-->刷挂频度,5(虚拟测试值,怪物死亡时间)

<!--[if !supportLists]-->d) <!--[endif]-->其它压力人数800人,持续加压每30分钟登录100人,外部活跃人数1000人。

当然,这个模型仅仅是个模拟。实际的测试,可能还需要考虑更多因素,但是有一点我们需要清除,测试仅仅是尽可能模拟玩家的行为操作。它只能反应一些客观规律和现象,它不是万能的。更细致的工作,需要我们通过其它形式测试或者开发手段来解决实际问题。有关更多案例分析,会在专题的版本上进行讨论。


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics