摘 要: Redis+MySQL+MongoDB技术架构实现了本项目中大数据存储和实时云计算的需求。使用MongoDB切片的水平动态添加,可在不中断平台业务系统的同时保障扩容后的查询速度和云计算效能;依据切片键索引分片,位于各切片独立进行计算,使大数据下的实时分析成为现实。对于高频访问的数据放在了Redis中,有效地降低磁盘I/O,使业务系统响应更为敏捷,满足了高并发下应用服务的高呑吐要求。
关键词: 移动位置服务SaaS;Redis;MongoDB
基于移动位置服务的应用是根据用户所在位置提供的一种增值业务,主要通过移动定位技术获得其当前所在位置,在电子地图和业务平台的支持下,提供位置相关的信息服务。通过互联网提供软件服务的SaaS(Software as a Service)模式具有企业初期零投入,不需服务器、系统研发等软硬件投入等独特的优点,为广大中小企业解决前期资金投入不足的情况下开展信息化建设,引入管理信息系统提供了一个可行的模式。
1 项目简介
基于此需求背景提出开发一种面向中小企业移动位置服务的SaaS平台,帮助所有具有外勤、外巡、外服的户外工作业务的中小企业降低成本,将定位技术与智能手机客户端相结合,利用运营商的GSM/WCDMA等无线网络,为企业提供在外工作人员的具体位置和行走轨迹,同时实现考勤签到、快速审批、位置标注、语音群聊、数据上报、区域预警,更好地进行地理化分析、业绩审视,快速响应客户需求和有效管理员工,深度巩固企业在市场中主体地位和增强企业核心竞争力。
2 业务数据分析
移动位置服务的SaaS平台作为企业移动互联网应用,应用过程将积累大量数据。其中包括:静态信息(手机号码、注册信息、手机型号等);位置信息(行动轨迹、速度、停留时间、地点属性);与APP关联的数据(访问行为、社交行为、交易行为等);交互特点(报告频率、数据类型与格式等)。其数据容量和特点较传统业务有较大地变化。
2.1 数据来源分析
数据来源包括终端采集的数据和SaaS平台数据,终端数据涵盖了Android、IOS智能终端和PC端,智能终端是企业应用的数据采集器,是企业人在业务活动中“人体器官”的延伸。同时还有部分数据源于PC端;另外系统运行过程中,会产生大量日志数据。
(1)终端采集的数据
①轨迹数据:以包括公司id、用户id、经纬度、地址、定位时间、定位类型等信息的一个数据样本为例,默认30 s采集一次,假如企业员工默认工作时间8小时,每个员工每天条数为2 080条,假定用户数为10 000,那么每天有2 080万条;单条数据占用空间184 KB,10 000用户一天占用空间约为3 GB。
②常规业务数据:常规业务数据种类有考勤、工作计划、工作日志、申请、事件提醒、通知公告、销售上报等;保守预计单条数据容量为512 KB,按每个用户每天产生15条相关业务,其数据量为7 680 KB,10 000用户一天产生数据量约为73 MB。
③即时聊天和工作微博数据:即时聊天和工作微博数据为非结构化数据,包含如下种类:语音、图片、文本、位置分享等。保守预计单条图片语音数据量为: 100 KB,按每个用户每天产生30条,其数据量为3 000 KB,10 000用户一天产生数据量约为28 GB。
(2)平台数据
作为服务众多企业的云平台,还有如下种类数据需要产生和管理:企业、企业组织、企业用户、用户通信录、用户通信录个性化备注、群组名片等;平台方面的数据暂且不作考量,与普遍的企业应用基本类似。
2.2 数据特点分析
(1)移动化。与PC应用相比较,移动应用数据采集的时空变化了,智能终端不知疲倦,可以自动采集上报如位置等信息;同时移动化使得采集数据的便捷性得到了极大提高,用手机拍照立即便可上传,相比过去的照相机采集没有空间限制也没有链接PC上传的限制。
(2)非结构化。采集的图片语音等媒体数据非结构化,例如采集门店的货品陈列的图片数据等,工作微博分享的数据文档化,与传统结构化、需要事务支持的数据有明显差异。
(3)平台级增量化。与以往企业级应用对应一家企业增量相比,平台级数据增量化带来的数据量巨大增加,通过上面的分析,10 000用户每天会带来大约30 GB的数据增量。30 GB数据有些均匀地提交到平台,有些会以峰值的方式提交到平台;考勤通常集中在上下班时段,而轨迹则均匀分布在所有上班时间。
针对以上数据分析,如何解决其大容量和非结构化数据特点面临的存储和处理的挑战?通过技术选型和前期的测试数据对比,选用了Redis+MySQL+Mongodb架构的解决方案。
3 相关技术
3.1 Redis简介
Redis(Remote Dictionary Server)是一个使用ANSI C语言开发的开源的Key-Value存储系统,它和目前较流行的Memcached类似,都是基于内存(缓存)的数据存储方式,不同的是Redis支持的数据类型更加丰富并且对每种数据结构提供了丰富的操作。同时,Redis不同于Memcached之处在于它会将更新的数据异步的持久化到硬盘中或者把进行过的修改操作写入日志文件中。Redis虽然是Key/Value形式的数据库,但是它吸收了部分关系型数据库的优点,如在能保存Lists和Sets类型的数据的同时,还能完成排序等高级功能,同时在实现INCR(自增)、SETNX(若不存在Key则创建并设值)等功能时保证其操作的原子性。在此基础上还实现了Master-Slave(主从)同步[2]。Redis主从复制特点:(1)支持一个Master可以拥有多个Slave,同时Slave还可以接收其他的Slave;(2)主从复制不会阻塞Master和Slave,在同步数据时,Master和Slave都可以接收Client请求[2]。
3.2 MongoDB及其自动分片简介[3]
MongoDB是一个基于分布式文件存储的数据库[4]。由C++语言编写。它支持的数据结构非常松散,是类似json的bson格式,因此可以存储比较复杂的数据类型。MongoDB的特点是面向集合存储,模式*,支持动态查询、完全索引、查询、复制和故障转移,自动处理碎片[5]。MongoDB的核心理念在于文档模型,它是MongoDB数据的基本单元,等价于关系型数据库的行。MongoDB中的集合等价于关系型数据库中的表。一个单一的MongoDB可以承载多个独立的数据库,每个数据库可以拥有自己的集合和管理权限。
MongoDB的分片架构是指把数据分割成不同部分,在不同的机器上的存储过程,通过分割数据到不同的服务器上,使得无需使用更强大的机器来存储更多的数据和处理更大的负载。MongoDB支持自动分片,集群可以自动分割数据和数据的再均衡。MongoDB提供以下的分片技术:(1)对负载的变换和数据的分布自动平衡;(2)动态添加额外服务器;(3)无单点故障;(4)自动故障转移[6]。
4 技术实现
4.1 架构功能角色
Redis+MySQL+Mongodb架构对应功能角色如下。
Redis:基于内存高速缓存,保存集群*会话,即时通信离线消息队列,即时通信重发消息集合,用户令牌生命周期管理,应用高频访问数据缓存,HTML5模板数据缓存,静态应用资源缓存。
MySQL:进行事务数据存储:相关企业帐号数据,企业常规业务数据,企业平台交易数据。
Mongodb:进行非结构化文档数据存储:包括图片、图标、语音、工作微博文本以及结合位置数据的非结构化的文档数据,需要动态扩展无固定模式的数据,应用日志数据,需要map-reduce计算的数据。
4.2 可靠性和可用性保障措施
为了保证生产系统数据可靠性和可用性,规避Redis+MySQL+Mongodb单点故障,分别作了主从备份,在此基础上采用了KEEPALIVE,通过VRRP协议实现了故障的自动切换。Redis配置了主从,MySQL配置了主从,Mongodb配置了切片;详细配置清单举例如下。
Redis主从配置需要在从配置文件Redis.conf指定主IP和端口:slaveof 192.168.10.10 6379
MySQL主从配置:
主配置:server-id=1;log-bin=mysql-bin;binlog-do-db=wqt_web
从配置:server-id=2;log-bin=msyql-bin;master-host=192.168.10.3;master-user=slaveuser;master-password=gotop4001680756;master-port=3306;…
Mongodb切片配置:
mongod-shardsvr-port 10001-dbpath=/home/data/shard11/-logpath /home/data/shard11/mongodb.log--fork
mongod-shardsvr-port 10002-dbpath=/home/data/shard12/-logpath
…
mongo 127.0.0.1:20000/admin
配置分片必须要链接admin集合。链接成功后可以把分片加入集群:
db.runCommand({"addshard":"127.0.0.1:10001"})
…
db.runCommand({"addshard":"127.0.0.1:10004"})
这样就成功地把4个shard加入了分片。制定分片的规则如下:
db.runCommand({"shardcollection":"kingfihser.tablename","key":{"primaryKey":1}})
激活分片的设置:db.runCommand({"enablesharding":"kingfisher"}),最后成功的配置了分片。
4.3 详细代码
4.3.1 Redis实现案例
在通信中,作为发布订阅队列使用,Web发布消息,进入Redis发布订阅频道,通信中心消费此频道消息,所有的信息发布都在Redis中进行,从而提高了响应的速度。
public boolean sendMsg(String msg){
boolean rebool=true;
Jedis jedis=null;
try{
jedis=(Jedis)pool.getResource();
jedis.publish("kingfisher.*",msg);
}catch(Exception e){
e.printStackTrace();
rebool=false;
}finally{
pool.returnResource(jedis);
}
return rebool;
}
4.3.2 Mysql实现
进行事务数据存储:包括相关企业帐号数据,企业常规业务数据,企业与平台交易数据。此部分的存储计算采用HIBERNATE+SPRING方式实现。
4.3.3 Mongodb实现案例
(1)媒体数据利用GFS网格文件子系统存储。
class fileservice(BaseHandler):
def get(self):
id=self.get_argument("id","")
f=GridOut(self.mongo.fs,ObjectId(id))
try:
fn=f.filename.lower()
…
self.write(f.read())
def post(self):
…
def delete(self):
…
(2)工作微博内容和二维空间索引,以及轨迹数据的索引和查询。
class listmark(BaseHandler):
′′′
搜索工作微博列表
′′′
def get(self):
self.set_header("Content-Type", "application/json")
…
class mark(BaseHandler):
′′′
基于二维空间的搜索
′′′
def get(self):
self.set_header("Content-Type","application/json")
try:
…
(3).map-reduce计算做日志分析。
′′′
调度生成当天用户访问行为
′′′
class currdayuser(BaseHandler):
def get(self):
…
′′′
调度生成当天服务运行行为
′′′
class currdayservice(BaseHandler):
def get(self):
目前这种存储结构,解决了项目中大数据存储和实时云计算的需求。使用了Mongodb切片的水平动态添加,可不中断平台业务系统的同时保障扩容后的查询速度和云计算效能;依据切片键索引分片,计算位于各切片独立进行,使大数据下的实时分析成为现实。对于高频访问的数据放在了Redis中,有效地降低了磁盘I/O,使业务系统响应更为敏捷,满足了高并发下的应用服务的高吞吐要求。虽然大数据的存储和计算变得简单,但由于版本和技术在日新月异的变化,数据系统的管理工作并不轻松。在新架构下的运维管理还会遇到新的挑战并需不断优化完善。