Restful后台系统架构深入分析.docx
- 文档编号:26419193
- 上传时间:2023-06-19
- 格式:DOCX
- 页数:35
- 大小:480.86KB
Restful后台系统架构深入分析.docx
《Restful后台系统架构深入分析.docx》由会员分享,可在线阅读,更多相关《Restful后台系统架构深入分析.docx(35页珍藏版)》请在冰豆网上搜索。
Restful后台系统架构深入分析
APP后台系统架构说明书
编号:
20140804
版本:
V1.0
语言:
中文
文件状态:
草稿
保密级别:
绝密
文件标识:
需求规格说明书
项目名称:
APP_FRAMEWORK
当前版本:
1.0
作者:
罗林
审核:
张尹路
完成日期:
2014年9月
变更记录
日期
版本
变更说明
作者
2014-08-04
1.0
创建
罗林
填表说明:
1.日期:
文档变更的日期。
2.版本:
对应文档的版本号。
3.变更说明:
简单的变更说明。
4.作者:
文档编写与修改者.
目录
第一章概述5
1.1编写目的5
1.2读者对象5
1.3参考文献5
1.4术语与缩写解释5
第二章系统设计6
2.1API设计6
2.1.1Restful设计原则6
2.1.2api的命名6
2.1.3安全性6
2.1.4api返回数据6
2.1.5图片的处理(流媒体)7
2.1.6返回的提示信息7
2.1.7在线api文档和测试8
2.2XMPP服务8
2.2.1Openfire简介9
2.2.2XMPP运用范围9
2.2.3处理多账号同时登陆9
2.2.4一些常用的openfire插件9
2.2.5php的xmpplibrary9
2.2.6个人开发openfire插件10
2.2.7常见问题10
2.3短信、邮件、推送服务10
2.3.1重点10
2.3.2短信10
2.3.3邮件11
2.3.4短信方面11
2.4通讯的安全性11
2.5表情的处理15
2.6LBS服务15
2.7项目管理18
(1)sprint计划会议18
(2)日常开发19
(3)每日例会19
(4)测试和修bug20
(5)sprint评审会议20
(6)sprint回顾会议20
(7)及时反馈20
2.8数据库分表21
2.9动态通知22
2.10数据增量更新23
2.11系统架构28
1.Apns28
2.Email29
3.Coreseek29
4.Redis29
5.Httpsqs29
6.Xmpp29
7.Monitor29
第一章概述
1.1编写目的
本说明书用于明确要后台系统该架构的具体需求,规范的描述出APP后台系统架构要实现的各种功能和所要达到的性能,使用户和软件开发者双方对该软件的初始规定有一个共同的理解,并使之成为整个开发工作的基础。
1.2读者对象
程序员、项目经理。
1.3参考文献
提示:
列出本文档的所有参考文献(可以是非正式出版物),格式如下:
[标识符]作者,文献名称,出版单位(或归属单位),日期
1.4术语与缩写解释
缩写、术语
解释
第二章系统设计
从2011.11月开始接触Android开发,已经两年多了。
接近三年的工作经验却一直徘徊在JavaWeb和Android之间,总是找不到进步的方式。
一直独立开发,在接近一年多app相关的系统架构、api设计,先后在两个创业公司中工作,经历过手机网页端,android客户端,iphone客户端,其中的乐与苦,得与失,仰首问天有谁知?
我觉得是时候来个总结,把相关的技术和心得记录下来。
2.1API设计
2.1.1Restful设计原则
Restful风格:
RESTfu设计原则,它被RoyFelding提出(在他的”基于网络的软件架构“论文中第五章)。
而REST的核心原则是将你的API拆分为逻辑上的资源。
这些资源通过http被操作(GET,POST,PUT,DELETE)。
但现在看,一般的操作只有两种:
GET,POST。
这个设计原则最简单的应用就是根据object而不是页面来设计api。
最开始的时候,app的一个页面需要什么数据,api就返回什么数据。
结果随着app的UI不断改版,需要的数据不断变化,不停地修改api,最后当api的改动会影响以前的版本的时候,只能写一个新的api版本,最后弄得api中有很多_V2,V3这样的标志,恶梦!
后来在网站的重构过程中,就根据object来设计api,但根据object来设计,又有一个问题,一个大object可能包含很多小object,是一个api返回全部小object,还是分为多个api返回?
根据业务和技术,带宽等仔细考虑吧。
2.1.2api的命名
其中一个原则,一看api名字就知道这个api是干啥。
在创业团队中,一般就只有一两个人负责后台,当你要负责几十甚至上百个api,你就知道不能“望名知api”是个什么样的痛苦。
2.1.3安全性
参考【2.3通讯的安全性】。
2.1.4api返回数据
app客户端的语言java和object-c都是强类型语言,所以怎么处理空值显得特别重要,不合理的设计很容易造成app的闪退。
从后台的角度来说,api中返回的数据中,正确值和空值的类型必须一样,举例,用户名的字段是“realname":
"xxx”,如果用户名为空,则应该返回“realname":
""。
如果返回值是一个array,空数据则返回一个空array,绝对禁止null值。
对于客户端,必须用个全局的函数来处理所有api的返回数据,需要有一个机制:
对于某个客户端需要数据,如果api中缺失,客户端自动补上并给予默认值。
这个机制在我们的实践中大大减少了app的闪退。
同时,在数据库设计的时候,一个合理的设计必须是所有字段都有默认值,不应该允许null值。
null在大量的语言和数据库中,会带来无穷的问题。
对于这个数据库设计原则,我以前不太明白,现在经历了一年的api设计后,终于懂得。
如果客户端是php,还有一个问题,php中数组和字典都是array,但在java和object-c中是不一样,这个问题一定要注意。
2.1.5图片的处理(流媒体)
在不同版本的app中,各种不同尺寸的手机中,同一张图片显示的尺寸可能是不一样,如果每次都需要用返回原图,然后在客户端处理,则极大浪费网络资源。
而如果是后台处理好图片才返回,则又是一个挑战,怎么有效保存和裁剪多种图片尺寸呢?
例如,一开始头像只需要返回60*60的尺寸,后来在新的版本需要返回70*70,又出了一个新版本,需要返回80*80,每次增加一个新的尺寸,怎么在数据库上记录下来。
这个问题在一开始做api的时候没考虑,后来不得不用了一个极端的方法,每增加新的图片尺寸,就在数据库中增加一个新的字段,保存并生成新的图片尺寸,结果最后数据库的头像字段有"avatar","avatar_60_60","avatar_70_70","avatar_80_80",这种极度恶虐的设计。
最后,针对图片,我们才用了这样的策略:
a)客户端本地缓存图片,只有没有合适的图片,才去服务器取。
b)当客户端需要某种尺寸的图片,由客户端告诉服务端图片的尺寸,服务端动态生成并缓存起来。
例如,客户端需要图片(则服务器就生成80*80的尺寸并返回。
采用了这样的图片处理机制,数据库中只要有一个字段保存原图就行了,其它尺寸就由客户端告诉服务端动态生成。
以后无论什么尺寸的图片,数据库中都不需要记录,数据库只有原图就行了。
2.1.6返回的提示信息
最科学的情况,服务端只返回信息代码,具体的文字提示由客户端决定。
如果文字信息是由服务端返回,则最起码要区分2种信息:
提示用户的信息,提示客户端程序员的信息。
这两者的区别:
1.提示用户的信息是要在让客户知道的,提示客户端程序员的信息不需要让客户知道的。
2.提示用户的信息文字很友好,客户不需要专业基础一看就知道是什么,提示客户端程序员的信息则很专业,例如告诉客户端少传了哪个参数?
哪个参数有问题等等。
2.1.7在线api文档和测试
我们网站的api在线测试文档,既是一份在线api文档,也是一个在线测试工具,极大方便沟通和测试。
每次客户端程序员觉得某个api有什么问题,我们就是这个在线工具上讨论沟通的。
客户端程序员最喜欢这个玩意了^-^。
上个图解一下馋(这个图是旧版的api,已经弃用了):
负责做这个功能的同事专门写了篇博客详细介绍了这个在线api测试文档,还带有demo:
可以参考网址:
2.2XMPP服务
在app中有时候是需要添加聊天服务,在这里谈谈曾经开发聊天服务的经验:
2.2.1Openfire简介
聊天服务端选的是Openfire,这是一个基于xmpp协议的聊天服务器(XMPP是一种基于XML的协议,它继承了在XML环境中灵活的发展性。
因此,基于XMPP的应用具有超强的可扩展性。
经过扩展以后的XMPP可以通过发送扩展的信息来处理用户的需求,以及在XMPP的顶端建立如内容发布系统和基于地址的服务等应用程序。
而且,XMPP包含了针对服务器端的软件协议,使之能与另一个进行通话,这使得开发者更容易建立客户应用程序或给一个配好系统添加功能。
Gtalk,网易泡泡,Facebook聊天等都是基于xmpp,具有广泛的包容性)。
网页上的聊天,使用的是strophe.js,有一本书《XMPP高级编程:
使用JavaScript和jQueryXMPP高级编程:
使用JavaScript和jQuery》是基于这个strophe.js,里面的例子对于初学xmpp具有极大的参考价值。
2.2.2Xmpp运用范围
xmpp除了可以提供聊天服务,还可以充当消息服务器,例如有什么消息需要推送到客户端却不希望使用推送工具,xmpp也是个选择。
2.2.3处理多账号同时登陆
有时候同一个账号需要在不同的客户端同时登陆服务端,例如,网页端和ios会出现用同一个账号登陆聊天服务器的情况,为了保证两个客户端都能收到聊天消息,需要做下面两个处理:
a.相同的账号需要使用不同的resource,可用时间戳生成,如vim@gmail/1359956556,vim@gmail/1359956777。
b.在后台AdminConsole>ServerManager>SystemProperties中,设置“route.all-resources”为true。
2.2.4一些常用的Openfire插件
Subscription:
官方的描述是这样的:
Automaticallyacceptsorrejectssubsriptionrequests。
一个保存openfire聊天记录的插件,当根据我的使用经验,这个插件是把全部聊天记录保存在一个表中,性能极差,只能勉强应付,法律规定要保存3个月聊天记录这个需求,在实际应用中没啥用。
2.2.5Php的XmppLibrary
如果服务器是使用php,那么能使用的xmpp客户端就只有xmpphp,这个libary只提供了最基本的发送消息功能,很多常用的功能都没有提供,我根据开发经验把一些常用的xmpp功能开发出来,并整合到xmpphp中:
registerNewUser//注册一个新用户
addRosterContact//发送添加好友的请求
acceptfriendrequest//接受好友请求
deleteRosterContact//删除某个好友
roomMessage//发送群聊消息
createChatRoom//创建群聊
kickUserOutToChatRoom//把某个人剔除群聊
项目的地址:
2.2.6个人开发Openfire插件
在手机的聊天应用中,经常出现的一个需求就是把用户的离线消息通过推送系统推送到用户的手机上,为了实现这个功能,本人就开发了本插件,这个openfire插件是拦截了发给openfire用户的离线消息,然后根据自身的业务逻辑推送到手机上。
详细介绍:
2.2.7常见问题
openfire中发送某些特殊字符会断开xmpp连接的问题,解决方法请看:
另外一个好消息,和android应用简单整合就能提供聊天服务,密切关注中。
如果真的能实现,那么对于app提供聊天服务是个很好的选择。
但有几个问题:
1.它现在还没正式上线。
2.访问外国网站的风险。
3.法律规定要保存3个月聊天记录。
2.3短信、邮件、推送服务
在app的后端设计中,免不了消息的推送,短信,邮件等服务,下面就个人的开发经验谈谈这方面。
2.3.1重点
最重要的是,各种推送一定要放在队列系统中处理,不然会严重影响api的响应时间。
2.3.2短信
以前我们是用亿美软通的短信服务,但在三大运营商收紧了短信服务后,亿美软通的短信延迟非常厉害,后来我们找到了这家短信服务商,这家发送短信到联通,电信,移动手机很快就到了(直到2014.01.24)。
如果发送到移动的短信还没有改善,最后的后备方案:
发送到联通,电信的短信使用国内的服务商,发送到移动的短信就只能使用国外的短信服务商(国外发短信到移动手机3毛一条,好贵啊!
!
!
)
2.3.3邮件
在一开始时使用服务器自身的postfix发送邮件的,但我们发现邮件被很多邮件服务商当成垃圾邮件了,而且没有重发机制,不能保证邮件的准确到达。
后来查了一下各大网站,发现知乎和github都是使用的邮件服务,看了一下文档,价格很公道,而且每月有1万封的免费邮件额度,非常适合创业型的公司。
2.3.4短信方面
在这方面,我考虑的重点是:
在创业初期,能用第三方就尽可能多使用第三方的服务,自身只处理业务逻辑本身,快速的开发产品。
android篇:
android方面,我们使用过3种消息推送机制:
1.极光推送,现在放弃了。
我们使用的过程中,发现极光的机制有点古怪,一般来说,一个app在极光服务器中是固定一个id,但在极光中是通过广播来通知app这个id,而且在文档中居然说明这个id会不定期变化。
2.openfire服务器。
app通过连接openfire服务器来获取各种消息,但是openfire有个机制,当app连接openfire后空闲就自动断开,没法保持连接的的稳定性,而修改这个openfire的机制成本太高了,后来也放弃使用openfire。
3.XX推送。
已现在使用一段时间的情况来说,推送及时快速,挺满意XX的推送服务。
iphone篇:
apns是iphone推送的不二选择。
但如果自身开发apns的服务,会遇到无效token而需要重发,这样需要维护一个队列并建立重发机制,考虑到项目的时间和研发成本,最后也是使用了XX推送的服务。
当用户在iphone上卸载了app后,devicetoken会失效,所以应该定期访问苹果的feedback服务器,把无效的token去掉。
2.4安全性
在开发一个项目的时候,大家经常会忽略项目的安全性问题,有很多的安全性问题其实就是一个意识的问题,解决起来并不复杂,但是因为这些疏忽,却可能会给我们的用户带来很大的风险。
下面就列举一些在做项目的时候应该考虑的一些安全性问题。
2.4.1通讯的安全性
在app的后台设计中,一个很重要的因素是考虑通讯的安全性。
因此,我们需要考虑的要点有:
1.在app和后台,都不能保存任何用户密码的明文。
2.在app和后台通讯的过程中,怎么保证用户信息的安全性?
在app中,根据安全考虑,用户的操作分为两类:
1.用户登录注册操作。
2.用户的其他操作。
在第一点,用户登录注册操作中,是会出现用户密码,所以在这个过程中,必须要使用https通讯,保证通讯的安全。
在第二点,用户的其他操作,怎么保证这部分通讯的安全呢?
在我的设计中,是采用了公钥加私钥保证安全。
用户的id是公钥,通过一定的算法对用户的id进行加密得到一个加密字符串是私钥。
当用户登录或注册后,通过https把公钥加私钥返回给app客户端。
这个过程如下:
2.4.2密码保存
保存密码的第一准则是不能明文保存密码,之前CSDN密码泄露一事还记忆犹新。
通常的做法是对密码进行不可逆加密,加密时不要使用MD5或者SHA系列的算法加密,现在对这两个算法的破解研究工作已经有了相当的进展。
推荐使用bcrypt。
2.4.3CI服务器的安全性
CI服务器和Build服务器经常是攻击者最完美的跳板,这些服务器几乎拥有你系统的所有权限(代码库,各个生产环境的访问权限等等)。
请确保其安全。
2.4.4校验客户端安全证书的“指纹”
当使用SSL时,我们需要验证安全证书的“指纹”来确认该证书是有目标网站颁发的证书,这可以有效防止“中间人攻击”漏洞。
2.4.5随机生成密码
不要对所有账户设置同一个密码,一锅端就不好了,使用密码管理软件为每一个账户生成一个独立的密码。
当前比较推荐的是1Password,期待有更好的密码管理软件诞生。
2.4.6使用安全系数更高的随机数生成类库
要想得到真正的随机数是很困难的,尤其是要满足安全领域的随机数标准,语言自带的一般随机数生成算法很难满足需要,所以JDK还提供了SecuredRandom这样的类,Ruby中也有SecureRandom这样的模块。
2.4.7总是使用HTTPS和HSTS
如无值得信服的理由,所有的请求都应该使用加密协议
2.4.8不要使用“安全问题”找回密码
一个桶能装多少水是有最短的那块木板决定的,一个安全系统的安全性也是有最薄弱的环节决定的。
不要让安全问题成为你的那块短木板。
2.4.9不要限制密码长度
通过密码长度来保证安全性的时代已经结束了,让用户使用"PassPhrases"是一个不错的主意。
2.4.10允许对密码或者密码短语使用更直观的复杂度控制
使用更有效,直观的方法帮助用户增加密码或者密码短语的难度。
而不是简单的必须有大小写,必须超过8位等这些生硬的条件。
2.4.11避免缓冲溢出
在弱类型语言中,最常见的安全性问题就是缓冲溢出,这也是最常见的一种远程攻击方法,一般有四种防范方法:
*通过操作系统使得缓冲区不可执行,从而阻止攻击者植入攻击代码。
*写正确的代码*利用编译器的边界检查来实现缓冲区的保护。
*在程序指针失效前进行完整性检查
2.4.12避免注入攻击
所有的用户输入必须经过验证和清理才能传递给下游,最常见的就是SQL注入攻击。
2.4.13避免跨站脚本攻击
系统需要保证用户不能在页面中嵌入未经验证的信息。
2.4.14避免泄露信息给第三方
目前很多系统倾向于泄露信息给第三方,比方说Google,Facebook,新浪微博等等。
这些第三方会窃取很多用户信息。
2.4.15设置数据清理策略
只在需要数据时才保存数据,数据生命周期结束就清理掉,贼是没办法偷你没有的东西的。
2.5表情的处理
在app的应用中,文字中夹带表情是个很常见,那么,在后台处理表情的时间,我遇到过下面两个问题:
1.表情在mysql的存储。
表情的utf8编码,有时是有4个字节的,所以在一般的utf编码是没法存储的,我在网上看到的一个常用的解决方案,是把mysql升级到5.5,然后把字符编码改为utf8mb4_general_ci。
但在实践中,我发现了还有一个方法,适用于mysql5.1,就是把含有表情的那个字段的类型变为blob,没错,就是用二进制存储。
2.当文字中夹带表情的处理
很多时候,如果文字中夹带表情,那么这些文字的处理就会出现问题,例如,如果一个用户的昵称带有表情,那么我怎么把这个昵称转换为拼音呢?
在实际的开发中,我遇到了这个问题,先是找到了http:
//punchdrunker.github.io/iOSEmoji/table_html/ios6/index.html中ios6后新增的表情抓取出来,并写了个新的类库并开源了
2.6LBS服务
在LBS的应用中,一个基本的需求是查找附近的用户,现在有两种做法:
1.使用mysql的空间数据库,具体做法参考:
。
2.使用geohash编码,这个是本文需要讨论的。
geohash编码,可以把球面上的经纬度转换成一个值,简单点来说就是把二维坐标转换成一维坐标。
查找附近的时候,非常方便,用SQL中,LIKE‘w23yr3%’可查询附近的所有地点。
geohash的详细介绍,可参考http:
//www.wubiao.info/372。
在以前的产品中,一个需求是查找用户附近的商铺,发现用mysqlLIKE‘w23yr3%’这种方式检索geohash性能上的瓶颈很大,检索130万行的数据,平均花费了8秒,这是响应速度是无法忍受的。
后来经过不断优化,确定了如下使用coreseek+redis+mysql解决方案,一下子就把响应速度减少到平均1秒,这个方案的如下:
1.用每个商铺的坐标值计算geohash,把geohash作为key,商铺的作为value,放到redis的set集中。
$this->cache->redis->select
(1);//不能使用0,因为这里有大量的数据,需要独立。
$this->cache->redis->set('place:
geohash:
'.$geohash,$place_id);
2.根据用户的坐标,在redis中查找附近的商铺id
php
/**
*获取附近的地标公共处理方法
*@param$lat
*@param$lng
*@param$ngeohash值的长度,一般来说,当n=6,是获取当前附近1千米范围内的用户
*/
functiongetLocalPlace($lat,$lng,$n)
{
$lat=(float)$l
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Restful 后台 系统 架构 深入 分析