我使用了Spring MVC中的RestTemplate作为客户端,然后引入了Jackson-dataformat-xml作为xml映射为对象的工具库。由于集成外部API的事情已经做了很多次了,集成这个API也是轻车熟路,三下五除二就完成了。
接下来为了验证连通性,我先在SoapUI里配置了该外部API的某个测试环境,尝试发送了一个Get请求,成功收到了Response。然后我把自己的程序运行起来,尝试通过自己的程序调用该API,结果返回了HTTP 500错误,即“internal server error”。
这可奇了怪了。我第一反应是程序中对外部API的配置和SoapUI中的配置不一样。我仔细对比了发送请求的URL,需要的HTTP header以及用作验证的username和password都是完全一致的。这个问题被排除。
接下来我想再仔细看看Response,能否找到什么蛛丝马迹。仔细查看了Response的header和body,发现header一切正常,body是个空的body,没有提供任何的可用信息。
然后我能想到的另一个解决方案就是联系该外部API的团队,让他们帮忙看看我发送了请求之后,为什么服务器会返回500。但可惜这是一个很老的服务了,找到该团队的人并且排期帮我看log至少要花好几天的时间了。而且既然SoapUI能调用成功,而应用程序却调用不成功,问题多半还是出在我们这。
接下来我想既然问题有可能出在我们这,那么肯定是request有差异。由于我发的是一个Get请求,没有body实体,URL又完全一样,那么问题很可能出在request的header上。这个API需要request中包含两个自定义的header,而我在SoapUI以及自己的程序中都已经配置了。那问题会在哪里哪?
既然在SoapUI里无法重现这个问题,我就使用了Chrome插件版的POSTMAN,通过它配置了该API的调用。然后奇迹出现了,我竟然在POSTMAN中重现了这个问题。当我看到在POSTMAN也返回了500 error后,我思考了5秒钟,猜到了原因。问题很可能是出在了Authentication这个header上面。
要说这个问题,还要从HTTP的Basic Authentication说起。Basic Authentication是HTTP实现访问控制的最简单的一种技术。HTTP Client端会将用户名和密码组合后使用Base64加密,生成key为‘Authentication’,value为‘Basic BASE64CODE’的HTTP header,发送给服务器端以便进行Basic认证方式。
但这个经典的Basic Authentication是要经历两步的。第一步,客户端发送不带Authentication header的HTTP请求,服务器检查后发现受访的资源需要认证,就会返回HTTP Status 401,表示未授权,客户端发现服务器端返回401后,会再构造一个新的请求,这次包含了Authentication header,服务器接收后验证通过,返回资源。
那么我在自己的应用程序和POSTMAN中调用返回500 internal server error的原因是当第一次给Server发送不带Authentication header的HTTP请求时,Server竟然返回了HTTP Status 500。其实它应该返回401,这样HTTP Client会再发一个包含了Authentication的新请求。由于它返回了500,HTTP Client认为服务器有问题,就停止处理了。
那为什么在SoapUI中调用可以成功那?那是因为SoapUI使用的Http client在发第一次请求时就已经设置了Authentication header,所以就没有问题。这样可以避免重复发请求的现象。这种行为叫做‘preemptive authentication’(抢先验证),在SoapUI中你可以选择是否启用该行为。具体可以参见How To Authenticate SOAP Requests in SoapUI。
所以问题的根源在于该外部API在实现Basic Authentication时没有完全遵循规范,这锅我们不背。
解决方案有两种。第一种是让该外部API遵循Basic Authentication的规范,如果请求未授权应该返回401而不是500。不过我说过这是一个很古老的API了,让它们改要等到猴年马月了。
第二种就是我的应用程序在给该外部API发送请求时,第一次就设置Authentication header。我们用的是RestTemplate,而RestTemplate底层使用的是Apache Http Client 4.0+版本。要注入这个header很简单,在实例化RestTemplate后,给其多加一个Intecepter。
1 2 |
|
加上这一行代码后,运行程序,顺利的得到了Response,世界清静了。
最后一个问题,为什么Http Client当配置了用户名和密码后,不主动的启用‘preemptive authentication’那?毕竟可以少发很多请求啊。这是Apache官方给出的原因:
HttpClient does not support preemptive authentication out of the box, because if misused or used incorrectly the preemptive authentication can lead to significant security issues, such as sending user credentials in clear text to an unauthorized third party. Therefore, users are expected to evaluate potential benefits of preemptive authentication versus security risks in the context of their specific application environment. Nonetheless one can configure HttpClient to authenticate preemptively by prepopulating the authentication data cache.
扩展阅读:
]]>本人从2014年4月份开始跑步,到现在断断续续有3年多的时间。现在粗略的算一算投在跑步运动上的钱大概有多少。
本人参加的马拉松或者路跑活动不算多,以下是能想起来的一些比赛,具体报名费不是很精确。
2014年8月份,布里斯班马拉松, 报名费120澳元,人民币700块左右
2014年9月份,twilight半马,报名费忘记了,差不多400块吧
2014年11月份,西昌马拉松,报名费120元
2014年11月份,新川半马,报名费80元
2015年3月份重庆马拉松,报名费100元
2016年3月份浦那半马,报名费300卢比,人民币30块
2016年3月份另一个浦那的半马,也是30块
2016年9月份浦那的一个超马比赛,1000卢比,人民币100块
2016年11月份蜀道驿传,报名费100元
2016年一个10公里比赛,报名费120元
2017年一个爬楼梯的登高赛,报名费200元
2017年3月份成都双遗马拉松,报名费120元
2017年9月份成都马拉松,报名费120元
能想起的就这么多了,还有一些小比赛已经想不起来了。总共是2220。算上一些遗漏的比赛,就凑个整数2500元吧。
可以看出一般来说路跑赛事平均下来每公里的报名费花销在2-4块左右。也就是每跑一公里,就要花2-4块钱。
看起来是不是比较温柔,但是我2014年12月份一不小心入了越野跑的坑,先先后后参加了多场越野跑的比赛,那么赛事报名费的花销就不能小觑了。以下比赛的报名费也不是很精确。
2014年12月龙山30公里越野,200元
2015年2月份金鸡谷20公里越野,120元
2015年3月份爱江山龙山越野跑60公里,600元
2015年3月份杭州100,900元
2015年4月份大连100越野赛,报名费800元
2016年5月份汶川熊猫热土50公里组,报名费500元
2016年7月份张掖100越野赛,报名费800元
2016年10月份大理100越野赛,报名费800元
2017年3月份青城山30公里越野赛,报名费400元
2017年4月份江南100越野赛,报名费700元
2017年7月份曾家山越野赛,报名费600元
2017年8月份大山包100越野赛,报名费800元
除此之外还参加了很多萨洛蒙的月赛,粗略算有6次吧,每次平均120元。
总共是7940。越野跑的报名费明显比路跑的要高不少,平均1公里要8块钱左右。而且跑鞋也贵,装备要求高。大部分装备花销都是为越野跑准备的。
跑鞋:耐克跑鞋一双,800.在印度出差时买的POWER跑鞋一双,人民币300.亚瑟士GT2000跑鞋一双,收的是朋友的比赛奖品,半价,600元。泰尼卡闪电鞋两双,每双890。萨洛蒙大红鞋一双,收的尾货,650。萨洛蒙S-Lab的一双越野跑鞋,收的朋友的奖品,半价650元。
背包:萨洛蒙5L背包一个,900元。迪卡侬12L背包一个,400元。额外水袋一个,60元。
衣服:LP压缩衣、压缩裤、压缩腿套,当时参加了买装备送龙山越野赛名额的活动,压缩裤和腿套650元,但送了一件压缩衣和龙山越野赛名额。跑团的T恤和皮肤风衣算下来有300块吧。迪卡侬买的长袖训练服、训练裤好几件,算下来有500块吧。
TOMTOM运动手表一个,2500元,装酷的Oakley太阳镜一个,1200元。
迪卡侬手杖一对,160元,空顶帽两个80元。
总共是11530。当然这不是完整版,很多小装备钱不多,但是累积起来也不少。
主要包括路费、住宿费等。
我出省的比赛比较少。大头是交通费,包括机票、火车票等,住宿一般都比较便宜,一晚150-200的标准。先后去过大连、张掖和宁波奉化,路费和住宿费每次按1800算,三次5400元。
省内的我一般开车或者坐组委会的大巴或者坐火车去。比如去汶川自驾就有4、5次,青城山也有好几次。不细算了,就算个2000元吧。
总共7400元
为了跑的更快、更远,办了健身卡练习力量和核心。这几年的健身卡算下来有4000块把。刚买了跑后按摩放松的泡沫轴,145元。
这几项加起来总共是31015元。实际花销肯定比这个多。我估摸着至少还要多20%的样子。
另外今年也打算入铁三的坑,办了一张游泳卡,2500,买了一辆捷安特TCR6300自行车,4600元。周末刚去迪卡侬买了头盔和手套等配件,又是500元出去了。现在还缺胶衣、比赛用的泳裤(现在的泳裤都要穿烂了)、修车套件、装车包、打气筒、骑行服、骑行裤、休息把、锁踏、锁鞋…..又是一笔不小的开销。
其实还有很多装备想买,但是没有落实经费(经济大权老婆在掌控)。比如想买一个佳明F5,人民币大概6000元左右。一个GOPRO摄像机及配件,人民币3000元左右。这两个就轻松过万了。
跑步三年多,花费3万+。平均1年1万多,当然我这还不算是太败家的。这点钱在好多跑友那里连参加比赛的路费都不够。
这个钱花的值不值那?我认为值,你们随意。
]]>如果要打造一个持续交付的流水线,首先要考虑多环境的问题。一般一个应用程序会有多个环境,比如开发环境、集成测试环境、系统测试环境、用户验收测试环境、类生产环境、生产环境。如何在OpenShift中隔离并建立对这些环境的部署流程有多种方案可以选择。
我们以第二种方式为例,演示下多环境管理问题。
在上图中,我们有一个build project。build project包含了一组相互依赖性比较强的应用,每个应用对应一个build config,产生的Image Stream存放在image register中。而每个环境各对应一个project,其中包含了该应用的deployment config,其镜像输入是build config产生的Image Stream。之所以这样做,有以下几点考虑:
不同的环境分布在不同的project中,可以很好的借助project的特性进行环境隔离。比如sys project的容器只能部署在label为sys的node上,prod project的容器只能部署在label为prod的node上。
不同的project可以分别定义权限访问和控制。比如只有QA才能操作sys project中的资源,运维工程师才能操作prod project中的资源。
不同的环境共用一个Image Stream,保证了应用程序镜像在不同环境中的是完全一致的,防止由于测试环境和生产环境不一致而引入缺陷。
那么大家共用同一个Image Stream,如何实现应用的promotion那?解决方案就是使用tag。
如上图所示,一个image stream里面有多个版本的镜像,而OpenShift可以为版本添加自定义tag。在不同的project里面,我们配置image的来源为”ImageStreamTag”,名称为”applicationName:environmentName”。比如sys project的镜像名为”App1:sys”,prod project的镜像为”App1:prod”。如果想将version 3的镜像推送到sys环境,只需要简单的给version 3的镜像打上sys的tag,这样部署sys环境时就会自动使用version 3的镜像。
1
|
|
如果在Deployment Config里面配置了自动监听tag的变动的操作,那么一旦你修改了ImageStream的tag,就会自动触发对应环境的部署。
由于应用程序镜像在不同的环境中是一致的,那么变动的部分都被抽取到了外部配置中。如何根据不同的环境来加载对应的外部配置那?实现方式有很多种,这里介绍了使用Spring Cloud Config的方案。
首先我们将针对不同环境的配置放置在一个git仓中,然后通过Spring Cloud Config Server将其转换为http服务。而我们在应用中嵌入Spring Cloud Config Client,其会接收一个环境变量来拉取指定环境的配置。而该环境变量可以通过Deployment Config来进行注入。
1
|
|
使用Spring Cloud Config给予了我们更多的灵活性。我们可以选择在应用程序第一次启动的时候拉取配置,也可以设置每隔一段时间自动更新配置,从而实现热更新。
OpenShift虽然提供了构建和部署的能力,我们有时也需要使用Jenkins之类的工具来可视化以及编排整个流水线。
既然OpenShift是个容器化的管理平台,那么我们完全也可以将Jenkins作为一个应用纳入到OpenShift中来托管,这样Jenkins的Master和Slave都是容器化的。OpenShift官方提供了一个Jenkins2.0的镜像,其预装了OpenShift pipeline插件,可以很方便地进行构建、部署等操作。
OpenShift在产品环境的部署默认是rolling的方式。
每次部署时,它会启动一个新的Replica Controller,部署一个pod,然后削减旧的Replica Controller的pod,如此往复,直到旧的Replica Controller中的所有pod都被销毁,新的Replica Controller的所有pod都在线。整个过程保证了服务不宕机以及流量平滑切换,对用户是无感知的。
而有的时候部署场景要负责些,比如我们想在产品环境对新版本做了充分的PVT(product version testing)才切换到新版本。那么就可以使用蓝绿部署的方式。
蓝绿部署方案的关键点在于一个Router对应两个Service。而Route作为向外界暴露的服务端口是不变的,两个Service分别对应我们的生产蓝环境和生产绿环境。同时只有一个Service能接入Router对外服务,另一个Service用来进行PVT测试。切换可以简单的修改Router的配置即可。
1 2 3 4 5 |
|
OpenShift在应用的构建以及部署方面为我们提供了大量开箱即用的功能和解决方案,所以实现持续交付不再那么艰难。我们可以将更多的精力花费在提升应用程序质量以及架构方面,交付更好的产品。
]]>Docker提供了对打包和创建基于Linux的轻量级容器的抽象。而Kubernetes提供了多主机集群管理和Docker容器编排。OpenShift基于Docker和Kubernetes加入了新的功能:
OpenShift直接提供支持的应用程序镜像有:
OpenShift直接提供支持的数据库镜像有:
除此之外,OpenShift还让你通过一键点击便生成相应的应用,比如几秒之内搭建好一个Jenkins服务。包括以下:
从上图可以看出,OpenShift的典型用户分为两种,开发人员和运维人员。开发人员可以通过现有的代码管理工具和持续集成、交付工具利用OpenShift完成对应用程序的打包、部署、扩容操作。而运维人员可以利用现有的自动化工具实现对OpenShift平台的维护。
OpenShift中的Kubernetes用来管理跨宿主机(或容器)的容器化应用程序,并提供部署、维护和应用程序扩容机制。对于一个Kubernetes集群来说,它包括一个或多个master以及一组node。
Master主机托管了API服务器、controller manager服务器以及etcd实例。Master管理Kubernetes集群中的节点并控制运行在节点上的pod。
Node则提供了容器的运行时环境。Kubernetes节点中的每个node会运行受Master管理的服务,当然也包括Docker、Kubelet及serverice proxy服务。node可以为云机器、物理系统或者虚拟系统。Kubelet用来更新node上的运行的容器状态。Service Proxy用于运行一个简单的网络代理,来反映定义在node的API中的服务,从而使node可以跨后端进行简单的TCP和UDP流转发。
如果想自己架设OpenShift平台作为商业用途,必须要获取OpenShift Enterprise的付费订阅。目前OpenShift Enterprise的最新版本为3.6版。对于Master和Node节点的系统要求如下。
Master:
Node:
下图是一个在AWS中的OpenShift集群的示例。
Master节点:包含3个Master实例,实现高可用,上面运行etcd、通过一个external load balancer向外暴露服务。
Infra Node: 由三个实例组成,这三个实例用来运行支撑OpenShift集群服务的一系列容器。
App Node:用于运行应用程序容器的实例,可以按需进行扩展。
Bastion:用于限制对集群中实例的ssh访问,增强安全性。
存储:OpenShift使用EBS作为实例的文件系统并用于持久化容器的存储;另外还使用S3这个对象存储服务作为OpenShift registry的存储。 ELB:总共有三个.一个用来在集群外访问OpenShift API、OpenShift console。一个在集群内访问OpenShift API。另一个用来访问通过route暴露的部署在集群中的应用程序服务。最后通过AWS的Route53来管理DNS。
在AWS中部署OpenShift集群包括三个阶段:
关于整个部署活动绝大多数都是可以自动化的。RedHat提供了一个GitHub repo:openshift-ansible-contrib。openshift-ansible-contrib提供了将OpenShift集群部署到不同的Cloud供应商的解决方案,当然也包括了AWS。里面包含了相应的文档、代码以及脚本。RedHat提供了一个叫做openshift-ansible-playbooks的RPM包,openshift-ansible-contrib利用该RPM包来完成阶段1和阶段2,在阶段3中我们可以利用一些现有的脚本工具实现环境检查和认证。
选择部署的AWS区域需要至少有三个可用区以及2个EIP。该OpenShift平台需要新建三个公共子网和三个私有子网。 由于需要新建一大批的AWS资源,所以必须要提供一个有适当权限的AWS用户,包括创建账号、使用S3、Route53、ELB、EC2等。
六个子网需要在一个VPC中。Ansible脚本会建立一个NAT Gateway用来供内部的EC2实例访问外网。同时也会建立8个Security Groups来限制不同的实例、ELB和外部网络间的访问。
openshift-ansible-contrib提供了部署基础设施、安装和配置OpenShift以及扩展router和registry的功能。运行Ansible的机器必须是RHEL7操作系统。具体的安装过程可参见https://access.redhat.com/documentation/en-us/reference_architectures/2017/html/deploying_openshift_container_platform_3.5_on_amazon_web_services/deploying_openshift%E3%80%82
在AWS上部署OpenShift平台并不是一件轻松的事情,一方面需要对AWS的各种服务了如执掌,一方面也需要对OpenShift的架构和核心概念有所了解。虽然RedHat提供了一些Ansible脚本和RPM包来简化安装,但整个过程也绝非一片坦途。安装完备之后,如何和企业现有的应用程序开发流程、持续交付流水线结合起来无缝过度,也是一件非常考验人的事情。下一篇文章会对这些方面进行揭秘。
]]>虽然在赛道上一度想再也不参加超长距离越野赛了,但是赛后没几天就好了伤疤忘了痛。看到跑友发的大山包越野赛的报名帖子后,心里又蠢蠢欲动。大山包离成都只有500多公里,可以坐火车过去,而且看了大山包景区的照片,是那么的漂亮,晚上还可以看到每天的星空,运气好还有流星雨。而且大山包还有一个翼装飞行基地,简直不能再酷。所以就报了名,并拉上了黄奎一起。
由于比赛在8月12日,整个5月份和6月份没有任何比赛,所以训练也比较懈怠。每次只是早上起来跑个5公里左右,拉拉速度。5月份出勤13次,总跑步距离71公里。6月份出勤15次,总跑步距离77公里。到了7月份我才有些慌了,打算加大运动量,并且报了7月29日的曾家山越野赛60公里组作为赛前拉练。
曾家山越野赛前我突击训练了几次,每次10公里,一个LSD也没拉过。结果比赛中状态不是很好,在第47公里处心态崩溃,主动退赛。在退赛的那一刻我觉得自己已经不可能完成大山包百公里越野了,想弃赛。但交通、住宿都已经订好了,而且报名费又那么贵,还是硬着头皮上吧。
离比赛还有10多天的时间,我开启了突击训练计划。7月31日到8月6日这一周,前五天每天跑10公里,第六天跑了5公里,星期天去龙泉山参加李科大神的训练课,学习上下坡技巧,并小小的拉练一下。接下来的一周只跑了一次10公里和一次5公里。
8月9号晚上完成赛前最后一练已经是夜里11点多了,刚躺下准备睡觉就发现几个跑群炸锅了。原来是大山包百公里由于不可抗拒的原因路线变了。新的路线和爬升还不清楚。这也太狗血了吧!第二天我才收到了新的路线和各CP点的关门情况。看来以前规划的策略都要变了。
8月11日早上我和黄奎、蔡立飞从火车北站出发,前往昭通。路上为了打发时间,我们斗地主,惩罚是做俯卧撑。打了几个小时我总过做了差不多200个。以前曾经突击训练过俯卧撑,这么点对我来说不算什么,就当是为明天比赛热身了。
达到昭通已经是晚上9点多了,还好赶上了组委会的一个小车去大山包。到了大山包已经是凌晨12点多了,赶紧整理装备,冲个澡睡觉,3点半起来去集合点准备做摆渡车到起终点。这一夜总共睡了3个小时,接下来还要奋战20多个小时不能合眼,命苦啊。
这次大山包比赛我的装备有了一定的升级,买了压缩裤和压缩衣。
我的穿着是:
越野背包中包含:
跑步腰包中包含:
我的换装包中包含:
我们到达起终点之后没多久,比赛就准时在5点开始了。起点到CP1只有6.8公里。0爬升,680的下降。由于天黑没亮,只有打开头灯跑,这段路是机耕道,但是由于连日下雨泥泞不堪,需要小心躲避各种水坑。本来打算和黄奎一起跑,但是没多久又因为人多加路烂冲散了。前面人太多,路由不好走,我想提速也提不起来,本来计划6分配速跑完,但实际上用了8分多的配速,到达CP1时是5点59分,比预计时间多了10多分钟。CP1人太多,粥都喝完了,我只补充了点可乐,给水袋灌了一瓶矿泉水就又匆忙上路。
CP1到CP2距离12.4公里,爬升368米,下降629米。这段路还是比较轻松的。刚出站就是一段爬升,天已经亮了,不过还有有雾,虽然视野也不是很开阔,但也能感受到大山包的壮美。爬升完后就是连续几公里的下降,一路小跑下去也没觉得累就到了CP2。我在CP2喝了点热水,听说下一个CP点有羊肉汤喝,就赶紧继续前进。
CP2到CP3只有5.6公里,526米的爬升和380米的下降。距离比较近,所以没觉得怎么发力就到了。这个CP点有鸡汤和羊肉汤。我连喝了两碗羊肉汤,然后拉伸了一下肌肉,继续前进。CP3到CP4有12.9公里,爬升569,下降729米。也是先爬升后下降的套路。爬升对我来说还好,不紧不慢的走着。接下来的下降对我来说就有点吃力了,毕竟右膝盖受过伤,做过手术,连续下降冲击开始隐隐作痛。不过我还是比较淡定,因为我早习惯了每次跑到20公里左右右膝就会疼痛,而神奇的是随着距离的加长它会不再疼痛。
到达CP4是10点多,稍作补给,喝了几碗鸡汤,吃了几块鸡肉,还有一些西瓜,开始向CP5进发。这段爬升就比较剧烈了,6.8KM爬升有721米,下降有268米。这是魔鬼赛段的开始,一直爬到有两个巨大石头处到了我们全程的最高点。两个巨大石头前的爬升让我恍然有了环汶川越野赛的感觉,那垂直爬升巨酸爽。CP5到CP6官方路线说爬升有760,下降有140.所以我在CP5就多休息了一下,喝了鸡汤,放松了一下大腿肌肉,然后继续进发。但是跑了好一段路发现都是下降,没看到爬升。一路上都是沿着路标跑的,不可能跑错,那大爬升在哪里那?一路怀疑自己,不知不觉就到了CP6.我一直质疑这是个假的CP6,说好的700多米的爬升那?
CP6是个换装点,所以我在这里呆了有半小时。我脱了长袖长裤,换上了厚的裤子和冲锋衣。脚由于前面数次涉水已经被泡的发白,我洗干净后换了五指袜,又换了一双新的鞋子。穿上新鞋一切轻松,喝了碗姜汤感觉完全恢复了。这时候是下午2点,也就是说前50公里花了9个小时,这个时间我还比较满意。离关门时间还有19个小时,时间绰绰有余。
CP6到CP7距离11.7公里,爬升769米,下井258米,绝对的硬仗。一开始就是连续的爬升,不过都是缓坡,而且是机耕道,路比较好走。我每爬40分钟就休息一下,吃一根能量胶继续前进。我发现能量胶真是个好东西,每次没力气了,吃了根胶又可以继续干。随着不断的爬升,风景也越来越好,最后到达了一个地方,到处是连绵的草甸,还有巨大的太阳能发电厂。CP7就这样不期而遇。CP7的补给比较简单,我只喝了两杯可乐,休息了20分钟才依依不舍的出站。
出站之后就是一段下降。我这时候也没赶时间了。有当地小孩要和我合影,我们一起拍了几张。中途也曾停下来休息,和几个当地小孩聊天。他们问我是不是还在上学?上学难不难?参加这个比赛累不累?那两个长棍子(登山杖)是干嘛的?…我和他们聊了10多分钟,期间拉伸了股四头肌,然后才出发。有一段比较剧烈的下降,让我再次感受到了环汶川越野赛的感觉。由于有些地方有青苔,一不小心摔了好几次。最后不得不降低速度,慢慢挪下来。
挪到底后有一条小河,在这里遇到了跑友曾鹏,我们拍了几张照片后继续前进。过了河又是无尽的爬升。我碰到了一个当地村民,人家背个大包包,左右手各提着一大堆东西,爬这种50度的坡气都不喘。我和他边聊天边往上爬。到了半山腰由于路线原因我们就分开了。天色渐渐暗了,终于在天黑前到达了CP8。我进站前有一群小朋友站在一旁给我加油,让我受宠若惊。站内也只有我一个人,志愿者太热情了,不停的问我需要什么。我喝了点姜汤和羊肉汤,休息了20多分钟,放松了肌肉后才出站。虽然已经跑了70多公里,但感觉身体各方面状态都挺好的,唯一一个地方是压缩裤没有调整好,有点磨档,教训啊!
出站没多久天就黑了,拿出头灯继续前行,期间碰到几个警察热心地给我们鼓励。天气刚黑就起了大雾,由于路上路标太少,而且反光标很少,我一下子就迷路了。往回退了几百米碰到了和我一起出站的范哥和老黄,遂决定一起前行。其实CP8到CP9的路途比较简单,只有264米的爬升和321米的下降,白天跑起来肯定相当轻松。可惜大晚上的雾太大了,我戴着强光头灯能见度不到5米。头灯照着地下都看不清楚路况。我们一个人在前面找路,一个人在后面照明,慢慢前行。这么大的雾绝对是寂静岭的既视感。到了CP9志愿者都劝我们不要继续前进了,前面雾太大,而且山路急弯多,容易出事。我当时想三个人一起还是比较安全的,大不了慢慢走,全程不跑。CP9物资并不多,我只喝了一点白开水。
出了CP9没多久我们就迷路了,我去探路,沿着一条大路跑了将近700米都没看到路标,只好原路退回来。在这里折腾了将近20分钟,都没找到前进的路,直到后面来了三个小伙伴,我们才找到了正确的路要从一个小道上切过去。这时候我们组成了一个6人团体,集体前往CP10.前半段我们的速度比较慢,只有20分的配速。大雾也时有时无,我们一路紧紧看着路标,放置迷路。因为在这种大雾里面迷路是致命的,一旦走错了路再返回很容易泄气。后半段石子路的下坡我们越走越快,终于在凌晨1点半时赶到了CP10。
刚到CP10志愿者说恭喜我们完赛了,由于安全考虑组委会已经终止了比赛,凡是到达CP10的都被认为是完赛了。我一听这个第一反应不是高兴,而且彻底懵逼了。当时我身体各方面状态都非常好,下坡也能跑起来,已经干了91.8公里,只有13公里到终点了你告诉我比赛终止了?我想继续前进,奈何没人响应,自己一个人跑也不太安全,只好作罢。
我们在CP10等了3个多小时才等到了转运车,回到酒店已经是凌晨5点多了。洗了澡睡觉真是舒服。早上9点多起来吃饭,取换装包,退手环,领完赛衫和完赛奖牌。这次比赛就告一段落了。
这次比赛组委会有很多地方没做到位,比如路线图和实际不符,CP5到CP6的爬升下降搞反了,CP10到终点的距离绝对不止13公里;路标不太完善,尤其是晚上的路标,在大雾中找路标太难了,反光标又太少,而且一些岔路口甚至没有路标;换装点和运动员预期不符,本来有两个换装点,但实际上只有一个在CP6,很多运动员到了CP8后才发现包在CP6,严重影响运动员接下来的比赛。
当然,我们也可以看到组委会和志愿者都是非常辛苦的。组委会在临时被迫换线的情况下迅速探出了新路线并布线,难度不可谓不大。组委会的贺胜珠一直在忙,赛前还给我打好几个电话联系车的事情,在CP10回起终点的路上也带领运动员去领包和去酒店住宿,可以说是24小时连轴转。而起终点和各个CP点的志愿者们都是超级热情,完全是在全心全意服务。当地的村民也很热情,有些CP点还烤土豆给我们吃。
这是我跑的最轻松的一次百公里,总结了一下原因如下:
不过也有值得总结经验的地方:
今年的百公里征战就告一段落了。好好练一练,明年再跑几次,玩玩铁三。
]]>术后一年的纪念文章在这里:膝盖中了一箭之康复篇-一周年纪念。
整个康复历程的文章在这里:https://www.google.com.hk/search?safe=active&q=site%3Awww.huangbowen.net+ACL&oq=site%3Awww.huangbowen.net+ACL
这一年总的基调就是稳步前进。右膝盖已经恢复的相当好了,当然离完美还差的远。
2016年重回越野跑行列。并且在一周年之际完成了复出赛,环汶川50公里越野赛成功完赛。这标志着休养生息正式结束,开始主动出击,重回挑战自我的轨道。所以2016年7月份参加了张掖100越野赛,第二次发起百公里冲击。不过50公里处被关门,倒不是因为膝盖的问题,而是自己战术错误没保温,再加上组委会也干了一些傻逼的事情。
之后又去了印度呆了两个月。在这两个月中可把我的膝盖给操练爽了。印度TWU教练团队有爱踢球的、有爱打球的。这些活动我当然要加入啊,能够自由自在的打球和踢球是多么的幸福。我们每周一次踢球、数次打球。膝盖没有什么明显的不适,当然我们的对抗也不是很激烈。
除了打球和踢球,我还每周数次去健身房举铁,周末还要正常的跑步训练。再加上适当的节食,我的身体素质进步的很快。趁着周末我还参加了PUNE当地的两次跑步活动,跑了一个半马和1个10公里。
一切都看起来很美好,似乎我的膝盖已经完全康复了。但是意外往往来的猝不及防。9月份在PUNE当地一个有名的花园中常规刷半马的时候,当我跑到10公里时膝盖突然出现弹响。几乎每跑2步就会响一次。当时暗想遭了,不过还是坚持完成了后10公里的路程。
回去后我发现右腿在从弯曲到伸直的过程中膝盖会发生弹响,感觉里面有组织在摩擦。接下来一周我没事就活动髌骨,按摩膝盖,但效果不大。我一度怀疑是不是接的韧带又断了。
第一次发生弹响的一周后在PUNE有个12小时超级马拉松的比赛。我一直在想要不要弃赛。不过最后一刻还是选择去参加。由于晚到了1个半小时,所以我总共跑了10个半小时,66公里。其实整个赛道并不是平路,而是山路,相当坑爹。跑到30多公里的时候伤膝就痛的不行了。膝盖受伤对平路和上坡影响不大。而下坡就比较痛苦了,身体重量不断冲击膝盖,速度根本不敢提起来。
跑完超级越野赛不久我就回国了。10月份长假去了川西自驾游。由于腿还没有好利索,爬黄龙时非常吃力,心里也是很忐忑是不是韧带又断了。过完长假就去找主治医生复查,也顺便照了核磁共振。高医生看了报告说恢复的非常好。我问弹响是怎么回事?他说接的再好也没有原装的好,我这个比大多数人都算恢复的好的了。
看了医生以后我算吃了一颗定心丸,说明韧带还没有断。不过由于膝盖还是有不适,我只好弃赛了10月中旬的大理100。11月份的四姑娘山越野赛也因为训练太少外加高原反应而被退赛。
由于膝盖不适,接下来我没有进行大量训练,心情糟糕也没有坚持去健身房健身。2016年末的我体重猛增,最高时到了78KG。
过完年后已经是2017年的2月份。这时候在伸直膝盖时还会有弹响,但跑步时影响已经不是很大了。所以我开启了晨练计划。每天早上7点起床,跑步5公里左右,然后做一组引体向上、臂屈伸和垂杠举腿。到现在算起来出勤率大概有50%。
2月份以后也开启了越野跑和马拉松比赛。先后跑过20公里、30公里、40公里等不同组别、不同难度的比赛,也跑过一次全马,不幸的是跑蹦了。这一切也是为了备战4月份的江南100越野赛。
4月份江南100越野赛是我第三次向百公里比赛发起冲击。颇有不成功便成仁的气势。最后我以28小时49分的成绩成功完赛。各中历程就不复述,我的赛记里面写的有。
完成百公里越野赛后,我终于可以考虑铁人三项的训练了。考虑到游泳是我的短板,所以5月初找了一家公司附近的恒温游泳池,办理了年卡。每周差不多去训练4次左右,学习自由泳。都说游泳不伤膝盖,是恢复的好方式,我要试试效果。
2017年前半年去健身房举铁的次数很少,平局1周一次吧。主要是大部分时间都投入到了游泳上。
目前我体重74公斤左右,正在备战8月份的另一场百公里赛事。韧带术后重建的标签已经离我远去。潜意识里我已经不是膝盖做过手术的人了,而是一个正常的人。
自我感觉我的恢复还是相当不错的,整个恢复历程还是比较顺利的,唯一的小波折就是弹响,不过目前对我影响不大。
运动可以重塑一个人的人格,我还在路上。
]]>HashiCorp Vault在2016年四月进入了ThoughtWorks技术雷达,位于Tools分类,处于ACESS级别。在2017年3月份最新一起Tech Radar中,HashiCorp Vault已经处于TRIAL级别。
https://www.thoughtworks.com/radar/tools/hashicorp-vault
在企业级应用开发过程中,团队每时每刻都需要管理各种各样的私密信息,从个人的登陆密码、到生产环境的SSH Key以及数据库登录信息、API认证信息等。通常的做法是将这些秘密信息保存在某个文件中,并且放置到git之类的源代码管理工具中。个人和应用可以通过拉取仓库来访问这些信息。但这种方式弊端很多,比如跨团队分享存在安全隐患、文件格式难以维护、私密信息难以回收等。
尤其是微服务大行其道的今天,如何让开发者添加私密信息、应用程序能轻松的获取私密信息、采用不同策略更新私密信息、适时回收私密信息等变得越来越关键。所以企业需要一套统一的接口来处理私密信息的方方面面,而HashiCorp Vault就是这样的一款工具。
HashiCorp Vault作为集中化的私密信息管理工具,具有以下特点:
存储私密信息。 不仅可以存放现有的私密信息,还可以动态生成用于管理第三方资源的私密信息。所有存放的数据都是加密的。任何动态生成的私密信息都有租期,并且到期会自动回收。
滚动更新秘钥。用户可以随时更新存放的私密信息。Vault提供了加密即服务(encryption-as-a-service)的功能,可以随时将密钥滚动到新的密钥版本,同时保留对使用过去密钥版本加密的值进行解密的能力。 对于动态生成的秘密,可配置的最大租赁寿命确保密钥滚动易于实施。
审计日志。 保管库存储所有经过身份验证的客户端交互的详细审核日志:身份验证,令牌创建,私密信息访问,私密信息撤销等。 可以将审核日志发送到多个后端以确保冗余副本。
另外,HaishiCorp Vault提供了多种方式来管理私密信息。用户可以通过命令行、HTTP API等集成到应用中来获取私密信息。HashiCorp Vault也能与Ansible、Chef、Consul等DevOps工具链无缝结合使用。
HashiCorp对私密信息的管理进行了合理的抽象,通过优良的架构实现了很好的扩展性和高可用。
Storage backend: 存储后端,可以为内存、磁盘、AWS等地方。
Barrier:隔离受信区域和非授信区域,保证内部数据的安全性。
HTTP API:通过HTTP API向外暴露服务,Vault也提供了CLI,其是基于HTTP API实现的。
Vault提供了各种Backend来实现对各种私密信息的集成和管理。比如Authentication Backend提供鉴权,Secret Backend用于存储和生成私密信息等。
HashiCorp Vault作为私密信息管理工具,比传统的1password等方式功能更强大,更适合企业级的应用场景。在安全问题越来越严峻的今天,值得尝试HashiCorp Vault。
]]>在讲述AWS的认证体系之前,我们可以先探讨一下为什么要考取这样的认证。根据我接触的考证的人,总结出考证的原因主要是以下几个方面:
通过考证提高自己的竞争力。这是大部分想考证的人的目的。https://blog.cbtnuggets.com/2016/07/10-high-paying-it-certifications/一文中列出了IT领域薪资最高的10个证书,第一名就是AWS解决方案架构师认证。拿到认证的人员的平均年薪为125,871美元。在云计算领域,AWS是当之无愧的NO.1。阿里云在早期就是对标AWS,很多服务都是参照AWS做的。不过阿里云在国内市场的环境下也有创新,比如其开发的云盾产品,在各大云计算厂商中走到了前面。AWS随后也推出了类似的产品。
公司或部门要求员工考证。现在越来越的传统组织和企业拥抱公有云。据资料统计,目前有将近60%的国内网站运行在阿里云上。在拥抱云计算的同时,这些企业内的IT组织人员就需要掌握云计算相关的知识和技能。而考取认证可能就会成为企业和部门对公司部分员工的要求。另外云计算是一个很大的市场,除了各大云计算厂商外,他们都有很多合作伙伴。AWS也不例外。而要成为AWS的合作伙伴,则对公司内部考取认证的人数有一定要求。这也促使这些合作伙伴要求员工考证。
通过考证检验自己的技能学习情况。笔者就属于这个原因。笔者自从2012年接触AWS,至今已经将近5年。笔者在2013年通过了AWS的助理级解决方案架构师认证。后来也通过了开发者认证。目前正在积极备战解决方案架构师认证。
其实无论考证是处于什么目的,我想说应该抱着掌握AWS服务的使用的目的来学习AWS,考证只是对自己掌握情况的检验。有个考取了专家级解决方案架构师认证的同事打过这样一个比喻,AWS认证就像是一名登山者所带的一盒午餐,当他爬到山顶后,可以享用这盒午餐。而他收获的肯定不仅仅是这盒午餐,而是沿途上的风景,午餐只是附赠品。如果单纯为了花费最小的力气来通过认证,往往会事倍功半。
AWS的认证有路线图,主要分为Architecting(架构)、Developing(开发)、Operations(运维)三条线。每条线又分为助理级认证和专家级认证,必须通过助理级认证后才能考取相应的专家级认证。架构这条线的两个认证为助理级解决方案架构师认证和专家级解决方案架构师认证。开发这条线的两个认证为开发者认证和DevOps工程师认证。运维这条线的两个认证为SysOps系统管理员认证和DevOps工程师认证。也就是说开发和运维两条线的专家级认证是同一个证书。
举个例子,如果想考取专家级解决方案架构师认证,那必须先考取助理级解决方案架构师认证才行。而要考取DevOps工程师认证,则先要考取开发者认证或SysOps系统管理员认证两个证中其中最少一个。
另外每个证书都有有效期,其有效期为两年。到期之后可以重新认证。重新认证的费用和题量减半。由于云计算现在还处于高速发展的阶段,AWS每年都会推出很多新的云服务,也会对现有的服务升级。为了避免你掌握的知识过时,设置证书两年过期还是比较合理的。
本书主要讲述三个助理级认证的考经,由于专家级认证考试范围、考试难度、备考方式完全不一样,所以本文不会过多涉及。
根据笔者的了解,助理级认证中考取解决方案架构师的居多,而开发者和SysOps的人比较少。可能是因为每个IT技术人员都有一个当架构师的梦吧。其实笔者从考试经验来说,无论你选择哪种助理级证书,在备考的时候其实都是差不多的。也就是说用一种备考方式,可以三证通吃。根据笔者的经验,这三个证书考取的难易程度如下:开发者认证<助理级解决方案架构师认证<SysOps系统管理员认证。也就是说开发者认证难度最小,SysOps系统管理员认证稍难些,助理级解决方案架构师认证居中。
每个认证都有一个考试指南,目前只有英文版。上面有对想考取认证的人员的AWS知识和IT知识有要求。大家可以根据这些要求来判断自己考取哪个证书更有把握。
AWS助理级解决方案架构师的考试指南地址为:http://awstrainingandcertification.s3.amazonaws.com/production/AWS_certified_solutions_architect_associate_blueprint.pdf。
AWS开发者认证的考试指南地址为:http://awstrainingandcertification.s3.amazonaws.com/production/AWS_certified_developer_associate_blueprint.pdf。
AWS SysOps系统管理员认证的考试指南地址为:http://awstrainingandcertification.s3.amazonaws.com/production/AWS_certified_sysops_associate_blueprint.pdf。
我们以开发者认证的要求为例,看看想考取该证书需要具备什么样的能力。
AWS知识:
通用IT知识:
如果你目前还未达到指定的要求,没关系。至少知道了自己的薄弱点,通过学习补强再考。
目前助理级证书都提供英文和中文试卷。这对于英文不好的同学是一个福音。(想当年笔者考试的时候只有英文试卷)。助理级考试有模拟考试和正式考试。模拟考试为费用为20美元,共有20道题目,考试时间为30分钟。注意模拟考试最多考一次就行了。因为第二次的题目会和第一次的题目一模一样。正式考试费用为150美元,也可以通过中国认证合作伙伴通过人民币购买,费用为1,150人民币。正式考试有55道题,考试时间为80分钟。
AWS的认证题目都是选择题,有单选题和多选题。多选题题目会明确的告诉你有几个正确选项。每个助理级认证都有相应的样题,供你熟悉考试题型。
AWS 助理级解决方案架构师认证的样题及解析可参见我的博客:http://www.huangbowen.net/blog/2014/10/22/aws-cert-sample-question/。
AWS 开发者认证的样题及解析可参见我的博客:http://www.huangbowen.net/blog/2016/07/27/aws-developer-exam-sample-questions/。
AWS SysOps系统管理员认证的样题及解析可参见我的博客:http://www.huangbowen.net/blog/2016/08/01/aws-sysops-exam-sample/。
我们可以助理级解决方案架构师认证的几个题目作为示例。
Amazon Glacier is designed for: (Choose 2 answers)
A.active database storage.
B.infrequently accessed data.
C.data archives.
D.frequently accessed data.
E.cached session data.
这是一个典型的多选题。题目明确告诉有两个正确选项。正确答案为B何C。因为AWS官方文档是这样描述Glacier的:
Amazon Glacier is an extremely low-cost cloud archive storage service that provides secure and durable storage for data archiving and online backup. In order to keep costs low, Amazon Glacier is optimized for data that is infrequently accessed and for which retrieval times of several hours are suitable.
段落出处为:http://aws.amazon.com/glacier/?nc2=h_ls
Your web application front end consists of multiple EC2 instances behind an Elastic Load Balancer. You configured ELB to perform health checks on these EC2 instances. If an instance fails to pass health checks, which statement will be true?
A.The instance is replaced automatically by the ELB.
B.The instance gets terminated automatically by the ELB.
C.The ELB stops sending traffic to the instance that failed its health check.
D.The instance gets quarantined by the ELB for root cause analysis.
这是一个单选题,正确答案为C。因为AWS官方文档有这样一项描述:
Elastic Load Balancing ensures that only healthy Amazon EC2 instances receive traffic by detecting unhealthy instances and rerouting traffic across the remaining healthy instances.
本段落的出处为:http://aws.amazon.com/elasticloadbalancing/?nc2=h_ls。
考试并没有详细的分数线。AWS 认证的分数线是依据统计分析结果来设定的,并不固定。AWS 不会公布考试的分数线,因为试题和分数线可能会更改而不另行通知。2013年的时候,根据经验一般正确率达到65%以上就可以通过考试,拿到认证。但近年来这个比例也在上升。目前至少要70%以上才有保险拿到证书。
其实没有必要被认证的考试指南中的要求吓到。有些技能我们可能目前不具备,但可以通过学习来掌握。
AWS目前有近百项服务,分为18个类别。要想全部掌握要花的时间可不少。不过如果想通过AWS的助理级认证,只需要熟悉掌握主要的服务即可。对其他服务只需要明白其使用场景以及一些应用限制。
我认为需要熟练掌握的服务:
知道其应用场景和限制条件的服务有:
对于需要熟练掌握的服务,每个必须都要进行实战演练。而第二类服务,如果不想花费太多时间,可以不必进行实战演练,查看相关的文档即可。
在开始学习之前,请先去aws.amazon.com的官网注册一个新的账号。因为AWS对于新的账号有free tier(免费套餐)服务。AWS 免费套餐服务/产品包括自 AWS 注册之日起 12 个月内可供免费使用的服务,以及在 AWS 免费套餐的 12 个月期限到期后不自动过期的其他服务/产品。我上面列出的所有服务基本上都在AWS免费套餐范围内。拿Amazon EC2来说,在新账号注册后的12月内,你可以享受750 小时 每月 Linux、RHEL 或 SLES t2.micro 实例使用时间,以及750 小时 每月 Windows t2.micro 实例使用时间。 例如,运行 1 个实例 1 个月,或运行 2 个实例半个月都是免费的。这样的免费套餐足够我们进行实战演练了。注意账号时需要绑定一张自己的信用卡,否则无法注册成功。
注意目前AWS分为中国区和全球区,中国区和全球区的账号是不能通用的。并且中国区账号并没有免费套餐服务,所以只有注册全球区的账号才可以使用免费套餐服务。
在学习AWS初期,你一定会听到各种各样的缩写词,很容易迷失。这些专业术语有的是和AWS服务紧密相关的,比如ELB(Elastic Load Balancing服务的缩写)、SQS(Amazon Simple Queue Service的缩写)等。有些是跟网络安全紧密相关的,比如ACL、AAD、SG、MFA等;有跟应用程序服务相关的,比如SOAP、WSDL、WAF等。每当你看到一个不懂的术语时,先记下来,然后弄清楚它的意思。这样随着时间的推移不懂的术语会越来越少。你可以查看AWS官方的术语表来进行巩固。英文版本为http://docs.aws.amazon.com/general/latest/gr/glos-chap.html。中文版本为http://docs.aws.amazon.com/zh_cn/general/latest/gr/glos-chap.html。
要学习AWS,最好的文档当然是AWS的官方文档。目前AWS的官方文档有80%都进行了汉化处理。也就是说如果英文不是很好的同学可以看中文的文档。
访问https://aws.amazon.com/cn/products/?nc2=h_ql_ny_gsc可以看到AWS提供的所有服务,最上面的菜单可以切换语言。我们以想要了解EC2为例,点击计算类别,可以看到Amazon EC2。点击该服务后就会进入Amazon EC2的主页https://aws.amazon.com/cn/ec2/?p=tile。这里列出了EC2的介绍以及其优势。这些内容务必仔细学习,能够让你迅速了解一门产品并且明白其使用场景和优势。
点击菜单栏的产品详细信息可以进入到另一个页面:https://aws.amazon.com/cn/ec2/details/。这里不仅有产品详情,还有开发人员资源、常见问题以及入门手册。如果想动手练习对EC2的使用,可以访问https://aws.amazon.com/cn/documentation/ec2/。里面提供了HTML/PDF/Kindle三种格式的入门指南。可以按照入门指南的操作步骤进行操作学习。
每个服务都有常见问题页,比如EC2的常见问题页是https://aws.amazon.com/cn/ec2/faqs/。每个服务的常见问题页都必须要熟读并掌握,因为至少70%的考题的答案都可以在常见问题中找到。但是单纯背诵这些内容是无意义的,很容易忘记。必须要明白AWS每个问题的答案的背后意义,这样才有助于记忆。
AWS官方文档对每个服务介绍的非常详细,但内容很多,看起来比较累。而AWS的白皮书则总结了使用AWS的一些最佳实践和方式,并针对一些具体场景结合相应服务的特点给出了最适合的架构设计。https://aws.amazon.com/cn/whitepapers/列出了AWS的所有白皮书。重点需要掌握的白皮书有:
除了实战操作、查看文档外,观看视频也是学习的途径之一。Youtube有很多操作视频可以观看。另外cloudguru和LinuxAcademy网站上也有大量的视频教程。Cloudguru和LinuxAcademy都是需要付费的。LinuxAcademy按月付费为29美元每月,年度费用为228美元。Cloudgruru则按课程收费,比如助理级架构师认证课程费用为29美元。另外还提供打包服务,全部AWS课程的打包服务为149美元,共7门课。我备战AWS考试的时候都用过这两个网站的服务。总体感觉Linux Academy的课程要丰富一些,并且便宜。这两个网站都提供一站式的服务。在这里你既可以观看视频学习,也可以通过其创建的AWS资源进行免费操练,更可以疯狂刷模拟题。注意这两个网站中的模拟题比正式考题的题目要简单些。模拟题的题库也不大,比如助理级架构师的题库有300多道题。我当时是刷穿了,基本上300道题做完只会错3、4道。
一个没有什么AWS使用经验的IT工作人员,想要考取AWS助理级认证还是要花些时间的。但时间也不是想象中的那么长。我第一个认证当时认真准备了1个半月。每天至少花3个小时,最后以65%的准确率惊险过关。而第二个证则只准备了1周多,只花了20多分钟就做完了55道题,准确率达90%以上,轻松过关。根据我经验判断,如果没有AWS相关的使用经验,每天投入三小时的话,最多3个月就可以去考试了。因为需要熟练掌握的服务差不多有10多个,每三天掌握一个,需要30天的时间,而需要了解的服务也有10多个,每两天掌握一个,需要22天。剩下的一个月可以阅读白皮书、动手做实验加强理解、在网站上刷题,补充薄弱点。
每学习一个服务时,要求动手与文档相结合。尤其是必须要理解AWS管理控制台上操作时每个选项的具体含义。一般官方文档都会给出其具体意义。另外文档也会包含有实战中了解不到的内容。比如个人账户最多只能开启20个EC2,再多就需要申请;SQS消息队列中消息默认的存活时间是14天;S3中存储的最小对象可以为0KB等。这些都有可能会成为考试内容。
个人建议每学习一个服务都要动手记下笔记。俗话说眼过千遍不如手过一遍。这样也可以避免学习了后面的忘记的前面的。笔记可以时不时拿出来复习一下。
访问https://www.aws.training/certification?src=cert-prep可以安排一场模拟考试或者正式考试。模拟考试在网上可以直接进行。正式考试则需要去相应的考点。目前在中国有成都、重庆、北京、上海、广州、杭州、长沙、大连、济南、南京、青岛、深圳、苏州、武汉、西安、厦门、郑州等城市设有考点。周一和周五都可以考试,一般提前一周报名注册即可。
正式考试时需要带上个人有效证件(比如身份证、护照、户口本)等。考试一本是一个单独的房间,只有你一个人,使用的电脑是考试方提供的电脑。我的几次考试都是在成都考的。成都这边的网络比较差劲,答完一道题后,需要等好几秒才能进入下一题。虽然页面刷新时计时器会暂停,但是非常影响节奏。考试的时候只能带笔和草稿纸,不能带任何电子设备,手机等需要放在外面。做完以后可以提前交卷,也可以等时间到以后自动交卷。交完卷后你会立马知道自己的成绩以及通过与否。
正式考试80分钟要答55道题,每道题的时间只有不到2分钟,所以时间很紧促。由于所有的题目都是选择题,那么有一个窍门是在一张A4纸上划上下面一个表格:
每道题为一行,对于认为绝对错误的选项划x,对于认为正确的选项划o,对于不确定的选项划?。这样有助于整理思路,然后回头检查时可以缩小范围,提高准确率。
洋洋洒洒写了很多,最后再快速总结一下。
需要熟练掌握的服务(需要了解它们的方方面面):
知道其应用场景和限制条件的服务有:
备考路线图:
平心而论,AWS认证的含金量还是比较高的。因为它的考试题目(尤其是专家级的考试题目)都是综合性的,不会考什么冷僻知识点,都是现实使用中会碰到的问题。尤其是我在备战专家级解决方案架构师的认证中,了解了各种实际场景下如何结合云计算提供的服务进行架构设计。自己的架构设计能力得到了真正的提高。
]]>该书的阅读门槛很低,刚开始讲述了线程基础、线程同步、线程池等基本概念。接下来讲述了C#4.0引入的关于异步操作的任务并行库以及C#6.0中最新的关于异步编程的语法和库。另外也涉猎了并发集合、PLINQ及Reactive Extensions等用于提高异步编程开发效率的实用库。同时也讲述了异步I/O的常用场景和常见的并行编程模式。最后也讲述了在Windows 10以及其他操作系统平台上使用异步编程的一些范例。
作者Eugene Agafonov编写此书时展示了他娴熟的技术功底。本书几乎每一小节都附有详细的可运行的代码,并且作者对代码都进行了细致入微的解读。读者可以一边阅读一边实战,一点也不会觉得吃力。 本人在翻译和校审本书过程中得到了同事和家人的帮助和支持,华章公司的编辑们也给予了很多宝贵的建议,在此一并表示感谢。最后,希望本书能给大家带来一次超凡的阅读体验。
黄博文
]]>2017年4月16日用时将近29小时完成了自己的第一个百公里赛事-江南100。完赛很艰难,代价也是很惨重的,左脚磨了6个泡,右脚磨了3个泡。尤其是左脚赛后血泡出现了感染的迹象,愣是瘸了一周才有些好转。之前报了环汶川的60公里组,也只好忍痛改为30公里组。
环汶川越野赛的60公里组赛道相当的虐,60公里爬升就要5200米,相当于江南100的爬升了。如果参加60公里肯定又是一场苦战。30公里组相对来说温柔些,总爬升2000多。
5月29日早上我们一家人自驾来到了汶川。我先领了参赛包,然后把家人安顿好。这次有幸加入了LP战队,整了一套压缩服。30公里组下午两点钟发枪,正是当天最热的时候。
我这次的装备是:
背包中包含的东西有:
这次装备精简了很多,并没有带羽绒服、冲锋衣等厚衣服。因为我预估天黑前会从山上下来,不需要准备太厚的衣服。根据前面几个越野跑的完赛经验,我给这次越野跑定下了6小时完赛的目标。
下午两点发枪,30公里组和17公里组一起出发。天气非常热,温度差不多有30度。所以刚开始我只是慢跑。左脚水泡好了以后刚长出新皮肤,频繁接触地面还是有些隐隐作痛。为了不让受伤加深,我没有加速。赛道介绍说起点到CP1只有3.6公里,爬升500多米。这段路比较简单,都是机耕道,爬升也不是很剧烈。我一边快走一边频繁补水。到达CP1其实手表记录距离已经有将近5公里了,耗时接近1个小时。CP1有西瓜,我抢了两块吃。然后把一个水袋灌满饮料,一个水袋灌满水就继续前进。
CP1刚出站就有一个比较陡峭的爬升,很多人也在这里慢了下来。我感觉体力尚可,进入超人模式。连续几公里的爬升后是一个下坡。终于可以飞起来了。但是刚跑一会就觉得不对,这路太险了,只有一人宽,悬崖几乎没有任何遮挡。为了安全起见只好减速慢跑。这次组委会做的特别到位,危险路段都提前有路牌指示,提醒选手小心。下完坡又是一个长上坡。上到顶后有一段在山脊奔跑。在这里拍几张照片绝对是大片。接下来都是下坡了,一路下到底。下坡弱的毛病又显现出来。我按自己最舒服的节奏跑下山。下山之后穿过村庄后到达了CP2。
到了CP2耗时2小时20多分。如果要6小时完赛,接下来还需要保持相同的速度。但CP2到CP3是最难的一段,短短10公里有1200的爬升。我去年曾登过一次赵公山,1400爬升花了2个小时。而这段路走的比我想象中的要辛苦。我做了短暂补给后,就继续前进。刚开始时一段盘山路,爬完后又是一段碎石路段的爬升。碎石路段的爬升后就进入了野路。眼前的这座大山差不多要爬到顶。刚开始状态还好,爬起来很有劲。随着下午的临近,山上越来越冷。尤其是刮风的时候,短袖有些扛不住。而我感觉肠胃也出了点问题,喉咙很痒,咳嗽的时候干呕。我赶紧停下来取出长袖、长裤穿上。奥利奥也感觉吃不进去,就吃了一小包杏仁。快到山顶的那段路爬的异常艰难。基本上爬10多米就要喘几口气。最后一公里竟然花了个1个小时。到顶后看到机耕道我觉得太亲切了。顿时调整为跑步模式。左脚还是有些隐隐作痛,所以跑的时候也没追求速度。就9-10分的速度。
一路下降就到了CP3,已经是7点20多了。6小时完赛肯定是不行了。所以我就在CP3好好的休息了很久。我喝了3大碗牛肉汤,吃了好几块西瓜。吃饱喝足之后,才心满意足的出发,迎接最后的几公里。出站没多久,天就黑透了。我拿出头灯戴好继续前行。CP3到终点的这段路没什么技术难度,都是平坦的大路,偶尔穿插一些小路。我全程小跑,状态还是比较好的,后来甚至越跑越快。不过左脚水泡处经过长时间的摩擦,痛感也有些加剧。
过了红军桥,离终点越来越近。虽然是晚上9点多了,终点还有很多人在等待。在主持人的欢呼中我冲过了终点。整个比赛用时7小时26分钟。回到终点后坐在一把椅子上休息了半个小时,然后才一拐一瘸的去体育馆退了手环,领了牛奶。参加热土越野的比赛就是划算,这样的牛奶都已经领了好几次了。然后去饭店吃了一碗拉面,感觉又满血复活了。
这次比赛又一次暴露出了肠胃问题。看来以后训练或者比赛一定要养成吃东西的习惯。接下来还要继续参加热土的赛事。第一次穿压缩服上阵,感觉LP的压缩服穿起来很舒服,效果也好,能有效缓解肌肉疲劳,赞一个!组委会也一如既往的给力,各方面都很到位,志愿者都很热情。继续加油。
]]>而传统的基础设施运维管理具有以下几个问题。
被动响应。 产品团队获取服务器资源采用的是申请制,中间存在若干审批过程,以及需要等待运维团队实施,响应不及时。
自动化缺乏串联。虽然有一定的自动化,但不能做到无人值守,需要执行一些临时命令介入。由于环境释放和重建的成本高,因而倾向于不释放,导致资源利用率低。
和产品团队脱节。很难根据需求随时动态增加环境。需要额外的文档来描述环境,可能更新不及时。
产品团队是实施持续交付的过程中,必须考虑将基础设施的维护纳入进来,作为支持产品运行的一部分。以下是产品团队的持续交付流水线全景图。
从上图可以看出,产品团队除了管理项目本身代码外,还要管理环境定义脚本。环境定义脚本可以由基础设施自动化工具执行,动态创建和销毁和更新产品运行所需的环境(包括服务器、负载均衡器、防火墙配置、第三方依赖等)。
如果实现了这一点,那么就实现了基础设施即代码的雏形。Kief在《Infarftruce As Code》一书中对基础设施即代码定义如下:
基础设施即代码是一种使用新的技术来构建和管理动态基础设施的方式。它把基础设施、工具和服务以及对基础设施的管理本身作为一个软件系统,采纳软件工程实践以结构化的安全的方式来管理对系统的变更。
基础设施即代码有四项关键原则。
环境中的任何元素可以轻松复制。
一致性。 无论何时,创建的环境各个元素的配置是完全相同的。
快速反馈。 能够频繁、容易地进行变更,并快速知道变更是否正确。
可见性。 所有对环境的变更应该容易理解,可审计,受版本控制。
基础设施即代码的目标是:
标准化。 以代码来定义环境,实现开发环境、测试环境、生产环境的标准化。
自动化。 以自动化工具来驱动代码准备环境。包括创建环境、更新环境以及销毁环境。
可视化。 以监控来可视化环境信息。环境当前状态可视、环境变更历史可视、可追溯。
基础设施即代码实践会产生高成熟度的持续交付和DevOps。
在实施基础设施即代码时,要遵守以下实践。
Ansible、Chef、SaltStack、Terraform等基础设施自动化工具都有各自的描述性语言实现对基础设施的定义。使用DSL更容易通过描述性的语言定义基础设施,也有助于代码重用。团队成员能建立起共同理解,从而维护脚本。
以下是Ansible的一个playbook示例。
1 2 3 4 5 6 7 8 9 10 11 |
|
在编写环境代码的配置时,也要编写对环境的测试。确保所有服务器都正确进行了配置,遵守了所有的安全规则,网络连通性等进行了验证。我们一般提倡将测试代码和配置代码放在一起维护。这样配置代码更新的化,能保证测试代码也被及时更新。
一些典型的基础设施自动化测试工具有ServerSpec、Testinfra等。以下是一个ServerSpec的示例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
一旦采用了环境定义脚本实现对环境的控制后,需要将环境定义脚本纳入到版本管理中。并且之后所有的环境变更都应该先修改环境定义脚本,由环境定义脚本触发对环境的变更。登录到服务器执行一些临时性命令是被坚决禁止的。因为这极有可能会破坏环境的一致性。当重建服务器时,也不能保证能应用所有需要的变更。
下图是基础设施即代码的一个典型使用场景。
除此之外,如果想要在生产环境中创建可伸缩性的服务的话,也需要借助基础设施即代码这一实践。在高峰时期,系统可以根据定义的环境自动创建并加入新的节点实现动态扩容,并在低峰时将其销毁。当监控发现某节点失败,系统可以根据定义的环境自动创建新的节点来替换失败节点,实现自动灾难恢复。
最后是我们在某团队实施基础设施即代码的案例解析。这张图是某团队的基础设施架构图。
该团队使用AWS作为基础设施平台。我们选用ansible作为基础设施自动化工具,并结合AWS提供的cloudformation服务实现快速创建和销毁资源。所有网元都有清晰的角色划分,配套对应的配置脚本。从网络配置到网元配置以及应用配置都实现了全自动化。所有的配置脚本都和源代码一起托管在GitHub。团队所有成员都可以查看并修改。从无到有构建整套系统从以前的10人天缩短到了短短的2小时。
]]>去年的12月份报名了江南100越野赛的100公里组。之所以报名江南100,一是因为自己没有去过宁波,听过赛道很美,想去看看;二是疯马团有团报,报名费可以便宜不少;三是100公里组爬升5200+,爬升适中,但是关门时间长达30小时,比较容易完赛。之前尝试冲击过2次百公里都没有完赛。第一次是2014年4月份举行的大连100,跑到CP7第72公里处因伤退赛;第二次是2016年的7月份张掖100,在CP3到CP5的山脊上由于下雨失温,差点丢了性命,到达CP5后已经被关门了。江南100是我第三次发起冲击,如果这次不成功,我打算沉寂一段时间。如果成功了,我就可以开始准备铁三的训练,好好把游泳练一练。
2月份开启了我的晨练计划。每天早上早起跑上3到5公里,距离虽然不长,但是注重训练效率。
2月份出勤14次,总跑步113公里;参加28公里越野赛一次,爬升1900+,用时7个半小时。
3月份出勤18次,总跑步153公里;参加40公里越野赛一次,爬升2200+,用时7小时20分钟;参加全程马拉松一次,用时4小时50分钟。
4月份比赛前出勤6次,总跑步50公里;参加30公里越野赛一次,爬升1900+,用时5小时42分钟。
总体跑量还是偏少,体重也比较大。不过进步还是能看的到的,以前路跑时跑进500配速都要累的够呛,后来状态好时420的配速也能跑的出来。越野跑爬山能力也得到了提升。不过有两个隐患为完赛蒙上了阴影,一是毕竟膝盖有伤,一般越野赛20公里后下坡右膝盖会非常疼痛,导致无法跑起来;二是右脚踝跑步时会隐隐作痛,怕运动时间长了会更严重。
14号早上坐飞机到了宁波,先去拜访了高中班主任。高中毕业一晃都12年了,老班还是和以前一样年轻。中午老班请吃了宁波当地的海鲜,那个春笋很是鲜美,很久没喝酒的我也和老班喝了两瓶啤酒。下午坐车来到了奉化镇,领取了参赛包,参加了技术说明会,入住了酒店。这次成都也来了不少人,和二队、西米露、武老师、张团长以及其他地方的跑友一起吃了晚饭。回到酒店后就可以整理参赛包。
这次江南100我的穿着是:
越野背包中包含:
我的换装包中包含:
根据天气预报15日和16日都是大晴天,也就是说不用雨战了。我其实是比较怕雨战的,因为本来下山就弱,一旦下雨更是寸步难行。去年的江南100就是因为大雨而中断比赛。不过我依然随身带着一身长衣服,这是因为被张掖100的失温整怕了,所以决定以后只要进山保暖一定要到位。多背点东西无所谓,一定不要自己难受。在整理参赛包时我本想将头灯放在换装包中。因为根据估算如果下午7点天黑的话,我有将近12个小时完成50公里跑到CP4换装点,所以无需前半程携带头灯。但后来觉得万一没在天黑前到换装点,就惨了。所以把头灯放到了背包中,事后证明这个选择真是太明智了。
15日早上5点多起来排空,给水袋灌满水,和微比一起去吃了美滋滋的牛肉面,顿时浑身充满了力气。我们步行来到起点已经6点半了。随便照了几张照片,热了下身,随着主持人的倒计时,百公里征程又一次开启。
起点到CP1爬升9.5公里,累计上升888,下降393。这一段路主要是在雪窦山景区里穿行,大都是硬化公路和景区台阶。我们路过了弥勒道场、三隐潭等地方,景色非常的漂亮。不过我由于急于赶路,也没有停下来拍照,一直在按自己的节奏前进。9点25分我到达了CP1,比预计时间晚了25分钟。主要是这段路程其实并没有组委会说的9.5公里远,我跑了将近12公里,看来又遇到了加量不加价。赛前我一直担心这么多人会不会导致补给点补给不足,毕竟张掖的教训在那里摆着。不过到了CP1之后我才发现自己的担心是多余的。江南100的补给确实丰富,各种运动饮料、矿泉水、可乐、小番茄、橙子、香蕉、馒头、稀饭、面包….太丰富了,我喝了几杯可乐和宝矿力,吃了点水果,把水袋灌满水,包里揣了两节香蕉、手里拿了一个面包就出站了,只在CP站呆了不到10分钟。
CP1到CP2距离9.7公里,爬升586,下降556,算是比较轻松的赛段。所以我想在这段路多赶点时间,争取2个小时完成。这时候早上已经过去了,天渐渐的热了起来,我感觉气温已经到了30度以上,跑着真是一种煎熬。这段路主要是在一些景区小路里穿行,有的路段特别漂亮,还穿过了几个江南小镇。不过有一段铁丝网的狭窄小路发生了堵车,足足耽误了将近20分钟的时间。这段里程有不可避免的被加送了里程,到达CP2时间为11点26分,我也没有多做停留,依旧是补完水、揣一个馒头就出发了。
CP2到CP3距离13.5公里,爬升628,下降528,也是比较轻松的赛段,但是在高温下却完全不一样了,温度足有35度左右,还未怎么奔跑就疲惫不堪。我的胃也出现了点问题,啃着馒头却咽不下去,结果直接吐了,把刚喝的稀饭、饮料全吐了出来。其实我已经有了轻微中暑了,只是当然自己并没有意识到。无奈扔了馒头继续前进。不过我带的能量胶派上了用场,吃了一个能量胶后感觉恢复了一些体力。路上碰到了空心菜,诧异他怎么这么慢。他说赛前一直感冒,状态很不好。我没有多做停留,就说先走一步,一会来捡我。CP2到CP3有一段连续爬升,是一条古道。古道上也有不少来此爬山的游客和户外队。每隔一段距离就有一个小房子,有一些选手就在里面乘凉。我跑越野的习惯是只在CP点做短暂停留,中途一直保持行走的状态,即使减慢速度也不会停歇。这段路程略显痛苦啊,有些人热的直接在马路边上睡觉休息。这段路有个坡叫做绝望坡,坡度70度,都是松软的砂石泥土,我只能手脚并用爬上去。到了CP3已经是下午3点10分,也就是说这段13.5公里的路我花费了3小时42分钟。本来我想计划是3小时内绝对要完成的,但结果把之前积攒的时间浪费了一些。CP3碰到张团长也在,他说有点中暑,状态不好,想退赛。我知道CP3到CP4是最难的一段路,爬升1024米,下降1600米。这是一场硬仗,跑完这段路完赛就有希望。我在CP3好好的修正了一番,也给水袋加满了水。由于肠胃问题,吃不下东西,只好多喝点稀饭。我之前赛前把2个能量胶放在背包前面口袋,剩余三个放在背包后面。但跑步时我记得所有能量胶都在前面口袋。CP3前吃了两个,再也没找到其他三个。恰好在CP3灌水时发现原来还有三个在后面,赶紧把它拿到了前面口袋。CP3到CP4有3个能量胶的支援,这段路我感觉更有信心了。
我直到3点30才出CP3。CP3会经过一个农家院子,我征得主人同意后用他们的水龙头洗了一把脸,感觉好了很多。CP3要翻越座大山,一座是青虎湾岗,最高海拔979米,两一个是四明山主峰,最高海拔1018米。爬青虎湾岗真让我苦不堪言,爬了一个陡峭的小山包,抬头优势一个小山包。一个接一个爬的让人绝望。这时候我的体力也不行了,爬几个山头后就要坐下来休息一番。爬上青虎湾岗以后,又是一个坡度5、60度的陡降,我只能拿出屁降绝技,慢慢的滑下去。在向四明山主峰进发的过程中,天也渐渐的黑了,我摸出头灯,穿上了长袖、长裤,继续前进。当我爬到一个山脚下时,看到黑暗中有两块明晃晃的牌子,依稀写着佛生什么的,旁边还有个红色的灯一闪一闪,远处也有一些灯忽明忽暗。这完全是鬼片的即时感嘛。不过我胆子大,一点也不怕。不知爬了多久,终于到了四明山主峰了,一个光秃秃的山包,下面灯光点点。到顶后,我连说了10个F**K。根据路线图来看,接下来就是将近1000米的下降就到CP4了。但是这个下降也要了我的命的。刚开始坡度60度度,只能使用登山杖一点一点往下挪。然后又是坡度40多度的羊肠小道,体力消耗大再加上怕滑倒,我根本跑不起来。下山弱的毛病暴露无遗。为了强制自己赶时间,我开始数数,每次跑100步然后走一段路,然后再跑100步再走一段路。也不知过了多久,终于下到了大路上,也看到CP4的灯光,听到了CP4传来的喧哗声。挣扎着跑到CP4打了卡以后一屁股坐在椅子上休息。这时候已经是晚上9点了,提早关门时间2小时,CP3赛段耗时5小时51分钟。CP4早已睡倒了1大片,很多人也在此退赛,有人在大声咒骂农民想钱想疯了,加量又加爬升。我喝了两碗稀饭,给水袋灌满水,拿来换装包穿上了冲锋衣,并把一条厚裤子放到了背包中。无论什么时候保暖都是第一位。然后装上了5个能量胶。这时候我也有点想退赛了,感觉耗尽体能才跑了50公里,后面50公里拿什么来跑?而且头50公里用时14小时,后面50公里只有不到16小时的时间,在身体极度劳累的情况下几乎完不成了。但我又不是很甘心,这是第三次向百公里冲击,事不过三啊。我分析了一下后半段的赛程,CP4到CP5爬升876米,是一场硬仗,CP5到CP6爬升472米,相对比较轻松,CP6到CP7爬升660米,难度适中,CP7到终点爬升只有66米,简直是so easy。也就是说只要能坚持到CP7就肯定可以完赛,我又燃起了完赛的欲望。我休息到了9点30,毅然决然的拿杖前行。
CP4到CP5距离15.2公里,爬升876米,下降296米。这也是一场硬仗。刚开始路程比较简单,是一段缓爬升的土路。这样的土路走起来比较舒服,基本能保持12分的配速。后面数次要过溪水,我都是踩着石头通过的。远处也传来了打雷的声音,宁波春天多阵雨。由于有些地方下了阵雨,导致有些小路都是水,需要踩水过去。平路我走的还可以,但是稍微有些爬升的话走的就比较慢。有一段路我在独自前行时,有一组四个人超过了我,我就跟在他们前行。他们行进速度很快,我在后面竭尽全力跟着。后来前面一男一女不见了,只剩下两个大哥。我跟着这两个大哥一直到了另一段绝望坡。已经凌晨了,看到这么陡峭的绝望坡才能感觉什么叫做绝望。恰在此时来了一阵大雨,如果雨再多下一会儿肯定就爬不上去了。当我爬上了绝望坡后,两位大哥都不见了踪影。此时我的体能已经达到了极限,连走路的力气都没有了。还好CP4的爬升已经够了,只要一段下降就能到CP5。在下降的过程中,我感觉体力恢复了一些,能够小跑起来。这时候困的眼睛都睁不开了,随便看一眼路,然后前进。脑袋也出现了幻觉,感觉地上的草都升了起来,升到了半空。
赶到CP5后是凌晨1点23分。CP4到CP5总耗时4小时21分钟,还算满意。我在CP5连喝了几大碗稀饭,泡了一碗方便面,但就是吃不下去,一旦做出吞咽的动作就会反胃。好在CP点有咖啡,我一口气喝了4杯咖啡,又坐在椅子上吃了很多葡萄干、圣女果,还有哈密瓜。虽然吃了这么多,我还是觉得胃里空空如也,但是固体食物真是吃不进去。我尝试着站起来好几次,都感到头晕的很,差点栽倒在地上。另外还突然有阵雨来袭,引起CP点一阵慌乱。我又动了退赛的念头。那两个大哥已经出站走了。我一直休息到了2点钟才决定出站继续前进。因为我看到CP5到CP6爬升只有400多,下降却有500多,而且距离有10.5公里,不是很难。
出了CP5后我竟然发现我的状态出奇的好,能够一路小跑下山。那些白天都不敢跑的路晚上我竟然能跑起来。可能是太黑了,看不清楚,也不觉得怕滑到了。一段下降之后就到了硬化路面,走在硬化路面上就是舒服,我一路上超了好几个人。之后是一段石板路的连续爬升,一路上一个人默默前行。到CP6是凌晨5点05分。快到CP6时又下了大雨,还好我穿了冲锋衣。在CP6喝了一些粥,也没有加水,只是揣了一瓶宝矿力。由于长时间运动脚上已经有水泡了。我在CP6休息到了5点半才出站。我知道完赛已经问题不大了,因为马上天就要亮了,时间很充裕。
CP6到CP7距离有14.7公里,爬升660,下降500。刚开始有几公里大路,并且是缓下降。我快走加跑想多赶些时间。天也渐渐的亮了,恰好我的头灯也没电了,我收起头灯继续前行。其实这段赛道还是很漂亮的,在满坡的桃树林中不断的穿梭。我也数次停下来休息做休整,研究爬升图,估摸着还有多远。就这样走走停停到了CP7已经是早上9点了,只剩下8公里的路程了,胜利在望。我在CP7休息到了9点半才出站。天也渐渐的热了起来,我把冲锋衣脱下来绑在腰间,感觉凉快了很多。脚底的血泡的疼痛感越来越大,每走一步都是钻心的痛。本来愉快的8公里下坡也根本跑不起来,只能一步一步的挪。烈日当空,我明确的感觉到自己中暑了,头昏昏沉沉的感觉随时要晕倒。当走到一个下坡处时,有个志愿者说只有2.5公里就到终点了。我在这里洗了脸,感觉好了一些,咬牙跑了起来。可是跑了大约1公里看到路程显示还有96公里,我f**k。不过我并没有停止奔跑,还是继续下降。终于下降到了公路上,离终点只有1公里了。我实在是跑不动了,慢悠悠的走到终点。离终点200米的时候才象征着跑起来跑过终点。
张团长一直在终点等我们。到了终点合完影以后还给我做肌肉拉伸,那酸爽不摆了。整个比赛没抽筋的腿在赛后抽了起来,尤其是大腿股四头肌抽的我要死的心都有了。我挪到了医疗点让医生帮我处理水泡。脱了袜子以后,那水泡简直不忍直视。左脚有大小水泡5个,右脚有鸡蛋大的水泡一个。处理完毕后我根本都走不动路了,主要是水泡在脚板心,每走一步都是煎熬。
回到家后周一在床上昏睡了一天。周二早上挣扎着上班,但是脚痛的厉害,已经肿了,头也晕得很。只好下午再去医院看了脚,回家休息。其实如果脚上没血泡的话,两天时间应该就能恢复了。可是左脚的血泡比较严重,出现了化脓的现象,直到一周后才减轻了不少。
江南100的比赛组织还是很不错的。补给站的补给很到位,志愿者也是非常的热情,路标很清晰,没有出现跑错路或者迷路的情况。美中不足的是送里程和爬升,赛道距离提示和实际不符,有些CP点间距离过大。希望以后能够继续改进,做成更好的赛事。
]]>在这三年的跑步生涯中,我总共参加过4场在汶川举行的越野跑比赛。四场比赛,不同的心情。
第一场比赛是2014年12月份由成都跑客在汶川龙山举办的龙山越野赛。当时比赛很简陋,我们参赛的人被寂阳拉到龙山半山腰布瓦村上方,然后随便选了个地方作为起点就向龙山进发。我报名的是30公里组别,直达龙山最高处,关门时间8小时。我是最后一个完赛的,当时到终点时离关门只有几分钟的时间。这也是我第一次参加越野跑比赛。第一次越野跑比赛就这么的虐,但却给我带来了非常不一样的体验。我突然发现祖国风光无限好,与其去开发成熟的景区,不如随便找一个野外都有其粗狂之美。
第二场比赛则是2015年3月份由爱江山举办的爱江山龙山越野挑战赛。我报名的是60公里组别。当时我还写了一篇赛记:爱江山越野跑-又上龙山之巅。我还清晰的记得当时还吃上了寂阳给跑客的小伙伴带的私补,一大包牛肉。不过纵然吃了私补也阻挡不了被关门的命运。我在55公里处因晚到了半个小时只能接受被关门的命运。
我在赛记里面总结了被关门的原因,但其实最主要的原因是自己的膝盖早已经出了大问题,右膝盖十字韧带早在2014年12月份一次踢球时断裂了。接下来的重庆马拉松跑出了PW,大连100越野赛也在72公里处由于膝盖疼痛而无奈退赛。
从大连回来以后我去医院检查,才确诊了右膝盖的伤病。医生说可以保守治疗,但以后就不能再运动了。我不假思索的说要做手术,我要重回赛道。2015年7月1日我做了手术。术后当天就开始积极的康复。2015年9月份的时候我小心翼翼的恢复了跑步,当时每次只敢跑3公里,要花费半小时的时间。除了跑步训练外,我也开始在健身房积极的做力量训练,力求把腿部肌肉练结实了。整个2015年的后半年我都在养伤恢复阶段,没有参加任何跑步比赛,2015年的环汶川越野赛也只好华丽丽的错过了。
2015年后半年和2016年前半年一直都在积极的康复,整个康复历程我都记录着:http://www.huangbowen.net/blog/categories/acl/。
当看到2016年环汶川越野赛又要开始报名时,我毫不犹豫的报了名,选择它作为我的复出之战。2016年环汶川越野赛50公里组的赛道那是相当的虐,我还记得那个变态的爬坡,必须拽着绳子才能上去。14小时关门,我花了13小时多才到终点。整个途中伤膝虽然还有些痛,但在可以忍受的范围之内。快到终点时我还差点流下了眼泪。这说明了将近一年的训练康复的汗没有白流,我又可以尽情的享受越野了。这是当时的赛记:熊猫热土-环汶川50公里越野赛赛记
熊猫热土的成功完赛让我重新回归了越野跑的赛道。之后我又参加了好几场热土举行的越野赛都成功完赛,同事也给了我膝盖完全康复的错觉。在9月份的一次例行刷半马时,我的右膝盖出现了不适症状,每次曲腿都会带来弹响。和我的主治医生复查后,医生说再好的韧带也没有原装的好,自己要多倾听身体的声音。我不想再让伤势扩大,也不想停止运动。所以之后的比赛我就成了坚定的完赛党,只求完赛,从不拼搏。
转眼到了2016年10月份,热土越野又举行龙山越野跑,作为11月份四姑娘山越野跑的拉练赛。我当时膝盖不适还没有完全消除,所以只报名了一个12公里组别。高手们都去参加更远的组别了,别想到我还捡了个便宜,意外跑了个第一。第二名和第三名其实实力也是非常强,但是他们第一次跑越野赛,不知道看路标的重要性,跑错了路,多跑了将近10公里,把第一拱手让给了我。这也是我第一次跑步得奖,当然恐怕也是最后一次了。
回想起这四次汶川龙山之行的心情,第一次是兴奋、第二次是遗憾、第三次是激动、第四次是惊喜。2014年第一次来到龙山,那比赛是相当的寒酸。但是短短3年,赛事规模和水平已经有了质的改变。这些年有一些人一直在默默的坚持,推广越野跑的发展。在这里我想对那些对中国越野跑的发展做出贡献的人说,“你们辛苦了”!
这个月末我会再次来到环汶川越野赛的赛道上,愿赛事越办越红火。
]]>A: 集成,就是一些孤立的事物或元素通过某种方式集中在一起,产生联系,从而构成一个有机整体的过程。知识经济的社会,集成已经成了很重要的一个名词。各行各业基本都会用到集成。比如汽车行业,那么复杂的一台跑车愣是通过一大堆零件组装起来。对于这些传统行业,它们在研发成功以后,可以通过流水线的方法批量生产进行集成。而在软件行业中,集成并不是一个简单的“搬箱子”的过程。因为软件工业是一个知识生产活动,其内在逻辑非常复杂,需求又很难一次性确定,完成的产品与最初的设计往往相差很远。敏捷宣言中就有一条是说响应变化重于遵循计划。而且由于软件行业的迅猛发展,软件变的越来越复杂,单靠个人是根本无法完成。大型软件还为了重用及解耦,还往往需要分成好几个模块,这样集成就成了软件开发中不可或缺的一部分。
持续集成这个词语最早是由大名鼎鼎的martin fowler。他在早期进行软件行业实习的时候就发现一个问题,即集成是项目中的一个大难题。当他在英国一家软件公司实习时,项目经理亲口告诉他一个项目已经开发了好几年了,现在正在做集成,集成已经进行了好几个月了,每个人都很疲惫,并不知道集成什么时候才能结束。其中一个很重要的原因就是项目集成发生的频率太低,导致大家对项目很没有信心。
在《持续集成》一书中,对持续集成的定义如下:持续集成是一种软件开发实践。在持续集成中,团队成员频繁集成他们的工作成果, 一般每人每天至少集成一次,也可以多次。每次集成会经过自动构建(包括自动测试)的检验,以尽快发现集成错误。自从在团队中引入这样的实践之后,martin fowler发现发现这种方法可以显著减少集成引起的问题,并可以加快团队合作软件开发的速度。
A:如果想要谈持续集成的好处,那么我们应该先谈谈没有采纳持续集成,项目会出现什么问题。总体来说,没有采用持续集成的项目一般会面临下面四个问题:
没有一致的可部署的软件。只有在完成集成测试、系统测试后,才能得到可用的软件,整个过程中只有最后时刻才能拿到可运行软件。集成活动不一定在一个标准的构建机器上生成,而是在某个开发人员的机器上构建的,那么可能存在在其他机器上无法运行的问题。
很晚才发现缺陷,并且难以修复。 实践证明,缺陷发现的越晚,需要修复的时间和精力也就越大。从上一个可工作的软件到发现缺陷之间可能存在很多次提交,而要从这些提交中找出问题并修复的成本会很大,因为开发人员需要回忆每个提交的上下文来评估影响点。
低品质的软件。 由于集成时每次包含的代码很多,所以大家的关注点主要都是如何保证编译通过、自动化测试通过,而往往很容易忽略代码是否遵守了编码规范、是否包含有重复代码、是否有重构的空间等问题。而这些问题又反过来会影响今后的开发和集成,久而久之集成变得越来越困难,软件的质量可想而知。
而通过持续集成的活动,我们可以实现以下价值:
减少风险。缺陷的检测和修复变得更快。软件的健康程度可以测量。
减少重复过程。让人们有时间做更多的需要动脑筋的、更高价值的工作。通过对重要过程自动化,克服项目中某些成员对实现改进的抵制。
在任何时间、任何地点生成可部署的软件。对客户来说,可以部署的软件是最实际的资产。
增强项目的可见性。集成就像我们项目的一面镜子,通过这面镜子能够快速的了解项目目前的状况、存在的问题。
对开发团队的软件产品建立起更强大的信心。它能够帮我们有效的决策,注意到项目进展的趋势。
A:一个最小化的持续集成系统需要包含以下几个要素:
版本管理系统:项目的源代码需要托管到适合的版本管理系统中,一般我们使用git作为版本控制库,版本管理软件可以使用github、gitlab、stash等。
构建脚本:每个项目都需要有构建脚本来实现对整个项目的自动化构建。比如Java的项目就可以使用gradle作为构建工具。通过构建工具实现对编译、静态扫描、运行测试、样式检查、打包、发布等活动串起来,可以通过命令行自动执行。
CI服务器:CI服务器可以检测项目中的代码变动,并及时的通过构建机器运行构建脚本,并将集成结果通过某种方式反馈给团队成员。
A:以下是持续集成的一个全景图。从中可以看到我们需要版本管理系统、构建脚本、CI服务器、CI构建机器、反馈机制。
A: 持续集成并不是说只要代码能编译通过就是集成成功,我们已经把每次集成都看做一次完整的测试。任何迁入到代码库中的代码都应该是可以部署到产品环境的。拿一个Java项目为例,持续集成一般执行的任务有:
1.代码静态扫描:通过静态扫描确定代码的一些潜在bug,比如未被使用的变量等。
代码样式检查:团队一致定义出需要遵循的编码规范,并通过一些插件对迁入的代码进行样式合规性检查,防止不守规范的代码进入版本库。比如方法名首字母小写、类的大字母大写、if关键字后面需要加空格等问题都可以纳入到样式检查中。
单元测试、集成测试、系统测试:通过运行自动化的单元测试、集成测试、系统测试可以有效的保证迁入代码的质量。一旦有测试失败,开发人员就需要快速反应进行修复。
测试覆盖率检查:一般项目会设置一个测试覆盖率指标(比如80%),如果代码达不到这样的测试覆盖率,就不会允许代码迁入。这样可以保证开发人员在新增功能时也要为新加入的功能编写自动化测试。
编译打包:确保没有任何语法错误,生成构建产出物。
发布: 将通过完整构建的产出物放置到产出物仓库,以便进行后续部署。
这些任务都必须是能通过命令行自动完成的,不同类型的项目任务略有不同。
A: 其中有一个重要的原则就是fail fast,即快速失败。一般会把运行时间短的、价值大的任务放在前面,而运行时间长的任务放置到后面。因为构建成功的标准是所有的验证都能够通过,那么执行时间短的任务放在前面更更快的得到反馈。
A: 并不是说搭建了持续集成服务器就说明团队能成功运行持续集成了。持续集成是一个实践,所以大家要遵循一些原则。大家可以先思考一下问题:1.在CI服务器上多久会看到一次集成?2.CI服务器的集成结果是绿色居多(指构建成功)还是红色居多(指构建失败)?3. 当构建失败后,团队成员有没有第一时间修复构建?团队成员有没有在构建失败的情况下依然在提交代码?团队成员在提交代码之前有没有进行本地的私有构建?
从这些问题可以引申出持续集成中需要遵循的一些原则:
经常提交代码
不要提交无法构建的代码
立即修复无法集成的构建
编写自动化的开发者测试
必须通过所有测试和审查
执行私有构建
避免迁出无法构建的代码
Q8: 本地提交代码应该经过哪些步骤? A:本地提交可以采用经典的七步提交法。
]]>笔者作为一名有数年工作经验的Java程序员,仔细研读了这份手册,觉得其是一份不可多得的好材料。阿里巴巴在发布时所说,“阿里巴巴集团推出的《阿里巴巴Java开发手册(正式版)》是阿里巴巴近万名开发同学集体智慧的结晶,以开发视角为中心,详细列举如何开发更加高效、更加容错、更加有协作性,力求知其然,更知其不然,结合正反例,让Java开发者能够提升协作效率、提高代码质量。” 同时,阿里巴巴也期望这套Java统一规范标准将有助于提高行业编码规范化水平,帮助行业人员提高开发质量和效率、大大降低代码维护成本。
其实早在多年前,Google就已经把公司内部采用的所有语言的编码规范(其称为Style Guide)都开源在github上,地址为https://github.com/google/styleguide。在这份清单中,包括了C++、Objective-C、Java、Python、R、Shell、HTML/CSS、JavaScript、AngularJS、Common Lisp、Vimscript等语言的编程规范。并且Google还发布了一个用于检查样式合规性的工具cpplint以及Emacs中使用Google编程样式的配置文件google-c-style.el。看来Google中Emacs粉比Vim粉要强势的多。
Google为什么要发布这样的Style Guide那?因为它认为几乎所有的开源项目都需要有一组约定来规范如何编写代码。如果项目中的代码都能保持一致的风格,那么即使代码再多也会更容易被人理解。
Google的这份编程规范包含了很多方面,从”对变量使用camelCase命名法”到”绝不要使用全局变量”到”绝不允许例外“等。其Java编程规范包含7大部分,分别为介绍、源文件基本要求、源文件结构、格式化、命名、编程实践和Javadoc。每一部分又细分为很多子条目。如果采取条规范的原因不是很容易理解,都会配有相应的示例或者引用文章。
由于Google的这份编程规范目前只有英文版本,所以中国的程序员只有少部分人知道它的存在。并且只有更少的团队在真正的应用它,其中就包括我的团队。我们团队根据Google的Java style guide也演化出了自己的团队版本,放置在团队共享wiki上供大家随时查阅。我们根据自身的项目特点丰富了”编程实践”里的内容,并且新加入一个章节来描述编写Java代码的一些原则,比如简洁代码、组合优于继承、stream优于for循环等。
我想阿里巴巴发布的Java开发手册之所以叫做”开发手册”,而不是像Google那样叫做“Style Guide(样式风格)”,是因为它不仅仅局限于style guide这一方面,而是以Java开发者为中心视角,划分为编程规约、异常日志规约、MYSQL规约、工程规约、安全规约五大块,再根据内容特征,细分成若干二级子目录。根据约束力强弱和故障敏感性,规约依次分为强制、推荐、参考三大类。
该开发手册中的每一条都值得了解。限于篇幅原因,这里只列出”编程规约“中有感受的几条来评述一下。
15. 【参考】各层命名规约:
A) Service/DAO 层方法命名规约
1) 获取单个对象的方法用 get 做前缀。
2) 获取多个对象的方法用 list 做前缀。
3) 获取统计值的方法用 count 做前缀。
4) 插入的方法用 save(推荐)或 insert 做前缀。
5) 删除的方法用 remove(推荐)或 delete 做前缀。
6) 修改的方法用 update 做前缀。
B) 领域模型命名规约
1) 数据对象:xxxDO,xxx 即为数据表名。
2) 数据传输对象:xxxDTO,xxx 为业务领域相关的名称。
3) 展示对象:xxxVO,xxx 一般为网页名称。
4) POJO 是 DO/DTO/BO/VO 的统称,禁止命名成 xxxPOJO。
命名规约的第15条描述了在Service/DAO层对于资源的操作的命名规范。这一条的参考价值极大,因为我所有呆过的团队对于这一点都没有明显的约束,每个团队都有五花八门的实现。如果能遵守这一点,那么我们在操作资源时就会减少一些困扰。
2. 【强制】long 或者 Long 初始赋值时,必须使用大写的 L,不能是小写的 l,小写容易跟数字1混淆,造成误解。
说明:Long a = 2l; 写的是数字的 21,还是 Long 型的 2?
这是常量定义的第2条。从这一点可以看出阿里巴巴对代码可读性的细节扣的很严格。我也很赞同这一点。代码只需编写一次,而会被查看无数次,所以要力争在第一次编写的时候尽可能少的引入歧义。
1. 【强制】大括号的使用约定。如果是大括号内为空,则简洁地写成{}即可,不需要换行;如果是非空代码块则:
1) 左大括号前不换行。
2) 左大括号后换行。
3) 右大括号前换行。
4) 右大括号后还有 else 等代码则不换行;表示终止右大括号后必须换行。
格式规约的第1条终于终结了括号之争。这一条需要强制遵守,那么左大括号换行一派则被彻底排除在阿里巴巴之外。有人说不推荐左大括号换行可以减少行数,增加单个屏幕可以显示的代码行数。而有的人反驳说现在屏幕已经足够大,不换行则破坏了对称之美。其实对于我来说两种格式都有各自的好处,我都可以接受,只要团队能够坚持使用其中之一即可。
5. 【强制】缩进采用 4 个空格,禁止使用 tab 字符。
说明:如果使用 tab 缩进,必须设置 1 个 tab 为 4 个空格。IDEA 设置 tab 为 4 个空格时,请勿勾选 Use tab character;而在 eclipse 中,必须勾选 insert spaces for tabs。
正例: (涉及 1-5 点)
public static void main(String[] args) { // 缩进 4 个空格 String say = "hello"; // 运算符的左右必须有一个空格 int flag = 0; // 关键词 if 与括号之间必须有一个空格,括号内的 f 与左括号,0 与右括号不需要空格 if (flag == 0) { System.out.println(say); } // 左大括号前加空格且不换行;左大括号后换行 if (flag == 1) { System.out.println("world"); // 右大括号前换行,右大括号后有 else,不用换行 } else { System.out.println("ok"); // 在右大括号后直接结束,则必须换行 } }
使用空格代替tab字符进行缩进已经成为了编程界的共识。其主要原因是不同的平台甚至不同的编辑器下tab字符的长短是不一样的。不过Google在其《java style guide》中规定缩进为2个空格,而阿里巴巴约定为4个空格。由于4个空格的缩进比2个空格的缩进长一倍,所以如果在代码嵌套过深的情况下可能会很快超过单行最多字符数(阿里巴巴规定为120个)的限制。不过这个问题可以从另一个方面进行思考,如果由于缩进的原因导致单行字符数超标,这很可能是代码设计上有坏味道而导致嵌套过深。所以最好应该从调整代码结构的方面下手。
6. 【强制】单行字符数限制不超过 120 个,超出需要换行,换行时遵循如下原则:
1) 第二行相对第一行缩进 4 个空格,从第三行开始,不再继续缩进,参考示例。
2) 运算符与下文一起换行。
3) 方法调用的点符号与下文一起换行。
4) 在多个参数超长,逗号后进行换行。
5) 在括号前不要换行,见反例。
正例:
StringBuffer sb = new StringBuffer(); //超过 120 个字符的情况下,换行缩进 4 个空格,并且方法前的点符号一起换行 sb.append("zi").append("xin")... .append("huang")... .append("huang")... .append("huang");
反例:
StringBuffer sb = new StringBuffer(); //超过 120 个字符的情况下,不要在括号前换行 sb.append("zi").append("xin")...append ("huang"); //参数很多的方法调用可能超过 120 个字符,不要在逗号前换行 method(args1, args2, args3, ... , argsX);
关于换行Google并没有给出明确的要求,而阿里巴巴则给出了强制性的要求。Google特别提示通过一些重构手法可以减少单行字符长度从而避免换行,这一点我颇为认同。关于参数很多的方法调用超过120个字符需要换行时,这暴露除了过长参数列的代码坏味道,解决方式之一就是使用重构手法的Replace Parameter With Method的方式把一次方法调用化为多次方法调用,或者使用Introduce Parameter Object手法创造出参数对象并进行传递。
17. 【推荐】循环体内,字符串的联接方式,使用 StringBuilder 的 append 方法进行扩展。 反例:
String str = "start"; for (int i = 0; i < 100; i++) { str = str + "hello"; }
说明:反编译出的字节码文件显示每次循环都会 new 出一个 StringBuilder 对象,然后进行append 操作,最后通过 toString 方法返回 String 对象,造成内存资源浪费。
这是《Effective Java》以及其他文章中经常提及的优化方式,而且面试初级Java工程师时几乎是一个必考点。其实不仅是在循环体内,而是所有需要进行多次字符串拼接的地方都应该使用StringBuilder对象。
20. 【推荐】类成员与方法访问控制从严:
1) 如果不允许外部直接通过 new 来创建对象,那么构造方法必须是 private。
2) 工具类不允许有 public 或 default 构造方法。
3) 类非 static 成员变量并且与子类共享,必须是 protected。
4) 类非 static 成员变量并且仅在本类使用,必须是 private。
5) 类 static 成员变量如果仅在本类使用,必须是 private。
6) 若是 static 成员变量,必须考虑是否为 final。
7) 类成员方法只供类内部调用,必须是 private。
8) 类成员方法只对继承类公开,那么限制为 protected。
说明:任何类、方法、参数、变量,严控访问范围。过宽泛的访问范围,不利于模块解耦。思 考:如果是一个 private 的方法,想删除就删除,可是一个 public 的 Service 方法,或者一个 public 的成员变量,删除一下,不得手心冒点汗吗?变量像自己的小孩,尽量在自己的视线内,变量作用域太大,如果无限制的到处跑,那么你会担心的。
这其实就是经典的原则‘ Principle of least privilege’ 的体现。我们必须遵循这一原则,但不知为何阿里巴巴将其级别列为“推荐”。
7. 【参考】方法中需要进行参数校验的场景:
1) 调用频次低的方法。
2) 执行时间开销很大的方法,参数校验时间几乎可以忽略不计,但如果因为参数错误导致 中间执行回退,或者错误,那得不偿失。
3) 需要极高稳定性和可用性的方法。
4) 对外提供的开放接口,不管是 RPC/API/HTTP 接口。
5) 敏感权限入口。
8. 【参考】方法中不需要参数校验的场景:
1) 极有可能被循环调用的方法,不建议对参数进行校验。但在方法说明里必须注明外部参 数检查。
2) 底层的方法调用频度都比较高,一般不校验。毕竟是像纯净水过滤的最后一道,参数错 误不太可能到底层才会暴露问题。一般 DAO 层与 Service 层都在同一个应用中,部署在同一 台服务器中,所以 DAO 的参数校验,可以省略。
3) 被声明成 private 只会被自己代码所调用的方法,如果能够确定调用方法的代码传入参 数已经做过检查或者肯定不会有问题,此时可以不校验参数。
编写代码时,对参数进行校验是不可避免的。详细说又扯到“防御式编程”和“契约式编程”的话题上。这两项之所以列为参考,并没有强迫大家遵守。
6. 【推荐】与其“半吊子”英文来注释,不如用中文注释把问题说清楚。专有名词与关键字保持英文原文即可。
反例:“TCP 连接超时”解释成“传输控制协议连接超时”,理解反而费脑筋。
看到这一条我已经笑出来了。这一条说的很好,注释是用来阐述问题的,如果看了注释还一头雾水,那么这样的注释不要也罢。使用中文没什么可丢人的,解决问题才是王道。
7. 【推荐】代码修改的同时,注释也要进行相应的修改,尤其是参数、返回值、异常、核心逻辑等的修改。
说明:代码与注释更新不同步,就像路网与导航软件更新不同步一样,如果导航软件严重滞后, 就失去了导航的意义。
阿里巴巴对该条的说明非常到位。其实我们团队在编写代码时默认是没有任何注释的,因为我们追求的是self-explanatory methods。即代码本身已经就能说明它的用途。只有在很少的情况下需要添加注释。
编程规约的第九部分都是很好的tips,值得去了解和学习。
除了编程规约之外,日志规约、MySQL规约、工程规约和安全规约也都有极高的参考价值,这也是比Google的Java Style Guide出色的地方。这里就不再评述了。
阿里巴巴公布这个Java开发手册绝对是值得赞赏的事情。最后我也想给其提几点建议:
建议使用公开wiki的方式发布该手册,而不是采用pdf的方式。因为如果像google那样是公开wiki的方式的话,可以很方便大家参与修正和改进,并且可以看到版本历史。
该手册并没有明确的版权许可,只是在页脚处加入了“禁止用于商业用途,违者必究”的字样。Google的style guide的版权为CC-By 3.0 License,建议阿里巴巴能够指明其版权。
手册中的部分示例代码并没有遵守其列出的编程规约,有点打脸之嫌。比如以下示例代码:
Iterator<String> it = a.iterator();
while(it.hasNext()){
String temp = it.next();
if(删除元素的条件){
it.remove();
}
}
其while和if关键字与小括号之间并没有空格,违反了该手册中3. 【强制】if/for/while/switch/do 等保留字与左右括号之间都必须加空格。
这一规则。
集合处理中可以多推荐一些Java8的集合操作方法。
有些名词没有过多解释,比如很多人可能都不知道什么叫一方库、二方库。
希望除了这份开发手册以外,阿里巴巴也可以推出对应的checkstyle配置文件以及Intellij、Eclipse的配置文件。毕竟格式化这些事都可以交由IDE来解决,通过在构建时使用checkstyle插件也可以防止不合规的代码迁入到仓库,从源头上保证代码样式的一致性。
最后,希望这份Java开发手册可以持续改进,吸纳百家之长,成为每个入门程序员必看的手册。
]]>2016年的工作可以分为三大块。
1月份和2月份还在咨询团队。这两个月在某国内大型企业做技术教练。先后开展了TDD、Clean Code、Continus Integration等课程。做咨询的日子每天都有很多挑战,收获也是大大的。
3月份、4月份以及8月份和9月份在印度Pune做TWU的讲师。在ThoughtWorks错失了以毕业生的身份参加TWU,不过还好可以以Coach的身份参加TWU。全英文授课,一对一coach,全新的环境…TWU对我来说挑战颇多,但是它绝对是一段奇妙的经历。有幸和来自全球8个国家的coach一起服务了有史以来TWU最大的一期batch。我很幸运自己是其中的一员。我很怀念大家一起备课,一起上课,一起泡吧,一起看电影,一起玩游戏的日子。尤其是每周一次的足球活动,能够直接感受巴西桑巴足球的魅力。
5-7月份和10-12月份在某国外项目的offshore account上担任tech lead。经过在在咨询团队以及TWU的锤炼之后,自己在看待问题、处理事情完全换了一个视角。尤其是10-12月份,随便每天都很忙碌,但是自己也学到很多东西。
当我在出差时,健身比较规律,一周能保证3次以上的健身房训练。当回到家以后时间就不能保证了。身体素质的巅峰期是在4月底的时候,卧推可以达到70KG。最弱的时候就是现在了。现在每周保持一次的训练节奏。
全年非完全统计总共跑了1336公里,耗时163个小时。
有四场赛事值得纪念。
拖了1年多,终于将《面向对象的思考过程》翻译出版,也算是了却了一桩心事。另外也校审和翻译了《C#多线程编程实战》的第二版,此书已经在出版过程中。还有参与了《基础设施即代码》一书的合译,目前正在校审过程中。
今年写的博客数量少于往年。完结了《膝盖中了一箭》系列,因为实在不想再写这样的口水话文章。技术类的精品文章不是很多,不过还好在ThoughtWorks洞见上发表了好几篇。
在2016年初的时候,我定下了每月一个目标的计划,结果执行了8各月就半途而废了。2017年初想法很多,先按下不表,过完新年再计议。
]]>很多IT从业人员进入这个行业都是从学习一门编程语言开始的。对于编程,我们往往过于关注语言的语法细节,反而忽略了其背后的设计理念。面向对象的思考过程就是一个非常优秀的设计理念。它可以独立于语言存在。如果你熟练掌握了面向对象的思考过程,那么就可以轻松地在不同的面向对象的语言之间切换。
本书透彻地阐述了面向对象这一概念。作者Matt在书中反复强调学习面向对象的思考过程优于学习任何编程语言或工具。事实上,他也是这么做的。Matt阐述了面向对象的三要素:继承、封装、多态,并且自己加上了第四个要素:组合。关于组合,Matt不惜篇幅做了大量的讲解,并且列举了很多通俗易懂的例子,这也是本书的一大特色。
Matt也纠正了人们的一些普遍误解,比如面向对象的范式与面向过程的范式并不是完全对立的关系。而且在应用面向对象的设计和开发时,Matt也讲解了不少如何与遗留系统集成的技巧。同时,Matt也简要介绍了UML这个建模利器。为了不混淆重点,他把介绍UML的章节放置在很靠后的位置。因为他明白,先了解面向对象的各项概念是最重要的。
我虽然拥有多年的从业经验,但是再看本书时仍然有不少收获。其实自从我接触了函数式编程,就渐渐成为函数式编程的拥趸。我会时不时地“鼓吹”函数式编程范式的好处,顺便“贬低”一下面向对象编程。但同时我也有个疑问,既然函数式编程这么好,为什么这几年的发展只能算是波澜不惊,而没有掀起大风浪呢?读了本书之后,我似乎找到了答案。首先面向对象的思考过程更加符合大家对世界的直观感受,毕竟不是每个人都是数学家。函数式编程可以简化很多问题,但它并不能简化所有问题。其次是面向对象的编程范式和函数式编程的范式并不是完全对立的,正如作者讲过,面向过程的编程范式和面向对象的编程范式也不是完全对立的。比如目前流行的一些语言(Scala、Go等)都具备函数式的特点,也兼具面向对象的特点(只不过它们的面向对象的机制与传统的方式有所不同)。所以无论你喜欢哪种编程范式,了解彼此的不同之处是至关重要的。而本书则是了解面向对象范式的优秀书籍。
本书已经更新到了第4版。从本书长达10多年的跨度来看,面向对象范式经久不衰。Matt也适时地在新版中加入了一些新的主题,比如可移植数据、分布式系统、Web服务等。Matt不仅阐述了这些技术,还讲述了它们的前世今生。这样可以帮助读者更加充分地了解技术的演化之路。
无论你是否有面向对象编程的经验,本书都适合你作为面向对象思考的旅程开端。最后,希望本书能给大家带来超凡的阅读体验。
购买链接:《面向对象的思考过程第四版》
]]>在印度浦那有着一所很神秘的大学,叫做ThoughtWorks Univesity,简称“TWU”。每个加入ThoughtWorks的毕业生,都要接受在TWU为期5周的洗礼。笔者于2016年以讲师的身份,参加了两期ThoughtWorks University。整个经历真的是一趟奇妙的旅程,收获颇丰。在这个教授敏捷的大学,我领略到了如何以敏捷的方式来运作一所大学。
《Practices of An Agile Developer》一书讲到,一个项目适不适合敏捷有两个先决条件:第一点是项目是否以价值为导向,第二点是团队是否能够达到高度协作。
第一点也就是说整个团队有一个总体一致的目标。TWU拥有明确的目标,一切都是围绕着培养毕业生的四个方面:Customer Serivce Mindset & Skills(客户服务意识和技能), Business Understanding(ThoughtWorks业务理解), Culture/Way of Life(文化及生活方式), Global & Social Experience(国际经验及社会责任)。
只有打造一个相对扁平的组织,给予充分的信任和自由度,才有利于敏捷的实施。这反过来又要求团队中的每个人有高度的自律性。
TWU的团队主要分为核心团队和讲师团队。核心团队统筹管理所有的TWU活动,确保所有的课程和活动都是围绕着TWU的目标开展。而讲师团队则是由全球各个办公室的员工抽调而来,负责具体实施这些活动。整个TWU团队都是完全扁平的架构,没有上下级的关系。
第二点是说必须能够保证团队中的成员能够流畅的交流。我们那期的讲师来自8个国家:中国、马来西亚、澳洲、美国、印度、巴西、英国、德国。这样的国际化战队能够在组建之后立马投入运作的最大原因就是每个人在ThoughtWorks学到的深入骨髓的合作理念。TWU的核心团队和讲师团队每周都有固定的时间碰头,讨论遇到的问题并商讨解决之道。每天早上TWU的讲师也有固定时间站会,更新各自的状态。下午也有碰头会,讨论当天的工作内容、遇到的问题,并提出行动来解决。
这两个先决条件在TWU完全符合。
《Practices of An Agile Developer》中讲到敏捷的基础就是反馈。如果别人能及时指出你走错了路,那么你就会少走点弯路。只有不断的接受反馈并付出行动,才会不断的提高。反馈也是双向的,不仅自己要接受反馈,也需要主动给同事反馈。
在TWU,首当其冲要接受来自核心团队和讲师的反馈。每周我们有个很独特的活动,叫做Speedback Session。在这个活动上所有的讲师会进行一对一的4分钟的谈话,相互给予反馈。这种开诚布公的行为把大家都团结到了一起。
而在每期TWU的前两周,新讲师会对课程进行试讲,这是获取其他讲师反馈的好时机。笔者本人收到了很多反馈,比如说我的语速很合适、声音洪亮等,也有鞭策我提高的反馈,比如我的引导力能力不强,有的时候课堂感染力不够等。
讲师要给学生讲课,及时收集学生的反馈也相当重要。TWU团队在每个教室都专门制作了一面反馈墙,每次讲师讲完课后都会提醒学生通过贴纸的方式留下对本堂课的反馈。从这些反馈中我找到了自己的一些问题,比如有的学生说我的口音有点重,对一些技术词汇解释的不是很清楚。这会促使我下次讲课时注意解决这些问题。同时我也收到了很多鼓舞,因为很多同学都留言说学到了很多有用的新东西,很感谢我的付出。
正是这种良好的反馈文化让我在短时间内意识到了很多不足之处,也明确了改进的方向。它能使你每天都正面面对工作和生活,每天都能保持提升自己。
《Practices of An Agile Developer》一书中讲到敏捷的精髓就是拥抱变化。TWU每一期的学生来自不同的国家和地区,各自拥有完全不同的经历。这就要求我们在短短几天内充分了解团队中的学生,并且对课程进行相应的调整。
比如有一次我们要求学生团队进行一次软件发布活动,而当时他们还没有学习功能开关(Feature Toggle),正在思考如何实现只发布想要的功能,而屏蔽掉其他正在开发中的功能。为了能让他们自行思考发布策略,我们特意把介绍发布策略的课程往后挪了一天。
我们不仅会调整课程的安排,对于课程的内容我们也会经常更新。比如有一节教授HTML和CSS的课程,我们对课程进行了大幅改动,删除了一些过时的内容,加上了一些通用的最佳实践。这样的改动能够保证TWU所有教授的内容都能赶得上IT领域日新月异的变化。相比起国内大学有些课程还在使用几十年前的教材,而我们的有些课程可能每半年就会全部更新一次。
一些重大的改动会被放到一年一度的TWU年度升级中进行处理。在年度升级中我们有两个月的时间对TWU的关键活动做升级。比如今年就将TWU使用的整个技术栈全部迁移到了AWS平台,实现能够一键式创建和删除整个学期需要的资源。
TWU在课程的设置方面一直紧跟市场的变化。ThoughtWorks最近不断接收一些关于UX和XD的业务,而TWU当时并没有专门针对UX和XD的培训内容。但是短短三个月的时间TWU一群卓越的同事就创建了相关的课程,并迎来了第一批UX和XD的毕业生。
在TWU当讲师的几个月,笔者一直感觉这个大学是一个充满活力的大学。在这个大学里面,没有权威,没有各种条条框框,整个团队有一股极强的凝聚力,每个人是TWU的主人。运作一所大学不易,但如果能坚持做到持续反馈、拥抱变化的话,这所大学将始终是一所紧追时代步伐的大学。
]]>假设现在有一个保险公司,他想找一个软件公司做一个在线卖保险的系统。那么这个系统从开始到完成至少需要三个角色。
Business owner -> developer -> end user
只有这些角色能够顺利、成功的完成一个产品吗?实际操作中肯定会遇到很多问题。这些问题会集中在两个地方。
第一个问题出在Business owner和developer。在沟通需求的时候他们彼此会发现太费劲了。Business owner张口就来的quote、premium、policy这些名词软件开发工程师不懂什么意思,因为他们没有保险行业的背景知识,而软件工程师喜欢说的MVC、BDD、Java之类的,Business owner也搞不懂,并且人家对这也不感兴趣。那么软件开发工程师想,如果有人能即懂得保险行业知识,又具有IT背景,那么分析需求肯定会顺利不少。这样的人在敏捷团队中就叫做BA(Business Anslyst,业务分析师)。BA会理解并挖掘客户的需求,然后将需求转变为具体的AC(验收条件,Acceptance critirial),再交由开发工程师来实现。同时他也可以将业务知识最大化的传递给开发工程师,保证开发工程师能够准确的理解需求(为什么不让Business owner直接将业务知识传递给开发工程师那?原因很简单,人家可是一秒钟几十万上下的主,那里有这么多闲工夫。)
所以系统从开始到完成变成了这个样子。
Business owner -> BA -> developer -> end user
另一个问题就出现在了developer和end user之间。开发工程师完成的系统能够直接拿给最终用户用吗?如果你说能,要么你是对自己的产品信心十足,要么就是盲目乐观。我想大多数情况是后者。因为开发工程师在将业务需求转换为编码实现时,一方面由于理解的问题,实现或多或少可能会与需求有所偏差。另一方面由于自身思维的局限性,会导致系统隐含了一些缺陷。假如最终用户在使用系统时,发现在线支付有问题,或者页面在自己所用的浏览器下不能正常显示,你觉得他们还有兴趣使用你的系统吗?这就相当于把最终用户当做系统的测试者,人家不收钱还帮助我们发现bug,那里有这好事?系统的问题要尽可能的避免暴露给最终用户。那么在软件开发工程师和最终用户之间应该再加一个角色,就是tester。tester的主要职责就是按照AC,对系统进行功能性测试,确保功能的正确性,另一方面是针对一些非功能性测试(比如安全性测试,性能测试),保证系统的健壮性。
Business owner -> BA -> developer -> tester -> end user
做到这些的tester还不能称之为QA,因为它的角色更像是软件质量的看门人,最终把关者,还达不到测试分析的要求。
现在新的问题来了,到底tester什么时候该开始对软件的测试那?
一个极端情况是等developer把所有的功能完成以后,再交给tester来测。这样会造成很多问题。
大家都知道在软件工程中,需求变更发生的越晚,bug发现的越晚,会软件开发的影响会越大。这种极端情况的做法是不可取的。
那么应该怎么做那?我们可以将整个系统的功能细分成很多小功能点,每一个小功能点都是独立可测的,那么一旦开发工程师完成此功能点,tester立马就可以拿去测试。每一个小功能点就是敏捷中所说的用户故事(user story)。
一个user story的典型的生命周期是这样子的。
如果只是实现这样的流程,那么这个团队还不算是真正的敏捷团队,这里的tester也不算是真正的QA。因为业务需求通过Business owner到BA再到DEV到tester,是一个衰减的过程。小时候我们玩过一个游戏,老师让一群人排成一排,他会给第一个人说一句悄悄话,然后让第一个人偷偷讲给第二个人,第二个人再原封不动的讲给第三个人..直到最后一个人把这个悄悄话讲出来和老师的原话比较,我们往往发现最后一个人的话很难和老师的原话保持一致,甚至意思会大相径庭。那么这就意味着tester在做测试的时候他不一定能够真正了解业务的实际需求,所以在测试时难免会出现纰漏。这样的卡最后让business owner确认时,很难避免给business owner “惊喜”。
所以为了解决需求衰减的问题,tester要尽早的介入到的story的前期工作。在BA分析故事卡的时候,tester就可以根据卡的内容准备测试策略、测试环境,甚至准备测试数据。在开发人员领取卡的时候,tester可以从测试的角度给开发人员提供一些建议。而在开发人员开发卡的时候,tester可以和开发人员一起pair编写自动化的测试用例。开发人员开发完毕后,tester可以在开发人员的本地环境中快速验证其是否满足所有验收条件,必要的自动化测试是否已经完成等。在UAT环节,tester又可以帮助business owner进行sign off。
这个时候需求的传递已经不是一个简单的链式的行为,测试人员作为连接器把需求良好地串联了起来。测试人员的职责范围已经超出了我们通常所理解的范围。这个时候再用tester这个称呼已经无法涵盖该角色的职责了。所以就有了QA(质量分析师)这一角色。可以看出在敏捷团队中QA并不是质量的最终把关者,而是在项目开始就参与到了质量的控制当中,一直贯穿到所有环节。
如果想了解敏捷团队中QA的具体职责,可以参见我司的同事的文章《敏捷中的QA》. 如果你想知道自己适不适合QA,请参见我司另一位同事的文章《敏捷QA,从入门到放弃》
]]>批处理应用通常有以下特点:
Spring batch是一个轻量级的全面的批处理框架,它专为大型企业而设计,帮助开发健壮的批处理应用。Spring batch为处理大批量数据提供了很多必要的可重用的功能,比如日志追踪、事务管理、job执行统计、重启job和资源管理等。同时它也提供了优化和分片技术用于实现高性能的批处理任务。
它的核心功能包括:
笔者所在的部门属于国外某大型金融公司的CRM部门,在日常工作中我们经常需要开发一些批处理应用,对Spring Batch有着丰富的使用经验。近段时间笔者特意总结了这些经验。
在使用Spring Batch时推荐使用最新的Spring Batch 3.0版本。相比Spring Batch2.2,它做了以下方面的提升:
支持Spring4和Java8是一个重大的提升。这样就可以使用Spring4引入的Spring boot组件,从而开发效率方面有了一个质的飞跃。引入Spring-batch框架只需要在build.gradle中加入一行代码即可:
1
|
|
而增强Spring Batch Integration的功能后,我们就可以很方便的和Spring家族的其他组件集成,还可以以多种方式来调用job,也支持远程分区操作以及远程块处理。
而支持JobScope后我们可以随时为对象注入当前Job实例的上下文信息。只要我们制定Bean的scope为job scope,那么就可以随时使用jobParameters和jobExecutionContext等信息。
1 2 3 4 5 6 7 8 9 10 11 |
|
之前我们在配置job和step的时候都习惯用xml的配置方式,但是随着时间的推移发现问题颇多。
我们渐渐发现使用纯Java类的配置方式更灵活,它是类型安全的,而且IDE的支持更好。在构建job或step时采用的流式语法相比xml更加简洁易懂。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
在这个例子中可以很清楚的看到该step的配置,比如reader/processor/writer组件,以及配置了哪些listener等。
Spring batch在运行时需要数据库支持,因为它需要在数据库中建立一套schema来存储job和step运行的统计信息。而在本地集成测试中我们可以借助Spring batch提供的内存Repository来存储Spring batch的任务执行信息,这样即避免了在本地配置一个数据库,又可以加快job的执行。先为Job的配置类添加扩展类:DefaultBatchConfigurer。
1 2 3 4 |
|
我们在build.gradle中加入对hsqldb的依赖:
1
|
|
然后在测试类中添加对DataSource的配置。
1 2 3 4 5 6 7 |
|
并且在applicaton.properties配置中添加初始化Database的配置:
1
|
|
Spring batch在配置Step时采用的是基于Chunk的机制。即每次读取一条数据,再处理一条数据,累积到一定数量后再一次性交给writer进行写入操作。这样可以最大化的优化写入效率,整个事务也是基于Chunk来进行。
当我们在需要将数据写入到文件、数据库中之类的操作时可以适当设置Chunk的值以满足写入效率最大化。但有些场景下我们的写入操作其实是调用一个web service或者将消息发送到某个消息队列中,那么这些场景下我们就需要设置Chunk的值为1,这样既可以及时的处理写入,也不会由于整个Chunk中发生异常后,在重试时出现重复调用服务或者重复发送消息的情况。
Spring batch提供了大量的Listener来对job的各个执行环节进行全面的监控。
在job层面Spring batch提供了JobExecutionListener接口,其支持在Job开始或结束时进行一些额外处理。在step层面Spring batch提供了StepExecutionListener,ChunkListener,ItemReadListener,ItemProcessListener,ItemWriteListener,SkipListener等接口,同时对Retry和Skip操作也提供了RetryListener及SkipListener。
通常我们会为每个job都实现一个JobExecutionListener,在afterJob操作中我们输出job的执行信息,包括执行时间、job参数、退出代码、执行的step以及每个step的详细信息。这样无论是开发、测试还是运维人员对整个job的执行情况了如指掌。
如果某个step会发生skip的操作,我们也会为其实现一个SkipListener,并在其中记录skip的数据条目,用于下一步的处理。
实现Listener有两种方式,一种是继承自相应的接口,比如继承JobExecutionListener接口,另一种是使用annoation(注解)的方式。经过实践我们认为使用注解的方式更好一些,因为使用接口你需要实现接口的所有方法,而使用注解则只需要对相应的方法添加annoation即可。
下面的这个类采用了继承接口的方式,我们看到其实我们只用到了第一个方法,第二个和第三个都没有用到。但是我们必须提供一个空的实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
而使用annoation的方式可以简写为:
1 2 3 4 5 6 7 |
|
在处理百万级的数据过程过程中难免会出现异常。如果一旦出现异常而导致整个批处理工作终止的话那么会导致后续的数据无法被处理。Spring Batch内置了Retry(重试)和Skip(跳过)机制帮助我们轻松处理各种异常。我们需要将异常分为三种类型。第一种是需要进行Retry的异常,它们的特点是该异常可能会随着时间推移而消失,比如数据库目前有锁无法写入、web服务当前不可用、web服务满载等。所以对它们适合配置Retry机制。第二种是需要Skip的异常,比如解析文件的某条数据出现异常等,因为对这些异常即使执行Retry每次的结果也都是相同,但又不想由于某条数据出错而停止对后续数据的处理。第三种异常是需要让整个Job立刻失败的异常,比如如果出现了OutOfMemory的异常,那么需要整个Job立刻运行。
一般来说需要Retry的异常也要配置Skip选项,从而保证后续的数据能够被继续处理。我们也可以配置SkipLimit选项保证当Skip的数据条目达到一定数量后及时终止整个Job。
有时候我们需要在每次Retry中间隔做一些操作,比如延长Retry时间,恢复操作现场等,Spring Batch提供了BackOffPolicy来达到目的。下面是一个配置了Retry机制、Skip机制以及BackOffPolicy的step示例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
在Job执行过程中不一定都是顺序执行的,我们经常需要根据某个job的输出数据或执行结果来决定下一步的走向。以前我们会把一些判断放置在下游step中进行,这样可能会导致有些step实际运行了,但其实并没有做任何事情。比如一个step执行过程中会将失败的数据条目记录到一个报告中,而下一个step会判断有没有生成报告,如果生成了报告则将该报告发送给指定联系人,如果没有则不做任何事情。这种情况下可以通过Decider机制来实现Job的执行流程。在Spring batch 3.0中Decider已经从Step中独立出来,和Step处于同一级别。
1 2 3 4 5 6 7 8 9 10 |
|
而在job配置中可以这样来使用Decider。这样整个Job的执行流程会更加清晰易懂。
1 2 3 4 5 6 7 8 |
|
批处理工作处理的数据量大,而执行窗口一般又要求比较小。所以必须要通过多种方式来加速Job的执行。一般我们有四种方式来实现:
在单个step多线程执行任务可以借助于taskExecutor来实现。这种情况适合于reader、writer是线程安全的并且是无状态的场景。我们还可以设置线程数量。
1 2 3 4 5 6 |
|
上述示例中的tasklet需要实现TaskExecutor,Spring Batch提供了一个简单的多线程TaskExecutor供我们使用:SimpleAsyncTaskExecutor。
并行执行不同的Step在Spring batch中很容易实现,以下是一个示例:
1 2 3 4 5 6 7 |
|
在这个示例中我们先执行step1,然后并行执行flow1和flow2,最后再执行step3。
Spring batch提供了PartitionStep来实现对同一个step在多个进程中实现并行处理。通过PartitonStep再配合PartitionHandler可以将一个step扩展到多个Slave上实现并行运行。
远程执行Chunk任务则是将某个Step的processer操作分割到多个进程中,多个进程通过一些中间件进行通讯(比如采用消息的方式)。这种方式适合于Processer是瓶颈而Reader和Writer不是瓶颈的场景。
Spring Batch对批处理场景进行了合理的抽象,封装了大量的实用功能,使用它来开发批处理应用可以达到事半功倍的效果。在使用的过程中我们仍需要坚持总结一些最佳实践,从而能够交付高质量的可维护的批处理应用,满足企业级应用的苛刻要求。
]]>