一切福田,不離方寸,從心而覓,感無不通。

《精灵宝可梦:Go》带来的软件质量启示

如果您的应用拥有2100万活跃用户,且随时保持在线,那么需要处理的质量难题一定不计其数。为了避免出现严重问题,我们将共同探讨如何抢先一步搞定体验保障工作。 《精灵宝可梦:Go》终于上线。这款手游的人气有多高?很简单,其已经成为全美有史以来最流行的移动游戏,目前拥有2100万活跃用户。 但兴奋的玩家们在游戏时却发现了大量问题。我个人就发现自己无法使用谷歌凭证完成登录,因为其“无法接入该服务器”。后来虽然登录完成,但却由于“GPS连接丢失”而无法捉住身边的妙蛙种子。网上报告该游戏问题的帖子层出不穷,同时也给出了一些潜在的解决方案。Google Play与iTunes出现了大量用于“修复”该游戏问题并保持玩家顺利游玩的相关应用。 我们不禁要问:为什么会有这么多故障? 难道是游戏开发者们没有为汹涌的玩家做好充分准备?或者,他们没有测试全部可能用例——包括地理位置、设备、操作系统、硬件等等? 在上线后的头一周,几乎每天都会出现《精灵宝可梦:Go》服务器崩溃以及影响人们使用体验的报告。值得庆幸的是,这些都没有影响到这款游戏的人气。目前其开发商Niantic公司已经掌握并修复了多种问题,然而随着此游戏在更多国家的上线,恐怕他们还要面临规模更大、强度更为夸张的冲击。 凭借着对游戏的热爱,下面我们一起来看应当从中吸取的四项软件质量保障教训: 教训一:你的实际水平由短板决定——测试并监控API 《精灵宝可梦:Go》的核心在于API。无论是登录应用、识别位置、查看增强现实效果、收集宝可梦小怪物、对战还是开着游戏街,这一切都依靠着API实现数据与请求传递。其中部分API由Niantic公司独立开发,也有一些属于流行的公共API——例如谷歌地理API。 然而很多玩家发现游戏无法检测到GPS位置,或者有时会给出错误位置。 相关问题包括: •    API端点可用性 •    响应请求的具体速度 •    载荷的功能正确性 由于整款游戏基于地理位置的正确性与严谨性而建立,因此即使是小小的误差也会影响到用户体验。游戏厂商不仅需要在部署之前测试不同API功能,还应当立足不同场景监控API功能的正确性——包括地理位置、设备、操作系统与服务供应商对效果的影响。 教训二:验证用户生成的数据 事实上,《精灵宝可梦:Go》并不是Niantic公司的首款增强现实游戏。早在2011年,他们就曾发布了Ingress的beta版本,其允许用户在世界各地的标志性建筑及历史地点收集“门户位置”。正是凭借着这部分数据,该公司才能够建立起《精灵宝可梦:Go》中的竞技场与宠物商店数据库。 虽然群众提供的数据非常庞大,但仍然有可能带来错误的结果。另外,其指向的某些偏僻位置甚至有可能给玩家带来人身安全风险。谁该对此进行控制?当然是游戏厂商! 教训三:测试并监控前端 在《精灵宝可梦:Go》这款游戏中,需要由API与GUI相配合以共同完成信息收集,这也意味着对二者进行测试变得非常重要。 前端图形用户界面(简称GUI)不仅需要API响应,同时亦需要配合设备硬件/传感器数据。举例来说,玩家所处地点由基于位置的传感器GPS提供,而其反过来又会影响到游戏GUI的表现。这意味着测试人员需要利用集成化GUI与API测试工具进行问题分析。 与此同时,要建立起规模化且坚实的自动化测试战略,我们还需要关注GUI与API层的行为优化。我们以此为基础建立更多单元测试,而后是API测试,最后完成数量进一步减少的UI测试。 由于游戏厂商有着极为庞大的全球化推广野心,因此为了在不同区域提供一致的使用体验,前端错误或可用性问题必须得到高度重视。 教训四:准备好应对一切潜在用户场景 与任何一款应用一样,《精灵宝可梦:Go》所面对的用户也是形形色色。他们来自不同的国家、身处不同地点、利用不同设备访问应用,但却希望获得同样的性能表现。 事实上根据我的个人经验,这款游戏在Android设备上非常耗电,我甚至不得不在尝试了几天之后选择将其删除。 我认为游戏开发商在增强现实游戏领域才刚刚起步,这类应用能够带来新的发展方向与潜在可能性,但同时也面临着种种前所未有的挑战。第一次尝试做到这样已经足够令人赞叹,也希望他们能够在未来继续积累经验,真正在软件质量层面带来让每个人满意的成果。 【51CTO译稿,合作站点转载请注明原文译者和出处为51CTO.com】 原文标题:4 Software Quality Lessons From Pokemon Go’s Wild First Week 原文链接:https://dzone.com/articles/4-software-quality-lessons-from-pokemon-gos-wild-f 核子可乐译 from:http://developer.51cto.com/art/201607/514878.htm

龙生   22 Jul 2016
View Details

一篇文章,掌握所有开源数据库的现状

数据库作为业务的核心,在整个基础软件栈中是非常重要的一环。近几年社区也是新的方案和思想层出不穷,接下来我将总结一下近几年一些主流的开源数据库方案,其背后的设计思想以及适用场景。本人才疏学浅如有遗漏或者错误请见谅。本次分享聚焦于数据库既结构化数据存储 OLTP 及 NoSQL 领域,不会涉及 OLAP、对象存储、分布式文件系统。 1 开源RDBMS与互联网的崛起 很长时间以来,关系型数据库一直是大公司的专利,市场被 Oracle / DB2 等企业数据库牢牢把持。但是随着互联网的崛起、开源社区的发展,上世纪九十年代 MySQL 1.0 的发布,标志着关系型数据库的领域社区终于有可选择的方案。 MySQL 第一个介绍的单机RDBMS就是MySQL。相信大多数朋友都已经对 MySQL 非常熟悉,基本上 MySQL 的成长史就是互联网的成长史。我接触的第一个 MySQL 版本是 MySQL 4.0,到后来的 MySQL 5.5 更是经典——基本所有的互联网公司都在使用。 MySQL 也普及了「可插拔」引擎这一概念,针对不同的业务场景选用不同的存储引擎是 MySQL tuning 的一个重要的方式。比如对于有事务需求的场景使用 InnoDB;对于并发读取的场景 MyISAM 可能比较合适;但是现在我推荐绝大多数情况还是使用 InnoDB,毕竟 5.6 后已经成为了官方的默认引擎。大多数朋友都基本知道什么场景适用 MySQL(几乎所有需要持久化结构化数据的场景),我就不赘述了。 另外值得一提的是 MySQL 5.6中引入了多线程复制和 GTID,使得故障恢复和主从的运维变得比较方便。另外,5.7(目前处于 GA 版本) 是 MySQL 的一个重大更新,主要是读写性能和复制性能上有了长足的进步(在5.6版本中实现了SCHEMA级别的并行复制,不过意义不大,倒是MariaDB的多线程并行复制大放异彩,有不少人因为这个特性选择MariaDB。MySQL 5.7 MTS支持两种模式,一种是和5.6一样,另一种则是基于binlog group commit实现的多线程复制,也就是MASTER上同时提交的binlog在SLAVE端也可以同时被apply,实现并行复制)。 如果有单机数据库技术选型的朋友,基本上只需要考虑 5.7 或者 MariaDB 就好了,而且 5.6、5.7 由 Oracle 接手后,性能和稳定性上都有了明显的提升。 PostgreSQL PostgreSQL的历史也非常悠久,其前身是UCB的Ingres,主持这个项目的 Michael Stronebraker 于 2015 年获得图灵奖。后来项目更名为 Post-Ingres,项目基于 BSD license 下开源。 1995 年几个 UCB 的学生为 Post-Ingres 开发了 SQL 的接口,正式发布了 PostgreSQL95,随后一步步在开源社区中成长起来。 和 MySQL 一样,PostgreSQL 也是一个单机的关系型数据库,但是与 MySQL […]

龙生   22 Jul 2016
View Details

立足GitHub学编程:13个不容错过的Java项目

今天我们将整理一大波干货满满的Java示例代码与能力展示素材。 GitHub可谓一座程序开发的大宝库,有些素材值得fork,有些则能帮助我们改进自有代码或者学习编程技能。无论如何,开发工作当中我们几乎不可能绕得开GitHub。 下面,我们将一同分享各有趣且颇为实用的Java库,大家请任取所需、不用客气~ 1.极致精简的Java Bootique是一项用于构建无容器可运行Java应用的极简技术。该项目允许大家创建REST服务、Web应用、任务、数据库迁移等等,且一切都立足于模块实现。另外,大家也可以将其作为简单的命令进行使用。 该项目的目标在于将应用从Java容器中解放出来,允许开发者重新回归main()方法。另外其中还包含部分内置命令,因此就算各位需要处理的代码量不多或者并未向应用中导入任何模块,仍然能够利用Bootique对其加以执行。 2.优雅的问题处理方式 99-problems,光看名字就能对其功能了解一二。很明显,它的作用是帮助大家磨练逻辑编程中的具体技能。大家可以选择利用Java 8、Scala或者Haskell进行问题解决,并最终找到最精致的解决办法。 如果大家喜爱解题,其中还提供多种不同层级的难度供各位选择。另外,如果大家将全部99道难题解决掉,则可进一步冲击Java Deathmatch。如果大家被难住了,请点击此处查看难题——但请注意,认真思考之后再参阅比较好哦。 3.字符串操作 Strman-java库是一套Java 8库,专门用于处理字符串。由于其可用于Maven,因此大家只需要面向选定的构建工具添加关联性即可使用。 如果大家使用过Kik并听说过其遭遇的leftPad问题,那么Strman可能是个更好的选择——其能够返回特定长度的新字符串,且自动填充开头部分内容。另外,其中还提供一整套功能列表,包括向值附加字符串、从特定目录中提取字符以及利用字符串在开始与结束间返回数组等等。 4.数据浏览 如果大家希望通过酷炫的方式进行数据交互,那么Dex绝对不容错过。它能够帮助我们提取、转换及可视化数据,同时附带预测功能。大家可以将可视化结果发布为3D或者其它HTML变量形式。 Dex允许我们生成超过50种不同的可视化模式,其中包括世界地图、参与时间表、网络使用情况等。大家也可以利用R与其运行实例相结合,从而构建起复杂的统计分析与预测分析体系。 民主党与共和党谁能胜出?利用弦状图看个究竟。 5.小小大数据 Tablesaw是一套内存内数据表,其中包含多种数据工具与面向列的存储格式。其设计思路认为没人会面向小型任务执行分布式分析,而大家可以在单一服务器上对200万行级别的表进行交互。 大家能够利用Tablesaw执行各种规则,从而检查显示布局、数据优先级或者针对数据显示及交互向特定用户提供扩展控制范围。在它的帮助下,我们可以利用RDBMS与CSV文件导入数据,添加及删除列,执行映射与规约操作或者将表保存在经过压缩的列式存储格式当中。 6.键值存储 Chronicle Map是一套内存内键值存储方案,其设计目标在于实现低延迟与/或多进程应用,例如贸易与金融市场应用。这套库主要面向中等读取与写入查询延迟场景,允许用户根据服务器中的硬件执行线程数量编写合适的查询机制。 其主要用途包括在单一服务器(例如Redis)中替代低速键值存储方案,或者取代同类面向JVM的解决方案以实现速度提升。大家也可以将部分应用状态移出Java堆,从而降低堆体积及GC压力。 7.负载调查工具 Gumshoe允许大家监控自己的应用性能统计指标。有了它,我们可以精确到具体代码行并了解与堆栈调用及个别栈帧相关的统计数据,从而确切分析资源使用情况(例如TCP、UDP、文件系统或处理器使用量)。 这套库能够在统计数据生成时对其进行捕捉、过滤与可视化处理,从而更为直观地实现数据结论查阅。如果需要更为具体地使用,大家还可以在数据捕捉与/或可视化处理过程中过滤栈帧,并在其运行中加以变更。 8.Java音乐 SoundSea允许大家搜索并下载歌曲。其内置有元数据与专辑信息,大家在查找特定歌曲时,SoundSea会在iTunes上查找相关元数据与专辑信息,并显示相关结果。如果匹配的歌曲超过一首,大家可在其中找到自己需要的条目。 歌曲本身下载自Pleer.com,大家还可以根据高品质、低品质或者VBR码率进行过滤。这同时也是一款迷你播放器,供我们直接聆听歌曲而不再经由其它音乐库。 搜索与下载 9.检查泄漏问题 LeakCanary是一套开源库,旨在帮助我们解决内存泄漏问题。大家可以利用它在Java(与Android)中检查内存泄漏。正如其GitHub页面中所言,“千里之埋溃于蚁穴”。 在LeakCanary设置完成后,大家可以利用其自动检查泄漏并在发现问题时给出通知。 10.多维数组 ND4J是一套开源库,能够将多种来自Python社区的科学计算工具引入JVM。其面向生产环境设计,因此运行速度很快但对内存容量却要求不高。在它的帮助下,工程师们能够轻松将算法及接口移植到Java与Scala库当中。 这套库的主要贡献是提供一套通用型n维数组对象,其多平台功能包括GPU与线性代数外加信号处理能力。其与Hadoop及Spark相集成,且提供API以模拟Numpy——一款高人气Python数学库。 11.监控Java 无论大家使用哪种监控工具,Automon都能够将其与AOP(AspectJ)相结合以实现Java代码、JDK以及依赖库监控声明。其可与其它各知名监控工具相协作,例如JAMon、JavaSimon、Yammer Metrics以及StatsD等,同时亦支持各类日志记录库,包括perf4j、log4j、sl4j等等。 另一款出色的生产型监控工具为Takipi。它能够帮助大家了解自己的代码何时及为何发生崩溃,查看全部意外状况并获取与之相关的全部堆栈、源与状态信息。 12.打理Java Jvm-tools,或者SJK,是一套用于JVM故障排查、监控与配置的工具组合。这是一款不像话地工具,使用JVM的标准诊断接口(例如JMX、JVM attach与perf计数器),同时添加了更多逻辑以应对各类常见故障排查用例。 这套库允许我们对目标JVM的CPU线程使用情况进行池化,同时定期向控制台报告实时CG信息并提供基础样本分析功能。在这里,我们可以通过命令行配合MBean执行各基本操作,同时将目标Java进程的全部MBeans转储为JSON格式。 13.最佳Java awesome-java是一套出色的Java框架、库与软件合集。如果大家不太清楚自己应当如何选择具体方案,请务必参考这套清单 ,其中甚至根据类别对各条目加以划分。 其中还包含一部分仍在使用的古老工具,包括能够简化映射的框架,可构建应用周期与依赖性的工具以及负责处理字节码编程的库等等。 总结陈词 这当然只是GitHub的冰山一角,毫无疑问还有更多项目值得大家审视并用于改善自身代码工程。也欢迎大家结合自己的经验在评论中提供更多推荐! 【51CTO译稿,合作站点转载请注明原文译者和出处为51CTO.com】 原文标题:The Hitchhikers Guide to GitHub: 13 Java Projects You Should Try 原文链接:https://dzone.com/articles/the-hitchhikers-guide-to-github-13-java-projects-y from:http://developer.51cto.com/art/201607/514785.htm

龙生   22 Jul 2016
View Details

大型网站应用中 MySQL 的架构演变史

没有什么东西是一成不变的,包含我们的理想和生活!MySQL作为一个免费的开源的关系型数据库,深受大家喜爱,从最初的无人问津到当下的去IOE,都体现出了MySQL举足轻重的作用。今天我们就从淘宝的发展来阐述MySQL在大型网站下的架构演变史! MySQL的可扩展性 架构的可扩展性往往和并发是息息相关,没有并发的增长,也就没有必要做高可扩展性的架构,这里对可扩展性进行简单介绍一下,常用的扩展手段有以下两种 Scale-up : 纵向扩展,通过替换为更好的机器和资源来实现伸缩,提升服务能力 Scale-out : 横向扩展,  通过加节点(机器)来实现伸缩,提升服务能力 对于互联网的高并发应用来说,无疑Scale out才是出路,通过纵向的买更高端的机器一直是我们所避讳的问题,也不是长久之计,在scale out的理论下,可扩展性的理想状态是什么? 可扩展性的理想状态 一个服务,当面临更高的并发的时候,能够通过简单增加机器来提升服务支撑的并发度,且增加机器过程中对线上服务无影响(no down time),这就是可扩展性的理想状态! MySQL架构的演变 MySQL简单网站架构(V1.0) 一个简单的小型网站或者应用背后的架构可以非常简单,  数据存储只需要一个mysql instance就能满足数据读取和写入需求(这里忽略掉了数据备份的实例),处于这个时间段的网站,一般会把所有的信息存到一个database instance里面。 在这样的架构下,我们来看看数据存储的瓶颈是什么? 1.数据量的总大小  一个机器放不下时 2.数据的索引(B+ Tree)一个机器的内存放不下时 3.访问量(读写混合)一个实例不能承受 只有当以上3件事情任何一件或多件满足时,我们才需要考虑往下一级演变。 从此我们可以看出,事实上对于很多小公司小应用,这种架构已经足够满足他们的需求了,初期数据量的准确评估是杜绝过度设计很重要的一环,毕竟没有人愿意为不可能发生的事情而浪费自己的经历。 这里简单举个我的例子,对于用户信息这类表 (3个索引),16G内存能放下大概2000W行数据的索引,简单的读和写混合访问量3000/s左右没有问题,你的应用场景是否 MySQL的垂直架构(V2.0) 一般当V1.0 遇到瓶颈时,首先最简便的拆分方法就是垂直拆分,何谓垂直?就是从业务角度来看,将关联性不强的数据拆分到不同的instance上,从而达到消除瓶颈的目标。以图中的为例,将用户信息数据,和业务数据拆分到不同的三个实例上。对于重复读类型比较多的场景,我们还可以加一层cache,来减少对DB的压力。 在这样的架构下,我们来看看数据存储的瓶颈是什么? 单实例单业务,依然存在V1.0所述瓶颈,遇到瓶颈时可以考虑往本文更高V版本升级, 若是读请求导致达到性能瓶颈可以考虑往V3.0升级, 其他瓶颈考虑往V4.0升级 MySQL的主从架构(V3.0) 此类架构主要解决V2.0架构下的读问题,通过给Instance挂数据实时备份的思路来迁移读取的压力,在Mysql的场景下就是通过主从结构,主库抗写压力,通过从库来分担读压力,对于写少读多的应用,V3.0主从架构完全能够胜任 在这样的架构下,我们来看看数据存储的瓶颈是什么? 写入量主库不能承受 MySQL的路由多集群架构(V4.0) 对于V2.0 V3.0方案遇到瓶颈时,都可以通过水平拆分来解决,水平拆分和垂直拆分有较大区别,垂直拆分拆完的结果,在一个实例上是拥有全量数据的,而水平拆分之后,任何实例都只有全量的1/n的数据,以下图Userinfo的拆分为例,将userinfo拆分为3个cluster,每个cluster持有总量的1/3数据,3个cluster数据的总和等于一份完整数据(注:这里不再叫单个实例 而是叫一个cluster 代表包含主从的一个小mysql集群) 数据如何路由? 1.Range拆分 sharding key按连续区间段路由,一般用在有严格自增ID需求的场景上,如Userid, Userid Range的小例子:以userid 3000W 为Range进行拆分 1号cluster userid 1-3000W 2号cluster userid 3001W-6000W 2.List拆分 List拆分与Range拆分思路一样,都是通过给不同的sharding key来路由到不同的cluster,但是具体方法有些不同,List主要用来做sharding key不是连续区间的序列落到一个cluster的情况,如以下场景: 假定有20个音像店,分布在4个有经销权的地区,如下表所示: 业务希望能够把一个地区的所有数据组织到一起来搜索,这种场景List拆分可以轻松搞定 3.Hash拆分 通过对sharding key 进行哈希的方式来进行拆分,常用的哈希方法有除余,字符串哈希等等,除余如按userid%n 的值来决定数据读写哪个cluster,其他哈希类算法这里就不细展开讲了。 数据拆分后引入的问题: 数据水平拆分引入的问题主要是只能通过sharding key来读写操作,例如以userid为sharding key的切分例子,读userid的详细信息时,一定需要先知道userid,这样才能推算出再哪个cluster进而进行查询,假设我需要按username进行检索用户信息,需要引入额外的反向索引机制(类似HBASE二级索引),如在redis上存储username->userid的映射,以username查询的例子变成了先通过查询username->userid,再通过userid查询相应的信息。 实际上这个做法很简单,但是我们不要忽略了一个额外的隐患,那就是数据不一致的隐患。存储在redis里的username->userid和存储在mysql里的userid->username必须需要是一致的,这个保证起来很多时候是一件比较困难的事情,举个例子来说,对于修改用户名这个场景,你需要同时修改redis和mysql,这两个东西是很难做到事务保证的,如mysql操作成功 但是redis却操作失败了(分布式事务引入成本较高),对于互联网应用来说,可用性是最重要的,一致性是其次,所以能够容忍小量的不一致出现. 毕竟从占比来说,这类的不一致的比例可以微乎其微到忽略不计(一般写更新也会采用mq来保证直到成功为止才停止重试操作) 在这样的架构下,我们来看看数据存储的瓶颈是什么? 在这个拆分理念上搭建起来的架构,理论上不存在瓶颈(sharding key能确保各cluster流量相对均衡的前提下),不过确有一件恶心的事情,那就是cluster扩容的时候重做数据的成本,如我原来有3个cluster,但是现在我的数据增长比较快,我需要6个cluster,那么我们需要将每个cluster 一拆为二,一般的做法是 1.摘下一个slave,停同步, 2.对写记录增量log(实现上可以业务方对写操作 多一次写持久化mq  或者mysql主创建trigger记录写 等等方式) […]

龙生   22 Jul 2016
View Details