技术优化原则

目录

1. 程序设计时需要考虑的事项

1.1 应用数据层设计时建议使用腾讯云存储解决方案

应用进入产品高峰期,海量用户带来很多设计初期难以想象的访问压力。
大多数开发者最开始直接使用单机MySQL来解决数据层的问题,后来使用Memcached来分担读压力,使用MySQL来进行持久化,后来又使用分布式MemCached和分库分表的MySQL集群方案。
至此系统的可扩展性比较强了,但是开发者需要密切关注应用Cache及DB层容量以根据情况随时进行扩容和数据搬迁等。此时的设备多,维护更加复杂,在数据层耗费了大量的精力。

腾讯根据研发过程中的实际经验,提供了两款高性能、低成本的云存储产品,分别是CMEMCDB,强烈推荐开发者使用:
-CMEM完全兼容memcached协议,CDB兼容MySQL协议,对于开发者来说基本无使用门槛;
-在开发和运营过程中,开发无需关心存储层的数据安全、容错、扩容等问题。

1.2 需要考虑对OpenID和OpenKey做校验

应用接收页面请求时,必须对OpenID和OpenKey做校验,以预防XSS漏洞。
OpenID的校验规则:长度为32的16进制字符串,字符在[0-9A-F]范围内。 开发者必须按照该规则对请求中传来的OpenID进行校验。(根据该规则生成的正则表达式:^([0-9A-F]{32})$)
OpenKey的校验规则:长度为不固定的字符串,不能为空。建议开发者不要检查openkey的长度,也不要在后台存储openkey,否则可能会导致用户无法登录。开发者可调用v3/user/is_login接口对请求中传来的Openkey做登录态校验。

1.3 需要考虑对登录态做校验

进行登录态校验的必要性:
如果应用的代码中没有登录态验证的逻辑:
-由于调用平台的任何后台接口时,平台都会对登录态进行验证,因此不存在用户信息泄漏的问题;
-但是如果应用不调用腾讯平台的任何后台接口(虽然这种情况很少见),则应用本身存在安全隐患。攻击者只要知道用户的OpenID就可以登录该用户添加的任何一个应用,并且以主人态进行操作,攻击者可以利用该漏洞发送垃圾信息。
-如果用户在应用中进行某些需要调用前台接口的操作(例如分享)时,接口判断其登录态失效,会直接返回登录态失效的提示语,这对于用户的体验很不好。因此强烈建议应用程序中包含有登录态校验逻辑,在发现其登录态失效时,及时弹出登录窗口提示用户登录。

进行登录态校验的方法:
用户进入应用时,URL中会带有该用户的OpenID和openkey,这时应用只要调用腾讯的任意后台API,都可以验证用户的登录态是否合法。
但是如果仅仅为了出于验证登录态 目的而去随意调用某一个OpenAPI,则会给后台服务造成很大的压力 。
因此更推荐应用在用户进入应用时通过以下方式进行登录态校验:
(1) 方式1:调用v3/user/get_info 接口来验证登录态。该接口即可验证登录态又可以获取登录用户的信息,1个应用一般都需要获取登录用户的信息,因此调用本接口可一举两得。
(2)方式2:调用专门的登录态校验接口v3/user/is_login

进行登录态校验的逻辑说明 :
(1)用户进入应用,应用获得用户的openid,openkey。
(2)应用按照上述方法,进行用户的登录态校验。
(3)如果登录态失效,则弹出登录弹框让用户登录(需调用fusion2.dialog.relogin接口);
(4)如果登录态有效,应用生成自己的登录态信息写到cookie中。应用自己的登录态可以是用户的openid+timestamp+应用希望的信息的加密串,请千万不要写到qzoneapp.com下,请写到自己的域名下,保证各应用之间不会冲突。
(5)之后所有的应用逻辑都只需要验证cookie中应用自己的登录态;调用平台的接口时还是验证openid,openkey。

1.4 需要考虑100-continue问题

在使用CURL做POST的时候,CURL并不会直接就发起POST请求,而是会分为2步:
(1)发送一个请求,请求头部包含一个“Expect:100-continue”,询问httpserver是否愿意接受数据;
(2)接收到Server返回的100-continue应答以后,把数据POST给httpserver。
(CURL的行为详见RFC2616中的相关描述:http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html#sec8.2.3

腾讯开放平台用来响应OpenAPI请求的httpserver出于性能上的考虑,不支持对100-continue的应答。需要在应用程序中进行处理,否则会导致请求发送失败,调用OpenAPI出错。
腾讯开放平台提供的官方SDK中已经增加了相关处理,因此不会出现该问题。
如果是开发者自己封装SDK,则需要在调用OpenAPI时增加对请求头部中“Expect:100-continue”的处理。以PHP为例:

curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:'));

2. SNS游戏类应用需特别注意的事项

SNS游戏类应用有其特有的特点:
(1)对数据的访问量和更新量都比较高。
(2)更新量占的比重比较大,一段时间内会对同一数据频繁更新。
(3)每个用户的重要数据平均大小比较小。
(4)要求请求的响应速度很高。用户操作门槛很低,如果响应速度慢,用户机就会频繁操作,体验很差,而且容易产生滚雪球效应。
(5)有部分次要数据允许丢失的,有部分次要数据准确性和安全性要求不高。例如:
-对于Feeds等促使好友互动的数据,用户只会关心最近的数据,老的数据可以丢失;
-对于用户比较难感知的周期性的状态数据,例如小偷列表,可偷标识等,对数据的准确性和安全性要求不高。
(6)逻辑比较复杂,同一个逻辑经常要访问多个数据源。

因此,针对SNS游戏类应用,有一些特有的建议优化原则:

2.1 避免使用双写逻辑

对于重要数据避免使用双写逻辑。

双写逻辑的问题在于:

1、数据一致难以得到保证,用户在不同的地方可能看到不同的数值;

2、使对用户的响应速度变长,任何一个数据源出问题都会影响用户操作。 有些应用会通过先写cache在写DB达到数据落地的目的,这是完全不可取的,会导致写请求响应数据很慢,DB成为瓶颈。

2.2 尽量只更新cache数据,采用异步合并落地

对于更新量高的数据只更新cache数据,数据落地尽量采用异步合并落地的方式。

先更新cache,然后积累上一段时间后再异步落地的方式将更新多次的数据写入DB。这样做的优点是:

1、可以保证比较高的用户响应速度;

2、合并一段时间的用户操作异步写入DB,可以减少对DB的更新请求量。这里的难点在于数据安全性的考虑,如果down机后如何恢复用户数据?

-对于DB和Cache之间数据,一段时间的不一致可以采用流水的方式保证数据的完整性。

-同时需要详细的监控,监控DB数据和Cache数据之间的时间差距。如果发现差距过多,考虑是否因为合并时间过短或者落地的数据过多,也可能因为DB的性能确实已经到极限。

3、DB用大内存的设备有利于提高DB的性能。

2.3 放弃用户不关心的数据

SNS Game的内容展示框一般较小,无法展示过老的内容。对于某些数据,用户也只关系最近一段时间的内容。那么可以考虑放弃老的不重要的数据。例如用户互动feeds,用户消费流水,用户行为流水等数据。

2.4 放弃不重要数据的数据安全性

对于某些不重要的数据可以不用考虑落地,不用考虑冷备。这些数据即使丢失用户感知也不明显,并且丢失后也会因为用户的行为快速生成。例如:农场中的小偷列表,已经加入修正逻辑的可偷标识等。

2.5 尽量采用高信息密度的数据存储方式

尽量采用高信息密度的数据存储方式,将访问量和更新量高的数据放到内存cache中提供对外服务。

将访问量高和更新量高的数据数据放到内存cache中提供服务是为了提高响应速度。

采用高密度的存储方式是为了减少内存的开销。例如,二进制或者压缩过的存储方式比JSON或者字符串的存储方式更优,同样大小的内存可以放更多的数据。

2.6 尽量采用高信息密度的协议

数据层的通信协议尽量采用高信息密度的协议。

高信息密度的协议可以减少IDC内部网络流量,同时也会减少CPU网络中断的开销。比较小的通信协议包可以考虑使用UDP协议,这样会使响应更快,性能消耗更小。

2.7 尽量考虑使用UDP协议

对于数据层协议尽量考虑UDP协议,对于用户感知不明显的地方甚至可以考虑不收回响应包。

该原则的使用有3个前提条件:

1. 用户数据的平均大小一般都比较小,所以数据层的协议包一般也比较小,不用考虑UDP分包的问题。

2. 数据层和逻辑层在同一个IDC,网络条件有保证。在这种情况下用UDP消耗性能更小,对用户的响应速度更快。

3. 对于非关键路径上的请求包甚至可以不收回响应。例如:可偷标识,虫草标识等。这些数据即使丢失,用户基本感知不到。

2.8 合理使用混排和批量查询

混排是一种用空间换时间的做法。

混排简单的说就是将某个用户好友的符合某些条件的信息存储在一起,需要的时候一次性得到,以达到减少查询请求量的目的。应用到混排功能的应用有:好友日志,好友心情等。

混排主要的缺点是数据量巨大,对于同一份用户数据可能有多份放置在内存中。因此混排的数据不能是更新很频繁的数据,混排适合更新量不高(或者对好友数据变更不敏感)的数据,每个好友数据量相对较大。

批量查询所有用户的数据分布在少数几台机器上,可以通过很少的几个批量请求就得到所有需要的好友数据。批量查询时每个好友的数据量较小(通常20Byte以下,20*5亿=10GByte,考虑到索引,20G应该可以完成,B5的机器32G),利用很少机器就可以存下数据。在SNS Game中批量查询可以满足很多的场景。

2.9 某些特殊场合需要使用回滚逻辑或者补送逻辑

由于SNS Game的逻辑复杂,很难保证一个逻辑中的所有修改的数据都在一个数据源,这样就会有被刷的危险,例如:

有一个CGI是赠送化肥和种子,化肥和种子在不同的数据源。假如种子的数据源压力过大已经不能服务,那么这个CGI每次先赠送化肥,再赠送种子,然后返回失败(没有设置已经送过的bit)。用户发现失败后继续重试,结果用户获得了很多免费的化肥。

回滚逻辑可以解决上面的问题,保证化肥不会被刷。

此外,也可以考虑使用补送逻辑来解决上面问题。那么对于上面的问题,所采取的流程就是:如果发现用户化肥成功,送种子失败,则告诉用户部分成功,后续补齐(同时设置已送的bit),这时候还需要记录一个bill。有另外一个程序发现有bill时定时重试。

2.10 申请合理数量的域名

对于采用HTTP协议的flash APP,申请合理数量的域名。

域名数过少,可能导致单域名流量过大。

域名过多,DNS解析成本过高,同时crossdomain.xml占用的过多流量。

推荐3-5个域名为宜。

2.11 对于采用TCP协议的flash APP,建议使用443或者80端口

建议在flash里面加入判断逻辑,如果443失败率较高,换80端口。

2.12 静态文件放到CDN上

腾讯云计算平台为hosting模式应用提供了CDN服务,详见:CDN_V2

2.13 按需加载素材

对于素材的加载建议采用按需加载,减少第一次进入游戏的下载时间。

以上信息是否解决您的问题?

Copyright © 1998 - 2017 Tencent. All Rights Reserved.

腾讯公司 版权所有

有问必答 返回顶部