在这片神奇的国家里,作为最大规模迁徙的春运每年都是让我为购买一张回家的火车票而绞尽脑汁,这里就不吐槽12306有多烂了,毕竟它省去了很多排队的时间,这次抢火车票最开始用的是360抢票浏览器,票一放出来就立马被抢光了,最后好不容易捡到了一张,后来在网上有网友吐槽说360是为了骗取12306的账号,这个就不得而知了。
先说一下360浏览器的抢票流程吧,首先你要输入自己12306的账号和密码登陆,然后这个软件从12306上拉取你的乘车人信息,然后再进行选定车次等操作就可以开始抢票了,一般我的账号里面有多个人的信息,这些人的信息是在12306上自己输入的,必要的有身份证号、性别、姓名等,并且这些信息要和身份证系统匹配才能提交,好了,那既然12306账号和购买车票的人没有任何关系(一个账号可以为任何一个人买票,只要身份信息能够通过审核),那么为什么不将12306的账号屏蔽掉呢?
前天看到支付宝钱包给阿里旅行APP做的广告,第一次买火车票与最少10块钱的红包,刚好还需要购买一张火车票,于是就下载一个阿里旅行试了一下,阿里旅行购买火车票的操作是这个样子的,首先使用支付宝账号登陆,然后摇红包(可以略去,也就摇到了10元),接着选择你需要购买的班次,选定完成之后再输入乘车人的信息(身份证号、姓名、性别),最后用支付宝支付,这样就成功买到了一张好车票。买完车票之后给我发了两条短信,第一条短信是告诉我付款成功,等待出票。第二条短信是告诉我车票成功,车次、时间、座位等信息。
第二天突然想起来这张票,就到12306上确认一下车次和时间,但是查看订单发现没有这张票啊,难道是我没有订到车票?!但是钱都付了啊,座位信息都告诉我了啊,这是怎么回事?!这时候才想起来,这张票的购买过程中我并没有输入自己的12306账号,所以肯定在我的订单里面没有这张票 ,最后在火车站取出票之后我才放下心来。
但是这个过程让我有所思考,阿里的这样的购票方式的确有点不同于其他的购票APP(例如360浏览器,网易火车票),但是仔细想一下,我要从网上买一张火车票必备的信息是什么?不就是乘坐火车的车次、日期和乘车人的信息,那为什么非要用我的账号购买呢,反正取票的时候刷的是身份证而不是12306账号,所以在购票的过程中完全可以把12306账号屏蔽掉,用户输入必要的信息,其他的都交给APP做吧。
作为码农立马就和技术联系到一块了,我们经常说操作系统是系统硬件资源的管理者,它屏蔽了计算机各种复杂的硬件,提交良好的接口给用户使用,最常见的例子吧,例如操作系统的内存管理,操作系统屏蔽了物理内存的分配操作,每一个进程在创建的时候都会分配4G(32位)的逻辑内存,而用户所使用的地址也都是这些逻辑地址,我们不关系也不用关心我们的数据存放在内存具体的哪个地方(甚至存在磁盘上),在每次读取数据的时候再使用逻辑地址映射到物理地址,再通过访问物理地址获取数据,而对于编程者来说这些过程都是透明的。以前接触过一些面向小文件的存储系统,例如TFS、haystack,这种系统的需求是实现对小文件高效、快速、可靠的存储,一般的实现都是通过小文件合并成大文件的方式,在存储一个文件的时候,需要为这个文件生成一个全局唯一的标示符,然后将文件内容追加的写入到一个大文件中(可能要写多份),接着在元数据服务器上记录这个标识符和该文件每一个备份的对应关系(每一个备份存储在哪一台服务器上,在哪一个大文件中,偏移量是多少等),之后的读取操作就可以通过这个对象的标示符来完成。这样,存储系统为我们屏蔽了存储、备份等细节,之所以能这样实现,类似于内存管理一样,我们并不关系我们实际的对象存储在那台服务器上,我们只需要能够在写入成功之后能够成功的读取它。
以上的两个例子还是有所区别的,在内存管理中,我们是首先知道我的虚拟内存的地址,然后我要在这个地址存储一些数据,内存管理模块再去为这段地址建立映射关系,读取这段数据的时候还是使用这个虚拟地址。就像我知道我的身份证号,我要用这个号码买一张好车票一样,取票的时候使用这个身份证号。而对象存储中则不一样,它里面的标示符信息是在存储文件的时候系统为用户分配的,而不是用户指定的。这个过程就好比我用我的身份证买一张火车票,成功之后发给我一条短信,这条短信上有这张票的一个唯一标识,我可以通过这个标识信息取到火车票。
但是,这种屏蔽在用户希望了解内部实现的时候就会让人烦恼,就像我在用自己的账号查看火车票的时候找不到一样。最近在学习一些大数据的根据,主要需要学习的有mapreduce、hive、sqoop、pig。我们知道每一个mapreduce任务都会在提交的时候被分配一个jobid,然后我们可以通过这个jobid查看该任务的执行状态详情。而sqoop的IMPROT、EXPORT操作都是转换成mapreduce任务来实现 的,hive的sql查看操作也是通过mapreduce完成的,但是每一个sqoop命令或者一个hive查询命令都有sqoop或者hive的标示符,这些工具向我们屏蔽了提交mapreduce的过程。我们现在项目有一个需求就是查看这些mapreduce的状态,那么我们就需要获得这些jobid,但是hive护着sqoop给我们返回的只有它们的id,这层映射对用户是透明的,也就让我焦头烂额的想办法怎么查找到每一个sqoop和hive命令对应的jobid。
pig的解决方案不错,pig在执行run(PigRunner.run)一个脚本的时候可以选择的传递一个参数,这个参数是一个Listener对象,需要实现Pig内部的PigProgressNotificationListener接口的方法,这样,在整个任务执行的过程中的各个阶段都会回调相应的函数,这样我们就可以通过一些方法来获取mapreduce的信息了。
在hive中也有一些hook,这些hook需要在配置文件中设置,在一个命令执行之前和执行时回调这些函数,但是从这里面暂时没有获取到jobid信息,另外,在hive中有一个格式化的日志,可以通过打开格式化日志通过捕获日志输出的方式获取。在sqoop中好像可以通过sqoopClient的方式访问sqoop server来获得每一个job的提交(这里的job是sqoop的job),在提交之后可以通过接口获得jobid,但是我们的输入是一个sqoop的完整命令,怎么将这个命令解析之后再使用sqoopClient访问还是一个难题。
最后,买到的那张火车票由于种种原因需要在发车的前一天退票,但是我不知道哪一个用户帮我买的火车票,所以我就不能到12306网站上把这张票退了,这时候只能再去联系阿里旅行APP,所以这一层的封装使我和12306彻底解耦了,不用再去和12306网站打交道,省去了不少烦心事,这的确是一个不错的方案。