经过本系列前几篇文字的分析和设计,我们成功地开发出了自己的SDK服务端。在我们自己的调试环境下运行一切正常,但是当然我们不能就这样把这套SDK服务端部署上线到正式生产环境,稍有正式大型项目经验的同学应该都知道性能优化以及部署上线相关设计对于服务端项目的重要性。我们到目前为止的分析设计中,并没有考虑到这些设计。那么,针对我们SDK服务端这样的应用场景,应该着重关注哪些相关的优化和设计呢?
数据存取优化
在我们的应用场景中,需要使用到存储的场景主要在以下几个处理中:
l 获取配置信息
对每个收到的请求,处理时都需要根据其来源游戏渠道等各种信息,获取到对应的配置信息,再作处理。配置信息访问频率相当频繁,但基本是只读的,处理过程中并不会对其进行修改。
l 存取订单信息
对支付产生的订单消息,服务端对其处理包括创建订单,查询订单和修改订单状态等等,对数据的处理包括储存和读取,两种操作频率基本相当。
l 保存日志信息
对收到的请求及产生的错误,服务端需要作保存日志的动作,这一动作属于纯写入操作,操作频率较高。
针对这几种数据,我们的处理策略也不相同:
对配置信息这样的频繁访问,又变化较小的数据,为了尽量加快访问速度,我们通常会选择将其存入内存。但是如果将配置信息以配置文件的方式保存,则又无法灵活管理。考虑到更进一步的动态加载配置需求,这里我们可以使用内存缓存的方式存取。即应用程序启动时从外部存储(DB)中读取配置,保存在内存中待调用,定期通过检查更新标志的方式更新配置。
订单信息属于重要的结构化信息,无疑应该保存在DB中。但是回顾一下前几篇文字中分析的支付到帐请求流程,可以发现,该流程对我们的处理效率提出了相当高的要求。如果我们不能在尽可能短的时间内,完成整个查询对比发货流程,就会导致渠道判定游戏服务端处理超时,从而触发渠道的订单重发机制。最糟糕的情况下,前一次处理过程还没有结束,渠道的后一次重发请求又到了,就会导致系统的处理效率急速下降乃至崩溃。因此,我们需要为订单建立一个缓存,为DB承担查询压力。在这方面,市面常见的缓存产品如Redis Memcache等都可以胜任该需求,具体设计这里就不再赘述。
日志信息属于只写不读的信息。如果将所有的日志都存入DB,无疑在空间和效率上都会不必要的消耗DB的性能。我们一般选择将日志以文件的形式存储。另外,这一写入操作必须使用异步形式处理,否则会大幅降低性能。关于异步处理,后文会进一步说明。
异步处理
任何可以晚点做的事情都应该晚点再做,异步处理正是基于这一原则来实施的。具体到我们的服务端设计上,我们可以总结出以下逻辑可以设计成为异步操作。
l 所有记录日志操作
l 大多数对DB的写入操作(包括修改订单状态/保存订单信息等)
读取操作则通常是一个同步操作,我们无法要求一个查询订单的请求“先返回一个已收到查询请求的信息,随后再异步提供查询结果”。
l 发货流程中,与游戏服务端通信的HTTP请求操作。
这里实际上异步操作由SDK端或由游戏端来实现均可达到我们的目的,但是还是由游戏服务端来实现更为合理。
具体的异步实现方式,由于开发语言及工具的实现各有不同,这里也不再详细讨论。
集群部署
在网站高并发访问的场景下,使用负载均衡技术为一个应用构建一个由多台服务器组成的服务器集群,将并发访问请求分发到多台服务器上处理,避免单一服务器因负载压力过大而响应缓慢,使用户请求具有更好的响应延迟特性。
使用集群部署和负载均衡技术的场合下,要求我们的应用在设计时也需要注意并发处理的技术细节,例如重复请求过滤,事务化处理逻辑等设计。原则上注意考虑多台服务端同时处理时带来的这些问题即可。
代码优化
之所以把代码优化的部分放在最后,是因为这部分无非是一些老生常谈的东西,相信读者每个人都处理过类似的优化工作。包括连接池资源复用,数据结构优化,利用垃圾回收机制等等。这里就需要读者自己根据所使用的开发工具和语言来实际操作了。
服务端设计的思路和架构系列文字,到本篇为止就告一段落,之后我们会用几篇文字和代码实际讲解如何具体实现本系列文字设计出的服务端。以及如何解决实际编码中遇到的设计问题。并在实际解决问题的过程中再进一步讨论更加深入的优化手段。
这个项目已开源,大家有兴趣可以自己研究或者参照项目编写自己的聚合SDK
项目地址:https://code.csdn.net/typesdk_code
项目地址:https://github.com/typesdk