Quantcast
Channel: IT社区推荐资讯 - ITIndex.net
Viewing all 15845 articles
Browse latest View live

英语听力训练三原则四个字

$
0
0
什么是听力训练的三原则、四个字呢。三个原则是:有恒,即持之以恒;有序,循序渐进;有量,要有一定数量的听力训练。四个字:3、6、9。什么是3?就是最好每次坚持进行至少30分钟的听力练习。6呢,一个星期,即进行至少6次的听力训练。9是一个层次的听力练习,至少要听够90篇以上的数量,如果条件许可,还可以在此基础上加大训练量。     “有恒”的道理,就不用说了。任何学问的取得,都离不开这个道理。没有恒心,想成就一番事业是不可能的。其实,我们国家很多学英语的人何其多也,但真正学成的,比例很有限,为什么呢?除了学习方法、天份等因素外,主要是没有坚持下去。听力练习,作为英语学习的一个非常重要的环节,其道理也是一样的。
    “有序”,是一种科学的方法。它适用于任何学科。只要科学地评判自己的水平,然后有针对性地制定适合自己的训练方法(而不是人云亦云),循序渐进,逐步攻克,并一步一步向前攀登。
    “有量”的原则非常重要。过去,人们对这个"量"的原则重视不够,或者强调不够。尽管人们都懂得"量变引起质变"这个哲学道理,但真正运用在语言学习上的人却不多。实际上这个道理非常浅显。但是越是浅显的道理,有时候越难让人置信。对于听力训练来说,量的原则尤其重要。很多人学英语,目标不可谓不明确、方法不可谓不得法、努力不可谓不努力,然而效果不明显。为什么?其实,很多时候,只是训练的量不够的缘故。这就好象是体育运动,如果你的训练量到不到教练要求的话,很多情况下是不可能获得预期的训练效果的。
    “量”的原则的具体体现,就是我们说的四个字。每次听力训练,坚持在30分钟以上。这主要是提供一次给耳朵和大脑接收有声语言输入的刺激过程,时间长度不够,刺激不充分,效果就不好。这其中的原理,有点像有氧运动。如果你不能每次坚持30分左右、心率在一定范围(因人而异)内的运动量训练,则效果一定大打折扣。所以,这个30分钟的量一定要坚持。可以是30分钟重复不停地听同一个内容,也可以听不同内容,长度相当于30分钟的材料,或者交错进行。总之,每次要进行至少30分钟以上的听力语言的熏陶。
    那么一个星期进行多长时间的训练为好呢?起码要进行6次以上的训练,每次30分钟。这个量的训练频率,加上最好以90篇素材内容为一个量的级别的高强度训练,可以逐步使自己在一个可控的范围内做到有目标和方向,又能循序渐进,即有序,加上可数的量的配合,最终达到一定程度的提高。并可以通过这种方法,逐步地、适时地进入到更高一级的层次。
免费在线英语体验:http://www.e-say.com.cn/favour/82467690

已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐




能让一个软件公司倒闭的软件开发方法,你干过几件?

$
0
0

我靠解决技术债务养家糊口。在我的工作中我看到许多难以维护的代码,并且一次又一次地看到很多相同的原本可以避免的问题。

我专长于调试,修复,维护和扩展旧的软件系统。我的典型的客户拥有一个尚可运行的网站或内部应用,但是开发者已经不知所踪。业务需求已经改变了但是软件没有跟上。抑或我的客户有了些“快要完成”的东西但是由于预算和日程安排的关系失去了开发者。通常那包括一系列尚未完成的功能和bug。

我的客户通常被别的开发者告知需要丢弃所有的东西从头来过。大多数程序员不喜欢维护代码,尤其是维护别人的代码。当程序员写代码的时候他们总是在可维护性上问错误的问题——关于这个话题详见Matt DuVall的文章: The myth of maintainability

我在这里为你的开发项目提供了一些建议以使我有活可以干。

不使用版本控制系统

我总是能惊奇地发现在过去几年写的大项目不使用版本控制。如果你不使用版本控制,下一任开发者就要找出哪些文件是现有系统的一部分以及哪些仅仅是备份。他没有任何提交信息和改动日志来知悉代码的历史。我在我的文章Introduction to Abject-Oriented Programming中讲述了如何不使用版本控制。

✓ 我就职的公司就是这样

个性化开发环境——越奇葩越好

不要让下一任开发者可以轻松地上手。要求特定的开发语言版本和工具,并且确保他们和操作系统自带的版本有冲突。疯狂自定义你的Eclipse或VisualStudio或vim,然后写一些只能在那个配置下运行的宏和脚本。不要创建一个磁盘映像或者脚本来重现你的开发环境,并且不要写任何文档——那给了太多提示。

✓ 我就职的公司就是这样

设计超级复杂的编译和部署步骤

把一个网站投入到正式服务器应该以下面的形式进行:

svn up
git pull
hg pull

程序员可以讨论代码是否简洁和优雅,然后他们转过身去建立最为详尽和复杂的展开系统。这是他们悄悄干的,不经过产品经理和客户的审查,也无法被理解的行为之一,所以它会轻易地失控。当你用不同的脚本语言把八个工具连接起来时,记得留下文档。

✓ 我就职的公司就是这样

没有测试/预部署环境

改变一个产品系统让人激动。不用麻烦去搭建测试或部署平台了。取而代之的,用秘密的登录方法或者用些后门URL来测试新特性。把测试数据和真实数据混合在你的数据库里。因为你没有使用版本控制,保存几份原先版本的拷贝以防万一。不要在代码里加入登录。不要在测试中关闭邮件发送,信用卡验证,等等。

✓ 我就职的公司就是这样

老代码一律删掉,重写软件

千万别用一个像Django, Rails, 或者CakePHP那样大家都能理解的框架。你可以写一个更好的引擎,ORM,排序或者哈希算法。当我看到一些例如“比原有字典更快的方法”或者“改变了PHP的库函数因为参数顺序烂透了”的注释时,我就要重置我的大脑。

✓ 我就职的公司就是这样

加强各种代码库/代码包之间的依赖关系

尽可能多的加入第三方代码。连接你需要连接的库。我见过用了大量的外接库只为调用某个方法的代码。改变第三方库的源代码这样它们就无法自动更新,但是千万不要用版本控制。这样我就能发现不同的地方从而还原出原来的版本。

✓ 我就职的公司就是这样

…对这些依赖关系坚决不写注释

我接到最多的紧急电话和更新出错有关。一个看上去无害的wordpress升级,Linux更新包,或者新的jQuery版本会造成一系列实效。不要把你的代码放到特殊的或者不用的第三方库版本下检测。甚至不要加上注释。

✓ 我就职的公司就是这样

混合多种不同的编程语言开发并且热衷使用前沿技术

每一天HackerNews和Reddit上涌现出新的酷的语言。在你的客户的东西上试试它们。任何合格的程序员可以在瞬间学会一种新语言,所以你的代码的继任者对其毫不了解也不是你的错。语言的边界,不兼容的API和数据格式,不同的服务器配置都是有趣的挑战并且值得在StackOverFlow上贴出来。我真的见过有人把Ruby嵌入PHP网站因为所有人都知道PHP很烂而Ruby更好。半吊子的caching, 流产的Rails和Node.js项目,特别是那些NoSQL方案都是我的好生意。

✓ 我就职的公司就是这样

该如何正确的开发软件?

你的代码是否完美地面向对象,光鲜亮丽都无关紧要——程序员在面对旧的系统时总是一团浆糊。我擅长用diff,grep和Ctag, 追踪代码,重构和调试。我会搞清楚所有的东西。最美丽,优雅的代码如果缺少了版本控制,加上太多从属关系和自定义,并且没有测试系统的话仍然是很难维护的。这就像在一群强迫性囤积症患者中找到一间干净整洁的屋子。

统计结果(2人/次)

50%
不使用版本控制系统
50%
没有测试/预部署环境

哈佛最受欢迎导师北大演讲:从幸福到更幸福的五个方法

$
0
0
哈佛最受欢迎导师北大演讲:从幸福到更幸福的五个方法
2014-08-27 有机生活馆

“Success→Happiness”对于社会上大部分人来说就像黑板上的公式。然而,只要取得成功就一定会感到幸福吗?不一定。如果成功不能让我们感到幸福,那到底什么能使我们感到幸福呢?本文是被誉为“哈佛最受欢迎导师”沙哈尔在北大的演讲实录,在演讲中他提出了让我们感到更加幸福的五个方法,简单有效,特选登于此与读者共享。

作者:泰勒·本-沙哈尔(TalBen-Shahar)

非常高兴今天下午能够到这里来演讲,人们都把哈佛大学称为北美的北大。对于我来说,在刚刚享受了美食之后,在这个时候向大家做一些演讲,实在是一大挑战。比起站在这儿,如果能美美地睡上一觉,是我更需要的东西。如果你们睡着了,我不会过去把你们叫醒,因为睡觉也是幸福的一个重要的组成部分。

我之所以会开设这门心理学课程,是因为曾经的我感觉自己非常的不幸福。实际上,我最开始在哈佛大学攻读的是计算机课程。当我到大学二年级的时候,虽然念书念得不错,体育方面也很好,社交方面也没有问题,但是我发现我一点儿都不幸福。我觉得这简直是没有道理,因为从我周围的环境以及外部的因素来看,我应该是幸福的,但是我的内心并不这样认为。所以有一天早上醒来之后,我见了我的导师,跟他说我要换专业,然后我从计算机专业换到哲学及心理学专业。我的导师问我为什么,我回答他,因为我要了解两个问题:第一,为什么我感觉不幸福;第二,我如何才能变得更加幸福。为了这一点,我暂时放弃了在哈佛大学的课程,前往剑桥大学学习教育课程,然后回到了哈佛大学攻读博士。

成功与幸福之间的关系

我们今天要了解一下,在过去20年中,积极心理学这个领域内的发展以及一些成果。不过我只能做一些简略的介绍,因为如果一直讲下去,可能今天半夜也讲不完。

首先一个问题是成功与幸福之间的关系。之前大家都会认为,成功与幸福之间的关系是,你只要能够取得成功就一定会感到幸福。比如我们进了好的大学,找到理想的工作,挣到很高的薪水等等,我们一直都是在这种模式下被教育成长的。不过从我自身的经历以及科学研究表明,这样的关系实际上是完全错误的。这方面有很多的研究,但是我今天想谈一下我在哈佛大学上课时的一些经历。

每年3月份的时候,我会向我的学生提问:如果你认为你在4月2号这一天会感到很幸福或者特别幸福的话就请举手。我为什么会选择4月2号这一天呢?因为4月2号是学生接到录取通知的日子,他们会知道自己有没有被新的学校录取。所以想一下,坐在我这个课堂上的学生,在4月2号有可能会接到哈佛大学的录取通知书。所以呢,我就选择了这一天。当时我班上有将近1000名学生,他们全都举起了手。

那么我的下一个问题是,如果你觉得你一生剩下的时光都会感到很幸福的话,你们就别把手放下来。几乎所有人仍然是举着手的,他们认为4月2号这一天感到幸福,因为接到哈佛大学的录取通知书,所以他们的余生都会感到很幸福。为什么会有这样的结果呢?是因为这些学生他们都是在这样一个模式下被教育长大的——只要你进入了像哈佛这样一流的大学,那么你就会受到同学的敬仰、老师的尊重,会找到很好的工作,因此你这一生都会很幸福。所以所有的人都继续举着他们的手,认为他们一辈子都会幸福下去。我接下来一个问题是,如果你们此时此刻感到幸福,不用感到非常幸福,或者特别幸福,只要是感到幸福就好,你们就继续举着手。几乎所有的人都把手放下了。

哈佛每年大约有80%的学生都会受到这种抑郁的困扰。这倒不是很严重的抑郁,只是觉得自己有一些无助的抑郁。对于他们其中的一些人来说,以及对于社会上大部分人来说,“Success→Happiness”就像黑板上的公式。当他们发现这些公式其实不成立之后,失望就会带来这种抑郁。公式到底成立不成立呢?其实,如果是把这个公式反向来看,“Happiness→Success”就是完全成立的——幸福可以引导我们走向成功。

要幸福,首先要接受不幸福

如果成功不能让我们感到幸福,到底是什么能使我们感到幸福呢?在我们进行下一步的讨论以及提问之前,我们首先要明确非常重要的几点,才能够让我们内心感到幸福。首先我们要重新接受自己作为人类个体的一个事实,我们要知道人类的个体不仅感受幸福,也会感受痛苦、哀伤、忧愁等等各种不良的情绪。

当我第一次在哈佛大学开设积极心理学课程的时候,在课程的第一天有个学生和我共进了午餐。他并不是我班上的学生,但他的一个室友选修了我这门课程。他一坐下来就跟我说,既然你现在开始教这门课程了,所以你要格外当心。我问他为什么,他说如果我发现你有一点点不开心、不幸福的话,我就会跟我的室友告密。所以,我在第二天上课时,跟学生说的第一句话就是,我认为这个世界上最不可能的一件事情就是,我会一直感到幸福,而你们在学习结束后也会一直都情绪高涨。

世界上不会经历忧伤、哀愁、嫉妒、失望、焦虑等等不良情绪的,只有两种人:第一类是精神病患者,第二类就是死人。

所以如果你确实经历了这种痛苦的情绪的话,我是非常为你们感到高兴的,这至少说明:第一,你不是精神病人,第二,你不是死人。我在现代社会中的很多国家,包括中国和美国在内,看到的一个问题就是,我们普通人不允许自己经历这种本来很本源的情感,或者我们经历这种情感的时候会感到非常不舒服。所以,当我们允许自己去全新地接受这种痛苦情绪的时候,如果我们能够坦诚地把它写下来,或者向我们的家人、朋友、治疗师等把这些情绪说出来,让自己能够全面接受这些情绪的话,就是非常好的一个方式。

痛苦的情绪就像弹簧一样,遇强则强。所以想要获得幸福的最基本的一个公式,听上去是自相矛盾的,首先就是要接受不幸福。

坚持锻炼与懂得感恩胜过灵丹妙药

我要谈的第二点就是身体上的锻炼。定期的体育运动对于心理上的健康的作用和最强效的心理治疗药物的效力是一样的。每周3次,每次30分钟定期的锻炼,可以排出我们大脑中的有害的化学物质,作用相当于抗抑郁和抗焦虑的药物。可以是散步、慢跑、游泳、打篮球或者是跳舞,不妨大家一起去跳个广场舞。

定期锻炼还可以增强我们的注意力、创造力,可以改善我们的人际关系,以及有利于自信心的提升。哈佛大学等著名大学的心理学家,他们把定期的心理锻炼称为心理治疗上的灵丹妙药。一周3次,每次30分钟,这样的体育锻炼足够了。

第三点,也是很重要的一点,要有感恩的心。

多项研究表明,把你很感激的一些事情写下来,不管是大事或者小事,把它们写下来,这样会让你感到更幸福,身体也会更健康。每天或者每周花一两分钟,把自己心存感激的事情都认真地记下来,时间不会花很多,但是能产生的改变却是非常大的。

大约在几个月前,我的同事们刚刚发表了一个研究,这个研究表明,要对未来表示感恩。研究参与者们在每天早晨起来的时候,写下一天当中他们期待发生的三件事情——可以是和朋友共进午餐,或者是期待学校中的一堂课程,或者仅仅是下午能够睡个好觉。不管是什么,大事小事都可以,至少写下三件。定期做这件事情的人们,焦虑会减少很多。因此,对我们的生活表示感恩,不管是对已经发生的事情还是我们期待发生的事情,都会让我们感到更加幸福。

不过很不幸的是,我们现在总是认为我们生活中出现的一切事情都是理所当然的。

要认为我们自己很幸福

除了上面所说的三点之外,我还要强调的第四点就是,要认为我们自己很幸福。

有研究学者对我们外在的身体行为进行了研究。他让研究参与者从两种方式中任选一种,一种是很放松的、充满能量的姿态,一种是紧张的、低能量的姿态,每个姿态保持两分钟。仅仅是这两分钟不同的姿态,就会对研究参与者产生非常大的影响。采取低能量姿态的人在两分钟之后,他们的皮质醇水平会上升25%,而采用这种高能量姿态的人皮质醇水平会下降15%。大家都知道,有一种非常强力的药物,它的作用就是降低人体内的皮质醇水平,而仅仅是两分钟时间的高能量姿态,就能够达到这样的作用。另外,雄激素水平在低能量姿态人群中会下降10%,在高能量姿态人群中水平会上升20%。

同时,不同的走路姿态也会导致人的幸福感的极大不同,像刚才这种雄纠纠气昂昂的走路姿态和蔫头耷脑的走路姿态导致的结果就是完全不同的。有时你只要做出这样一个积极的动作,就可以提升自己的动机水平,让自己振奋起来。

还有一个经典的研究,给你一支笔,让你把笔叼在嘴里,想想没有胳膊的人应该怎样写字。其中一组是把笔头朝下叼在嘴里,另外一组就是把笔横着叼在嘴里。在研究参与者头上放置的测试脑电波水平的电机表明,那些把笔头朝下叼着笔的人会感觉不太开心,而横着叼笔的人会感觉到更加开心,原因在于横着叼笔的人的嘴型看上去像微笑一样,即便他们没有真正微笑,也会让他们感到很开心。所以有的时候(当然不是一直),我们也可以假装自己很幸福,很开心。

第五点,也是非常重要的一点,就是一定要珍视与爱的人和爱我们的人一起共处的时光。和亲朋好友相处的时光一定要珍视,这与能够挣到多少钱,有多么出名,多么成功丝毫没有关系。

最后总结一下,让我们更加幸福的五个方法其实非常简单:首先是接受我们作为人类有痛苦情绪;第二是定期参加体育锻炼;第三是要有感恩的心,对我们获得的和将要获得的持有感恩的心;第四点,有时可以假装自己很幸福;第五,和你爱的人,和亲朋好友多多相处,并珍视这样的时光。

作者简介:泰勒·本-沙哈尔,哈佛大学心理学教授,被誉为哈佛大学“最受欢迎的导师”。他的《改变人生——积极心理学绝对能做到!》是哈佛大学排名第一的课程,也是哈佛有史以来选课人数最多的课程。被企业家和高管们誉为“摸得着幸福”的心理课程。潜心研究幸福学和积极心理学,著有《幸福的方法》等书。

来源:中信书院
因微友强烈要求,特公开“有机生活馆”专用个人微信号:china5666,欢迎关注。

  青春就应该这样绽放   游戏测试:三国时期谁是你最好的兄弟!!   你不得不信的星座秘密

网购秒杀系统架构设计

$
0
0

秒杀活动的技术挑战

1. 对现有网站业务造成冲击

秒杀活动只是网站营销的一个附加活动,这个活动具有时间短,并发访问量大的特点,如果和网站原有应用部署在一起,必须会对现有业务造成冲击,稍有不慎可能导致整个网站瘫痪。

2. 高并发下的应用、数据库负载

用户在秒杀开始前,通过不停刷新浏览器页面以保证不会错过秒杀,这些请求如果按照一般的网站应用架构,访问应用服务器、连接数据库,会对应用服务器和数据库服务器造成极大的负载压力。

3. 突然增加的网络及服务器带宽

假设商品页面大小200K(主要是商品图片大小),那么需要的网络和服务器带宽是2G(200K×10000),这些网络带宽是因为秒杀活动新增的,超过网站平时使用的带宽。

4. 直接下单

秒杀的游戏规则是到了秒杀时间才能开始对商品下单购买,在此时间点之前,只能浏览商品信息,不能下单。而下单页面也只是一个普通的URL,如果得到这个URL,不用等到秒杀开始就可以下单了。

 

秒杀系统的应对策略

1. 秒杀系统独立部署

为了避免因为秒杀活动的高并发访问而拖垮整个网站,使整个网站不必面对蜂拥而来的用户访问,可将秒杀系统独立部署;如果需要,还可以使用独立的域名,使其与网站完全隔离,即使秒杀系统崩溃了,也不会对网站造成任何影响。

2. 秒杀商品页面静态化

重新设计秒杀商品页面,不使用网站原来的商品详情页面,页面内容静态化:将商品描述、商品参数、成交记录和用户评价全部写入一个静态页面,用户请求不需要经过应用服务器的业务逻辑处理,也不需要访问数据库。所以秒杀商品服务不需要部署动态的Web服务器和数据库服务器。

3. 租借秒杀活动网络带宽

因为秒杀新增的网络带宽,必须和运营商重新购买或者租借。为了减轻网站服务器的压力,需要将秒杀商品页面缓存在CDN,同样需要和CDN服务商临时租借新增的出口带宽。

4. 动态生成随机下单页面URL

为了避免用户直接访问下单页面URL,需要将该URL动态化,即使秒杀系统的开发者也无法在秒杀开始前访问下单页面的URL。办法是在下单页面URL加入由服务器端生成的随机数作为参数,在秒杀开始的时候才能得到。

 

秒杀系统架构设计

         秒杀系统为秒杀而设计,不同于一般的网购行为,参与秒杀活动的用户更关心的是如何能快速刷新商品页面,在秒杀开始的时候抢先进入下单页面,而不是商品详情等用户体验细节,因此秒杀系统的页面设计应尽可能简单。

         商品页面中的购买按钮只有在秒杀活动开始的时候才变亮,在此之前及秒杀商品卖出后,该按钮都是灰色的,不可以点击。

         下单表单也尽可能简单,购买数量只能是一个且不可以修改,送货地址和付款方式都使用用户默认设置,没有默认也可以不填,允许等订单提交后修改;只有第一个提交的订单发送给网站的订单子系统,其余用户提交订单后只能看到秒杀结束页面。

 

        除了上面提到的秒杀系统的技术挑战及应对策略,还有一些其他问题需要处理。

1. 如何控制秒杀商品页面购买按钮的点亮

购买按钮只有在秒杀开始的时候才能点亮,在此之前是灰色的。如果该页面是动态生成的,当然可以在服务器端构造响应页面输出,控制该按钮是灰色还是点亮,但是为了减轻服务器端负载压力,更好地利用CDN、反向代理等性能优化手段,该页面被设计为静态页面,缓存在CDN、反向代理服务器上,甚至用户浏览器上。秒杀开始时,用户刷新页面,请求根本不会到达应用服务器。

 

解决办法是使用JavaScript脚本控制,在秒杀商品静态页面中加入一个JavaScript文件引用,该JavaScript文件中包含秒杀开始标志为否;当秒杀开始的时候生成一个新的JavaScript文件(文件名保持不变,只是内容不一样),更新秒杀开始标志为是,加入下单页面的URL及随机数参数(这个随机数只会产生一个,即所有人看到的URL都是同一个,服务器端可以用redis这种分布式缓存服务器来保存随机数),并被用户浏览器加载,控制秒杀商品页面的展示。这个JavaScript文件的加载可以加上随机版本号(例如xx.js?v=32353823),这样就不会被浏览器、CDN和反向代理服务器缓存。


         这个JavaScript文件非常小,即使每次浏览器刷新都访问JavaScript文件服务器也不会对服务器集群和网络带宽造成太大压力。

 

2. 如何只允许第一个提交的订单被发送到订单子系统

由于最终能够成功秒杀到商品的用户只有一个,因此需要在用户提交订单时,检查是否已经有订单提交。如果已经有订单提交成功,则需要更新JavaScript文件,更新秒杀开始标志为否,购买按钮变灰。事实上,由于最终能够成功提交订单的用户只有一个,为了减轻下单页面服务器的负载压力,可以控制进入下单页面的入口,只有少数用户能进入下单页面,其他用户直接进入秒杀结束页面。假设下单服务器集群有10台服务器,每台服务器只接受最多10个下单请求。在还没有人提交订单成功之前,如果一台服务器已经有十单了,而有的一单都没处理,可能出现的用户体验不佳的场景是用户第一次点击购买按钮进入已结束页面,再刷新一下页面,有可能被一单都没有处理的服务器处理,进入了填写订单的页面,可以考虑通过cookie的方式来应对,符合一致性原则。当然可以采用最少连接的负载均衡算法,出现上述情况的概率大大降低。


小结

        秒杀是对网站架构的极大考验,在难以预计和控制的高并发访问的冲击下,稍有不慎,系统就会被用户秒杀,导致整个系统宕机,活动失败,构成重大事故。因此在遵循秒杀活动游戏规则的基础上,为了保证系统的安全,保持适度的公平公正即可。即使系统出了故障,也不应该给用户显示出错页面,而是显示秒杀活动结束页面,避免不必要的困扰。

 

本文摘自李智慧的《大型网站技术架构:核心原理与案例分析》,对文中的内容做了一点细化与补充。

 



已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



ios应用提交上架被appstore拒绝的十大理由

$
0
0

1.崩溃和问题

你需要尽量修复你应用中的崩溃和那些明显的问题,否则你的应用很可能被拒绝。

2.失效的链接

保证你应用中出现的链接的有效性。

3.默认占位图片

含有系统默认占位图片的应用不会被通过,你需要处理你的占位图片/内容,保证其都是有意义的。

4.信息不完整
提供到苹果审核的信息需要保证完整性。比如你的应用如果需要登录,那你就需要提供一个demo账号和密码以供测试。

5.不精确的描述

你的应用描述和截图应尽量做到准确且包含了应用的主要功能。这能帮助用户尽快识别他们是否需要你的应用。

6.误导用户

你不应该夸大你应用的功能。所有在应用中承诺的你都应该实现。

7.广告

保证你的广告可以正确的工作,不要影响到系统的其他功能。

8.网页剪切/内容聚合/链接的集合

如果我们认为你的应用没有核心价值,只是网页内容的复制而没有针对ios设备进行优化,我们不会通过你的app.

9.相似应用的重复提交

如果你的应用和你此前的应用非常相似,我们推荐你改进或合并你的应用,而不是反复提交。

10.没有足够的持续价值

如果你的应用的市场范围非常狭窄,或提供的功能非常有限,那很可能不被通过。我们建议你多参考苹果市场的那些优秀应用,从而改进你的产品。


根据苹果官方文档意译:

https://developer.apple.com/app-store/review/rejections/

作者:openglnewbee 发表于2014-9-5 17:07:33 原文链接
阅读:0 评论:0 查看评论

MySQL锁阻塞分析

$
0
0

日常维护中,经常会碰到线程被阻塞,导致数据库响应非常慢,下面就看看如何获取是哪个线程导致了阻塞的。

blog地址: http://blog.csdn.net/hw_libo/article/details/39080809

1. 环境说明

RHEL 6.4 x86_64 + MySQL 5.6.19
事务隔离级别:RR

2. 测试过程



3. 查看锁阻塞线程信息

这里用几中方法进行分析:

3.1  使用show processlist查看

MySQL [(none)]> show processlist;
+----+------+-----------+------+---------+------+--------------+------------------------------------------+
| Id | User | Host      | db   | Command | Time | State        | Info                                     |
+----+------+-----------+------+---------+------+--------------+------------------------------------------+
|  2 | root | localhost | NULL | Query   |    0 | init         | show processlist                         |
|  3 | root | localhost | test | Query   |   70 | Sending data | select count(*) from t3 a,t3 b           |
|  4 | root | localhost | test | Query   |   65 | updating     | delete from emp where empno=7788         |
|  7 | root | localhost | test | Query   |   68 | updating     | update emp set sal=3500 where empno=7788 |
+----+------+-----------+------+---------+------+--------------+------------------------------------------+
4 rows in set (0.00 sec)

如果数据库存在较多线程的话,这种方法确实不太好确认的。


3.2  直接使用show engine innodb status查看

------------
TRANSACTIONS
------------
Trx id counter 4131
Purge done for trx's n:o < 4119 undo n:o < 0 state: running but idle
History list length 126
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 0, not started
MySQL thread id 2, OS thread handle 0x7f953ffff700, query id 115 localhost root init
show engine innodb status
---TRANSACTION 4130, ACTIVE 41 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 360, 1 row lock(s)
MySQL thread id 4, OS thread handle 0x7f953ff9d700, query id 112 localhost root updating
delete from emp where empno=7788
------- TRX HAS BEEN WAITING 41 SEC FOR THIS LOCK TO BE GRANTED:   ## 等待了41s
RECORD LOCKS space id 16 page no 3 n bits 88 index `PRIMARY` of table `test`.`emp` trx id 4130 lock_mode X locks rec but not gap waiting
Record lock, heap no 9 PHYSICAL RECORD: n_fields 10; compact format; info bits 0  ## 线程4在等待往test.emp中的主键上加X锁,page num=3
 0: len 4; hex 80001e6c; asc    l;;
 1: len 6; hex 000000001018; asc       ;;
 2: len 7; hex 91000001420084; asc     B  ;;
 3: len 5; hex 53434f5454; asc SCOTT;;
 4: len 7; hex 414e414c595354; asc ANALYST;;
 5: len 4; hex 80001d8e; asc     ;;
 6: len 4; hex 208794f0; asc     ;;
 7: len 4; hex 80000bb8; asc     ;;
 8: SQL NULL;
 9: len 4; hex 80000014; asc     ;;

------------------
---TRANSACTION 4129, ACTIVE 45 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 360, 1 row lock(s)
MySQL thread id 7, OS thread handle 0x7f953ff6c700, query id 111 localhost root updating
update emp set sal=3500 where empno=7788
------- TRX HAS BEEN WAITING 45 SEC FOR THIS LOCK TO BE GRANTED:   ## 等待了45s
RECORD LOCKS space id 16 page no 3 n bits 88 index `PRIMARY` of table `test`.`emp` trx id 4129 lock_mode X locks rec but not gap waiting
Record lock, heap no 9 PHYSICAL RECORD: n_fields 10; compact format; info bits 0  ## 线程7在等待往test.emp中的主键上加X锁,page num=3
 0: len 4; hex 80001e6c; asc    l;;
 1: len 6; hex 000000001018; asc       ;;
 2: len 7; hex 91000001420084; asc     B  ;;
 3: len 5; hex 53434f5454; asc SCOTT;;
 4: len 7; hex 414e414c595354; asc ANALYST;;
 5: len 4; hex 80001d8e; asc     ;;
 6: len 4; hex 208794f0; asc     ;;
 7: len 4; hex 80000bb8; asc     ;;
 8: SQL NULL;
 9: len 4; hex 80000014; asc     ;;

------------------
---TRANSACTION 4128, ACTIVE 51 sec
2 lock struct(s), heap size 360, 1 row lock(s)
MySQL thread id 3, OS thread handle 0x7f953ffce700, query id 110 localhost root cleaning up

我们知道,主要根因还是thread=3引起的,但从innodb status中却无法分析得到这个结果。

从上面来看,线程4和线程7都在等待往test.emp中的主键上加X锁,page num=3,但是线程7等待的时间为45s,而线程4等待的时间为41s,是较线程7之后申请的锁,所以可以判断是线程7阻塞了线程4。至于线程7为什么出现等待,这里分析不到根因。


3.3  使用mysqladmin debug查看

# mysqladmin -S /tmp/mysql3306.sock debug

然后在error日志中,会看到:

Thread database.table_name          Locked/Waiting        Lock_type


3       test.t3                     Locked - read         Low priority read lock
7       test.emp                    Locked - write        High priority write lock

这种方法中,能找到线程ID=3和7是阻塞者,但还是不太准确,判断不出来线程7也是被线程ID=3阻塞的。


3.4  使用innodb_lock_monitor来获取阻塞锁线程

MySQL [test]> CREATE TABLE innodb_lock_monitor (a INT) ENGINE=INNODB;  ## 随便在一个数据库中创建这个表,就会打开lock monitor
Query OK, 0 rows affected, 1 warning (0.07 sec)

MySQL [test]> show warnings\G
*************************** 1. row ***************************
  Level: Warning
   Code: 131
Message: Using the table name innodb_lock_monitor to enable diagnostic output is deprecated and may be removed in future releases. Use INFORMATION_SCHEMA or PERFORMANCE_SCHEMA tables or SET GLOBAL innodb_status_output=ON.
1 row in set (0.00 sec)

说明:这个在5.6中有一个warning,但不影响使用。

然后再使用show engine innodb status查看:

------------
TRANSACTIONS
------------
Trx id counter 4667
Purge done for trx's n:o < 4659 undo n:o < 0 state: running but idle
History list length 138
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 0, not started
MySQL thread id 9, OS thread handle 0x7f813c5f7700, query id 152 localhost root init
show engine innodb status
---TRANSACTION 4663, ACTIVE 78 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 360, 1 row lock(s)
MySQL thread id 4, OS thread handle 0x7f813c628700, query id 149 localhost root updating
delete from emp where empno=7788
------- TRX HAS BEEN WAITING 78 SEC FOR THIS LOCK TO BE GRANTED:   ## 等待了78s
RECORD LOCKS space id 16 page no 3 n bits 88 index `PRIMARY` of table `test`.`emp` trx id 4663 lock_mode X locks rec but not gap waiting
Record lock, heap no 9 PHYSICAL RECORD: n_fields 10; compact format; info bits 0  ## 线程4在等待往test.emp中的主键上加X锁,page num=3
 0: len 4; hex 80001e6c; asc    l;;
 1: len 6; hex 000000001018; asc       ;;
 2: len 7; hex 91000001420084; asc     B  ;;
 3: len 5; hex 53434f5454; asc SCOTT;;
 4: len 7; hex 414e414c595354; asc ANALYST;;
 5: len 4; hex 80001d8e; asc     ;;
 6: len 4; hex 208794f0; asc     ;;
 7: len 4; hex 80000bb8; asc     ;;
 8: SQL NULL;
 9: len 4; hex 80000014; asc     ;;

------------------
TABLE LOCK table `test`.`emp` trx id 4663 lock mode IX   ## 在给主键行上加X锁之前,先要在表上加意向锁IX
RECORD LOCKS space id 16 page no 3 n bits 88 index `PRIMARY` of table `test`.`emp` trx id 4663 lock_mode X locks rec but not gap waiting
Record lock, heap no 9 PHYSICAL RECORD: n_fields 10; compact format; info bits 0
 0: len 4; hex 80001e6c; asc    l;;
 1: len 6; hex 000000001018; asc       ;;
 2: len 7; hex 91000001420084; asc     B  ;;
 3: len 5; hex 53434f5454; asc SCOTT;;
 4: len 7; hex 414e414c595354; asc ANALYST;;
 5: len 4; hex 80001d8e; asc     ;;
 6: len 4; hex 208794f0; asc     ;;
 7: len 4; hex 80000bb8; asc     ;;
 8: SQL NULL;
 9: len 4; hex 80000014; asc     ;;

---TRANSACTION 4662, ACTIVE 81 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 360, 1 row lock(s)
MySQL thread id 7, OS thread handle 0x7f813c5c6700, query id 148 localhost root updating
update emp set sal=3500 where empno=7788
------- TRX HAS BEEN WAITING 81 SEC FOR THIS LOCK TO BE GRANTED:  ## 等待了81s
RECORD LOCKS space id 16 page no 3 n bits 88 index `PRIMARY` of table `test`.`emp` trx id 4662 lock_mode X locks rec but not gap waiting
Record lock, heap no 9 PHYSICAL RECORD: n_fields 10; compact format; info bits 0  ## 线程7在等待往test.emp中的主键上加X锁,page num=3
 0: len 4; hex 80001e6c; asc    l;;
 1: len 6; hex 000000001018; asc       ;;
 2: len 7; hex 91000001420084; asc     B  ;;
 3: len 5; hex 53434f5454; asc SCOTT;;
 4: len 7; hex 414e414c595354; asc ANALYST;;
 5: len 4; hex 80001d8e; asc     ;;
 6: len 4; hex 208794f0; asc     ;;
 7: len 4; hex 80000bb8; asc     ;;
 8: SQL NULL;
 9: len 4; hex 80000014; asc     ;;

------------------
TABLE LOCK table `test`.`emp` trx id 4662 lock mode IX   ## 在给主键行上加X锁之前,先要在表上加意向锁IX
RECORD LOCKS space id 16 page no 3 n bits 88 index `PRIMARY` of table `test`.`emp` trx id 4662 lock_mode X locks rec but not gap waiting
Record lock, heap no 9 PHYSICAL RECORD: n_fields 10; compact format; info bits 0
 0: len 4; hex 80001e6c; asc    l;;
 1: len 6; hex 000000001018; asc       ;;
 2: len 7; hex 91000001420084; asc     B  ;;
 3: len 5; hex 53434f5454; asc SCOTT;;
 4: len 7; hex 414e414c595354; asc ANALYST;;
 5: len 4; hex 80001d8e; asc     ;;
 6: len 4; hex 208794f0; asc     ;;
 7: len 4; hex 80000bb8; asc     ;;
 8: SQL NULL;
 9: len 4; hex 80000014; asc     ;;

---TRANSACTION 4615, ACTIVE 1579 sec, thread declared inside InnoDB 1222
mysql tables in use 2, locked 0
2 lock struct(s), heap size 360, 1 row lock(s)
MySQL thread id 3, OS thread handle 0x7f813c659700, query id 147 localhost root Sending data
select count(*) from t3 a,t3 b   ## 这是线程3当前正在执行的SQL
Trx read view will not see trx with id >= 4662, sees < 4659
TABLE LOCK table `test`.`emp` trx id 4615 lock mode IX  ## 线程3中正在拥有表上的意向IX锁,并且有test.emp表上主键的行级X锁,page num=3
RECORD LOCKS space id 16 page no 3 n bits 88 index `PRIMARY` of table `test`.`emp` trx id 4615 lock_mode X locks rec but not gap
Record lock, heap no 9 PHYSICAL RECORD: n_fields 10; compact format; info bits 0
 0: len 4; hex 80001e6c; asc    l;;
 1: len 6; hex 000000001018; asc       ;;
 2: len 7; hex 91000001420084; asc     B  ;;
 3: len 5; hex 53434f5454; asc SCOTT;;
 4: len 7; hex 414e414c595354; asc ANALYST;;
 5: len 4; hex 80001d8e; asc     ;;
 6: len 4; hex 208794f0; asc     ;;
 7: len 4; hex 80000bb8; asc     ;;
 8: SQL NULL;
 9: len 4; hex 80000014; asc     ;;

为什么线程3当前执行的是一个select t3表操作,但却锁住了test.emp表上page num=3?
有可能是线程3之前对test.emp表的操作事务没有及时提交导致。
所以得出:线程3阻塞了线程7,而线程7又阻塞了线程4,所以根因就是线程3,让线程3尽快提交或是kill掉即可。


4. 结论

在分析innodb中锁阻塞时,几种方法的对比情况:

(1)使用show processlist查看不靠谱;
(2)直接使用show engine innodb status查看,无法判断到问题的根因;
(3)使用mysqladmin debug查看,能看到所有产生锁的线程,但无法判断哪个才是根因;
(4)开启innodb_lock_monitor后,再使用show engine innodb status查看,能够找到锁阻塞的根因。

blog地址: http://blog.csdn.net/hw_libo/article/details/39080809

-- Bosco  QQ:375612082
---- END ----
-------------------------------------------------------------------------------------------------------
版权所有,文章允许转载,但必须以链接方式注明源地址,否则追究法律责任!

作者:HW_LiBo 发表于2014-9-5 15:10:10 原文链接
阅读:75 评论:0 查看评论

手把手教你用jpcap抓包

$
0
0

本文原创,转载请注明出处~

 

在工作中经常需要抓包进行分析,我们可以使用各种工具来抓包,比如常用的tcpdump和wireshark。但有时候我们想用程序来进行控制,比如把抓到的包存储到数据库中,以后可以进行查询等等。我在工作中用的是Java,那么就用它来做示范吧。

 

本教程在centos和ubuntu上测试通过。

 

1)安装libpcap库

先安装底层使用的库吧,我们用到了libpcap库,tcpdump也是用的这个库,所以先去http://www.tcpdump.org/#old-releases

下载源码进行编译安装,不需要用太新的库吧,因为jpcap挺老的。这里我选了1.1.1版本。

解压,configure,make,make install,完成了。

 

2)安装jpcap库

我们使用v0.01.16版本,下载为:

http://sourceforge.net/projects/jpcap/files/jpcap/v0.01.16/

我们下载的是源代码版本,虽然有rpm包提供,但却是32位版本的,我们的服务器是64位的,只能自己编译生成了。

 

解压后编译scripts/env_jpcap文件,配置编译过程中的环境变量,只需要改其中的两项:

 

# 你解压后的目录
export PROJECT_HOME=~/dev/sourceforge/jpcap
# 生成目录
export RELEASE_HOME=~/dev/releases
# 选填,指定你的JDK目录
#export JAVA_HOME=/usr/java/jdk1.3 ; export PATH=$JAVA_HOME/bin:$PATH

 

 

然后让配置生效

 

. ./scripts/env_jpcap

 

 

编译

make clean && make

 

哈哈,发现出错了:

 

g++ -Wall -O2 -I/usr/include/pcap -I/usr/local/jdk1.6.0_29/include -I/usr/local/jdk1.6.0_29/include/linux jpcap.c process.cpp -fPIC -shared -o libjpcap.so -lnsl /usr/lib/libpcap.a
g++: /usr/lib/libpcap.a: No such file or directory

 说是没有libpcap.a,我们刚才不是安装好了吗!!find一下发现原来在/usr/local/lib目录中。拷贝过去就好了:

 

sudo cp /usr/local/lib/libpcap.a /usr/lib

OK,继续。

 

恭喜,又报错了:

jpcap.c:678: error: lvalue required as left operand of assignment

因为这个版本的jpcap是2004年的,我们的机器的gcc版本是4.4.6,也许gcc的版本太新了吧。可以考虑安装多个版本的gcc,但这里直接把代码改改就好:

vi capture/jpcap.c

定位到678行,进行修改:

 

// for(;ifr < last; (char*)ifr += ifrSize) {
for(;ifr < last; ifr = (ifreq*)((char*)ifr + ifrSize)) {

 OK,继续。

 

 

没有报错,完成了,再执行:

make release

就可以在之前配置的RELEASE_HOME目录下发现编译好的文件了:

javadoc_net.sourceforge.jpcap-0.01.16.jar

net.sourceforge.jpcap-0.01.16.jar

 

解压后者,发现libjpcap.so也在里面,需要把这个库也安装到合适的地方,你可以把库放到下面代码打印的任意一个目录中:

 

System.out.println(System.getProperty("java.library.path"));

 

 

下面就开始写Java代码了,需要引入3个Jar包,分别是前面生成的net.sourceforge.jpcap-0.01.16.jar,还有之前下载的jpcap-0.01.16/thirdParty/jars目录下的包。

 

net.sourceforge.jpcap-0.01.16.jar中其实就包含了很多例子程序,如图所示:


 

例子就不写了,附上java doc文档地址:

http://jpcap.sourceforge.net/javadoc/index.html

 

使用过程需要注意2个地方:

1,必须使用root权限执行,因为要使网卡进入混杂模式必须要有root权限,不过不使用root会报这样的错误:

Exception in thread "main" net.sourceforge.jpcap.capture.CaptureDeviceNotFoundException: no suitable device found

 

2,如果你发现抓到的tcp的data的数据跟实际发送的数据少了一段,那么在代码中需要注意要这样使用:

Instead of pcap.open(device, true);
try pcap.open(device, 65535, true, 1000);

 原因参考:

http://stackoverflow.com/questions/17906635/get-full-tcp-packet-data-using-jpcap



已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



Memcached的简单使用实例

$
0
0

Memcached的简单使用实例

 

最近一直在做一个项目的前期设计工作,考虑到后期系统的扩展和性能问题也找了很多解决方法,有一个就是用到了数据库的缓存工具memcached(当然该工具并不仅仅局限于数据库的缓存)。先简单的介绍下什么是memcached。

    Memcached 是高性能的,分布式的内存对象缓存系统, 用于在动态应用中减少数据库负载,提升访问速度。Memcached由Danga Interactive开发,用于提升LiveJournal.com访问速度的。LJ每秒动态页面访问量几千次,用户700万。Memcached将数 据库负载大幅度降低,更好的分配资源,更快速访问。

    上网baidu了很多东西,几乎都差不多,而且基于java的说的很少,所有只有在研究了各个其他语言类的应用后再来尝试在java上进行简单的操作应 用。先从memcached上进行说明,memcached的最新版是采用c语言进行开发和设计的,据说旧版的是采用perl语言开发的,而且它是一个应 用软件来的,是作为缓存服务器的服务器端运行在服务器上的,需要使用特定的语言编写客户端与其进行通信来进行数据的缓存和获取。通常我们是把 memcached安装运行在web服务器上,然后通过对需要的数据进行缓存,据我目前所知,所有数据的缓存设置和存取操作,以及数据的更新后替换操作全 部需要程序来进行,而不是自动进行的(自动不知道能不能成功,呵呵)。下面从一个实际的例子来应用memcached。

    首先到 http://danga.com/memcached/下 载memcached的windows版本和java客户端jar包,目前最新版本是memcached-1.2.1-win32.zip和 java_memcached-release_1.6.zip,分别解压后即可!

 说明:window版本的memcache服务软件下载链接是无效的,我提供一个新的链接

   http://splinedancer.com/memcached-win32/

首先是安装运行memcached服务器,我们将memcached- 1.2.1-win32.zip解压后,进入其目录,然后运行如下命令:

c:>memcached.exe -d install
c:>memcached.exe -l 127.0.0.1 -m 32 -d start

    第一行是安装memcached成为服务,这样才能正常运行,否则运行失败!第一行是启动memcached的,作为测试我们就简单的只分配32M内存 了,然后监听本机端口和以守护进行运行。执行完毕后,我们就可以在任务管理器中见到memcached.exe这个进程了。好了,我们的服务器已经正常运 行了, 下面我们就来写java的客户端连接程序。

 

 

    我们将java_memcached-release_1.6.zip解压后的目录中的java_memcached-release_1.6.jar文 件复制到java项目的lib目录下,然后我们来编写代码,比如我提供的一个应用类如下:

package utils.cache;
import java.util.Date;
import com.danga.MemCached.MemCachedClient;
import com.danga.MemCached.SockIOPool;
/**
* 使用memcached的缓存实用类.
*
* @author 铁木箱子
*
*/
public class MemCached
{
    // 创建全局的唯一实例
    protected static MemCachedClient mcc = new MemCachedClient();
    
    protected static MemCached memCached = new MemCached();
    
    // 设置与缓存服务器的连接池
    static {
        // 服务器列表和其权重
        String[] servers = {"127.0.0.1:11211"};  //这个端口是memcache服务的端口号,是死的 不知道怎么修改
        Integer[] weights = {3};
 
        // 获取socke连接池的实例对象
        SockIOPool pool = SockIOPool.getInstance();
 
        // 设置服务器信息
        pool.setServers( servers );
        pool.setWeights( weights );
 
        // 设置初始连接数、最小和最大连接数以及最大处理时间
        pool.setInitConn( 5 );
        pool.setMinConn( 5 );
        pool.setMaxConn( 250 );
        pool.setMaxIdle( 1000 * 60 * 60 * 6 );
 
        // 设置主线程的睡眠时间
        pool.setMaintSleep( 30 );
 
        // 设置TCP的参数,连接超时等
        pool.setNagle( false );
        pool.setSocketTO( 3000 );
        pool.setSocketConnectTO( 0 );
 
        // 初始化连接池
        pool.initialize();
 
        // 压缩设置,超过指定大小(单位为K)的数据都会被压缩
        mcc.setCompressEnable( true );
        mcc.setCompressThreshold( 64 * 1024 );
    }
    
    /**
     * 保护型构造方法,不允许实例化!
     *
     */
    protected MemCached()
    {
        
    }
    
    /**
     * 获取唯一实例.
     * @return
     */
    public static MemCached getInstance()
    {
        return memCached;
    }
    
    /**
     * 添加一个指定的值到缓存中.
     * @param key
     * @param value
     * @return
     */
    public boolean add(String key, Object value)
    {
        return mcc.add(key, value);
    }
    
    public boolean add(String key, Object value, Date expiry)
    {
        return mcc.add(key, value, expiry);
    }
    
    public boolean replace(String key, Object value)
    {
        return mcc.replace(key, value);
    }
    
    public boolean replace(String key, Object value, Date expiry)
    {
        return mcc.replace(key, value, expiry);
    }
    
    /**
     * 根据指定的关键字获取对象.
     * @param key
     * @return
     */
    public Object get(String key)
    {
        return mcc.get(key);
    }
    
    public static void main(String[] args)
    {
        MemCached cache = MemCached.getInstance();
        cache.add("hello", 234);
        System.out.print("get value : " + cache.get("hello"));
    }
}

 

  那么我们就可以通过简单的像main方法中操作的一样存入一个变量,然后再取出进行查看,我们可以看到先调用了add,然后再进行get,我们运行一次 后,234这个值已经被我们存入了memcached的缓存中的了,我们将main方法中红色的那一行注释掉后,我们再运行还是可以看到get到的 value也是234,即缓存中我们已经存在了数据了。

 

     对基本的数据我们可以操作,对于普通的POJO而言,如果要进行存储的话,那么比如让其实现java.io.Serializable接口,因为 memcached是一个分布式的缓存服务器,多台服务器间进行数据共享需要将对象序列化的,所以必须实现该接口,否则会报错的。比如我们写一个简单的测 试Bean如下:

 

class TBean implements java.io.Serializable
{
    private static final long serialVersionUID = 1945562032261336919L;
    private String name;
    public String getName()
    {
        return name;
    }
    public void setName(String name)
    {
        this.name = name;
    }
}

 

然后我们在main方法中加入如下几行代码:

TBean tb = new TBean();
tb.setName("铁木箱子");
cache.add("bean", tb);
TBean tb1 = (TBean)cache.get("bean");
System.out.print("name=" + tb1.getName());
tb1.setName("铁木箱子_修改的");
tb1 = (TBean)cache.get("bean");
System.out.print("name=" + tb1.getName());

 

  我们首先把TBean的一个实例放入缓存中,然后再取出来,并进行名称的修改,然后我们再取这个对象,我们再看其名称,发现修改的对象并不是缓存中的对 象,而是通过序列化过来的一个实例对象,这样我们就无须担心对原生类的无意修改导致缓存数据失效了,呵呵~~看来我也是多此一想啊。所以这表明从缓存中获 取的对象是存入对象的一个副本,对获取对象的修改并不能真正的修改缓存中的数据,而应该使用其提供的replace等方法来进行修改。

 

 

 

    以上是我在windows下对memcached的一点小学习和实践,在以后的项目开发过程中将会更深入的学习和应用这一缓存工具,也希望和有兴趣的同行一起讨论学习该工具的使用 

 

 

 

 

 

 



已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐




摩托罗拉发布会:做工精美,价格惊喜

$
0
0

1-8-1940x1288

按常理一般厂商开新品发布会总是会倾己所能,大张旗鼓地弄得巴不得全世界都知道,但是这一常理放在摩托罗拉身上是不适用。想必今天许多人在凌晨时爬起来,希望看看传闻已久的新一代 Moto X、MOTO 360、新一代 Moto G 和智能耳机 Moto Hint,但最终他们失望了。

失望的原因来自于摩托罗拉在发布会上与记者们的保密协议,因为保密协议,所有产品细节都要等到北京时间 5 号下午 2 点才能公布。如今时间已经到了,就让我们看看摩托罗拉在这次发布会上究竟带给我们什么样的惊喜。

首先是第二代 Moto X,它的命名不会改变,主打人性化语音操作与个性化定制。强大的语音控制可完成电话短信、拍照、打开应用等几乎所有常用操作。它配备分辨率为 1920×1080 的 5.2 英寸屏幕,搭载主频 2.5GHz 的高通 801 MSM8974AC 芯片,2GB RAM,采用 1300 万像素摄像头和 2300 毫安时电池。

除此之外,它还拥有两个闪光灯、四个麦克风和五个传感器,在外观方面,它采用铝合金边框,拥有 30 种背壳,其中包括真皮和竹木。月底登陆美国市场,其中无锁裸机售价为 499 美元,手机自带中文语言,但是语音操控功能并不支持中文。

61ff0139gw1ek1k8lhnvij20su12g4bh
61ff0139gw1ek1k8puumej21f2128wuq
61ff0139gw1ek1k8u617tj21f2128nf5
61ff0139gw1ek1k8y919bj21f611wwtg
61ff0139gw1ek1k978wx7j21dw122h1m

其次是 Moto 360,它搭载分辨率为 320×290 的 1.56 寸屏幕,采用康宁公司的金刚玻璃和 TI MOAP 3 处理器,内存组合为 4G ROM 和 512MB RAM。表身通体由 316L 级别不锈钢打造,重量仅为 49 克,拥有 IP67 级别的防水尘,在功能上与其他 Android Wear 相似,可测运动和心率。

Moto 360 采用无线充电,带有充电底座,电池可以坚持 1 至 2 天,但为了保证连续使用,还是需要每晚充电。为了满足用户需求,摩托罗拉为 Moto 360 设计了黑银两种颜色,分别搭配黑色与灰色的真皮表带,它的售价为 249 美元,另外还有不锈钢表带版本,它的售价则为 299 美元。

Cg-4WVQJVpeID8JXABPHkWpRbbcAARLMgKleQ8AE8ep779
61ff0139jw1ek1llfkvcrj20xc18gk2b
61ff0139jw1ek1llb43j4j20xc18gk2b
61ff0139jw1ek1ll68wgxj20xc18gdne
61ff0139jw1ek1ll0zbmlj20xc18gn6m
61ff0139gw1ek1kdmkb9qj21fc11w7tm
61ff0139gw1ek1kb7i2n0j21fa10kh1i

接下来是新一代 Moto G,它配备分辨率为 1280×720 的 5 寸屏幕,搭载主频为 1.2GHz 的高通骁龙 MSM 四核 8226 芯片,拥有 1GB RAM,储存内存方面分为 8GB 和 16GB 两个版本,它的主摄像头为 800 万像素,前摄像头为 200 万像素,电池容量为 2070 毫安时,还拥有双卡双待版本,不支持 LTE,售价依旧是 179 美元。

61ff0139gw1ek1lh7e022j20n617wwiz
61ff0139gw1ek1lh4qfmaj21kw11y4iw
61ff0139gw1ek1lh2az6gj21kw0wnwzy
1-7-1940x1288
1-5-1940x1288

最后是 Moto Hint,它包括银黑两个颜色,重量只有 6 克,它主打语音操作,与 Moto X 完成配对之后,用户可以直接对 Moto Hint 下达语音指令。同时它附带的桶状保护壳也是一个移动电源,Moto Hint 一次充电可使用 3 个半小时,搭配保护壳则可使用 10 个小时,售价 149 美元。

22298_1087996_308550
22298_1087997_495848
22298_1087998_428054

题图来自 forbes

安心修道,才是王道。

#欢迎关注爱范儿认证微信公众号:AppSolution(微信号:appsolution),发现新酷精华应用。



爱范儿 · Beats of Bits |原文链接· 查看评论· 新浪微博· 微信订阅· 加入爱范社区!


25个必须记住的SSH命令

$
0
0

OpenSSH是SSH连接工具的免费版本。telnet,rlogin和ftp用户可能还没意识到他们在互联网上传输的密码是未加密的,但SSH 是加密的,OpenSSH加密所有通信(包括密码),有效消除了窃      听,连接劫持和其它攻击。此外,OpenSSH提供了安全隧道功能和多种身份验证方法, 支持SSH协议的所有版本。

SSH是一个非常伟大的工具,如果你要在互联网上远程连接到服务器,那么SSH无疑是最佳的候选。下面是通过网络投票选出的25个最佳SSH命令,你必须牢记于心。

(注:有些内容较长的命令,在本文中会显示为截断的状态。如果你需要阅读完整的命令,可以把整行复制到您的记事本当中阅读。)

1、复制SSH密钥到目标主机,开启无密码SSH登录

ssh-copy-id user@host

如果还没有密钥,请使用ssh-keygen命令生成。

2、从某主机的80端口开启到本地主机2001端口的隧道

ssh -N -L2001:localhost:80 somemachine

现在你可以直接在浏览器中输入http://localhost:2001访问这个网站。

3、将你的麦克风输出到远程计算机的扬声器

dd if=/dev/dsp | ssh -c arcfour -C username@host dd of=/dev/dsp

这样来自你麦克风端口的声音将在SSH目标计算机的扬声器端口输出,但遗憾的是,声音质量很差,你会听到很多嘶嘶声。

4、比较远程和本地文件

ssh user@host cat /path/to/remotefile | diff /path/to/localfile –

在比较本地文件和远程文件是否有差异时这个命令很管用。

5、通过SSH挂载目录/文件系统

sshfs name@server:/path/to/folder /path/to/mount/point

http://fuse.sourceforge.net/sshfs.html下载sshfs,它允许你跨网络安全挂载一个目录。

6、通过中间主机建立SSH连接

ssh -t reachable_host ssh unreachable_host

Unreachable_host表示从本地网络无法直接访问的主机,但可以从reachable_host所在网络访问,这个命令通过到reachable_host的“隐藏”连接,创建起到unreachable_host的连接。

7、将你的SSH公钥复制到远程主机,开启无密码登录 – 简单的方法

ssh-copy-id username@hostname

8、直接连接到只能通过主机B连接的主机A

ssh -t hostA ssh hostB

当然,你要能访问主机A才行。

9、创建到目标主机的持久化连接

ssh -MNf <user>@<host>

在后台创建到目标主机的持久化连接,将这个命令和你~/.ssh/config中的配置结合使用:

Host host
ControlPath ~/.ssh/master-%r@%h:%p
ControlMaster no

所有到目标主机的SSH连接都将使用持久化SSH套接字,如果你使用SSH定期同步文件(使用rsync/sftp/cvs/svn),这个命令将非常有用,因为每次打开一个SSH连接时不会创建新的套接字。

10、通过SSH连接屏幕

ssh -t remote_host screen –r

直接连接到远程屏幕会话(节省了无用的父bash进程)。

11、端口检测(敲门)

knock <host> 3000 4000 5000 && ssh -p <port> user@host && knock <host> 5000 4000 3000

在一个端口上敲一下打开某个服务的端口(如SSH),再敲一下关闭该端口,需要先安装knockd,下面是一个配置文件示例。

[options]
logfile = /var/log/knockd.log
[openSSH]
sequence = 3000,4000,5000
seq_timeout = 5
command = /sbin/iptables -A INPUT -i eth0 -s %IP% -p tcp –dport 22 -j ACCEPT
tcpflags = syn
[closeSSH]
sequence = 5000,4000,3000
seq_timeout = 5
command = /sbin/iptables -D INPUT -i eth0 -s %IP% -p tcp –dport 22 -j ACCEPT
tcpflags = syn

12、删除文本文件中的一行内容,有用的修复

ssh-keygen -R <the_offending_host>

在这种情况下,最好使用专业的工具。

13、通过SSH运行复杂的远程shell命令

ssh host -l user $(<cmd.txt)

更具移植性的版本:

ssh host -l user “`cat cmd.txt`”

14、通过SSH将MySQL数据库复制到新服务器

mysqldump –add-drop-table –extended-insert –force –log-error=error.log -uUSER -pPASS OLD_DB_NAME | ssh -C user@newhost “mysql -uUSER -pPASS NEW_DB_NAME”

通过压缩的SSH隧道Dump一个MySQL数据库,将其作为输入传递给mysql命令,我认为这是迁移数据库到新服务器最快最好的方法。

15、删除文本文件中的一行,修复“SSH主机密钥更改”的警告

sed -i 8d ~/.ssh/known_hosts

16、从一台没有SSH-COPY-ID命令的主机将你的SSH公钥复制到服务器

cat ~/.ssh/id_rsa.pub | ssh user@machine “mkdir ~/.ssh; cat >> ~/.ssh/authorized_keys”

如果你使用Mac OS X或其它没有ssh-copy-id命令的*nix变种,这个命令可以将你的公钥复制到远程主机,因此你照样可以实现无密码SSH登录。

17、实时SSH网络吞吐量测试

yes | pv | ssh $host “cat > /dev/null”

通过SSH连接到主机,显示实时的传输速度,将所有传输数据指向/dev/null,需要先安装pv。

如果是Debian:

apt-get install pv

如果是Fedora:

yum install pv

(可能需要启用额外的软件仓库)。

18、如果建立一个可以重新连接的远程GNU screen

ssh -t user@some.domain.com /usr/bin/screen –xRR

人们总是喜欢在一个文本终端中打开许多shell,如果会话突然中断,或你按下了“Ctrl-a d”,远程主机上的shell不会受到丝毫影响,你可以重新连接,其它有用的screen命令有“Ctrl-a c”(打开新的shell)和“Ctrl-a a”(在shell之间来回切换),请访问http://aperiodic.net/screen/quick_reference阅读更多关于 screen命令的快速参考。

19、继续SCP大文件

rsync –partial –progress –rsh=ssh $file_source $user@$host:$destination_file

它可以恢复失败的rsync命令,当你通过VPN传输大文件,如备份的数据库时这个命令非常有用,需要在两边的主机上安装rsync。

rsync –partial –progress –rsh=ssh $file_source $user@$host:$destination_file local -> remote

rsync –partial –progress –rsh=ssh $user@$host:$remote_file $destination_file remote -> local

20、通过SSH W/ WIRESHARK分析流量

ssh root@server.com ‘tshark -f “port !22″ -w -' | wireshark -k -i –

使用tshark捕捉远程主机上的网络通信,通过SSH连接发送原始pcap数据,并在wireshark中显示,按下Ctrl+C将停止捕捉,但 也会关闭wireshark窗口,可以传递一个“-c #”参数给tshark,让它只捕捉“#”指定的数据包类型,或通过命名管道重定向数据,而不是直接通过SSH传输给wireshark,我建议你过滤数 据包,以节约带宽,tshark可以使用tcpdump替代:

ssh root@example.com tcpdump -w – ‘port !22′ | wireshark -k -i –

21、保持SSH会话永久打开

autossh -M50000 -t server.example.com ‘screen -raAd mysession’

打开一个SSH会话后,让其保持永久打开,对于使用笔记本电脑的用户,如果需要在Wi-Fi热点之间切换,可以保证切换后不会丢失连接。

22、更稳定,更快,更强的SSH客户端

ssh -4 -C -c blowfish-cbc

强制使用IPv4,压缩数据流,使用Blowfish加密。

23、使用cstream控制带宽

tar -cj /backup | cstream -t 777k | ssh host ‘tar -xj -C /backup’

使用bzip压缩文件夹,然后以777k bit/s速率向远程主机传输。Cstream还有更多的功能,请访问http://www.cons.org/cracauer/cstream.html#usage了解详情,例如:

echo w00t, i’m 733+ | cstream -b1 -t2

24、一步将SSH公钥传输到另一台机器

ssh-keygen; ssh-copy-id user@host; ssh user@host

这个命令组合允许你无密码SSH登录,注意,如果在本地机器的~/.ssh目录下已经有一个SSH密钥对,ssh-keygen命令生成的新密钥可 能会覆盖它们,ssh-copy-id将密钥复制到远程主机,并追加到远程账号的~/.ssh/authorized_keys文件中,使用SSH连接 时,如果你没有使用密钥口令,调用ssh user@host后不久就会显示远程shell。

25、将标准输入(stdin)复制到你的X11缓冲区

ssh user@host cat /path/to/some/file | xclip

你是否使用scp将文件复制到工作用电脑上,以便复制其内容到电子邮件中?xclip可以帮到你,它可以将标准输入复制到X11缓冲区,你需要做的就是点击鼠标中键粘贴缓冲区中的内容。

 

 

转载自:http://www.cnblogs.com/weafer/archive/2011/06/10/2077852.html



已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



使用Xenotix_XSS框架进行自动化安全测试

$
0
0

‍‍‍‍

本文简单的介绍Xenotix_XSS框架常用的xss测试自动测试工具,可以用于对页面进行自动安全扫描。

配置服务器:

点击“setting—>configure server—>start”,服务器就配置完成。

扫描测试

scanner里面的”get request manualmode”是手动测试,即每次点击start的时候,只会执行一个payload,而”get request auto mode”是自动测试,设置时间间隔,就可以自动扫描。每次扫描的结果会在下面的三个浏览器中显示结果。

URL填写要测试的页面,parmeter填写”参数=”,测试时完整的URL可以在Browse处看到。

手动测试:


自动测试:

自动模式,在Inteval中设置时间间隔,然后点击start开始测试,可以点击pause暂停

 

多参数测试multiple parameter scanner:

点击”get parameters”会自动识别出URL中的多个参数,设置时间间隔后,点击start会逐个对每次参数进行测试。

URL fuzzer:

将需要fuzz的参数值修改为” [X]”,然后工具会对设置了[X]的参数进行测试

POST request scanner:

URL填写要测试的页面

Parameters填写POST的参数,参数值用[X]代替,response会在页面和postresponse body里面显示。

request repeater:

repeater里面支持get、post和trace方法,同样的,将HOST填写地址,path填写路径,参数值用[X]代替,start开始扫描

DOM SCAN:

个人写了几个DOM脚本,结果都没扫描到。。。没法截图了

 

隐藏表单检测:hidden parameter detector

很明显,就是检测html中的隐藏表单。

在tool下面的encode/decode工具也是比较常用的,不过编码不是太多:

‍‍‍‍

Cacti监控Redis实现过程

$
0
0
 Cacti是一套基于PHP,MySQL,SNMP及RRDTool开发的网络流量监测图形分析工具。被广泛的用于对服务器的运维监控中,Cacti提供了一种插件式的管理,只要按要求写好特定的模板,那么你就可以对任何服务进行流量监控。本文就是要为大家介绍两个模板,分别是MongoDB和Redis的Cacti模板,使用它,你可以对你的MongoDB和Redis服务进行流量监控。
  1,升级 python,此时如果是系统默认的python版本,会出现以下错误
python setup.py install
Traceback (most recent call last):
File "setup.py", line 3, in ?
from redis import __version__
File "/usr/local/src/redis-2.4.11/redis/__init__.py", line 1, in ?
from redis.client import Redis, StrictRedis
File "/usr/local/src/redis-2.4.11/redis/client.py", line 240
with self.pipeline(True, shard_hint) as pipe:
^
SyntaxError: invalid syntax
  2,安装python,先配置python环境,下载python源代码
wget http://www.python.org/ftp/python/2.5.2/Python-2.5.2.tar.bz2
$ tar –jxvf Python-2.5.2.tar.bz2
$ cd Python-2.5.2
$ ./configure
$ make
$ make install
[root@mysqlvm2 Python-2.5.2]# python
Python 2.4.3 (#1, Jun 11 2009, 14:09:37)
[GCC 4.1.2 20080704 (Red Hat 4.1.2-44)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>
  Version还是2.4.3的,解决办法如下:
  #cd /usr/bin
  #ll |grep python   //查看该目录下python
  #rm -rf python
  重新做个软连接就可以了
  [root@mysqlvm2 Python-2.5.2]# ln -s /usr/local/bin/python /usr/bin/python
  [root@mysqlvm2 Python-2.5.2]#
  [root@mysqlvm2 Python-2.5.2]# python
  Python 2.5.2 (r252:60911, Aug  4 2014, 14:43:36)
  [GCC 4.1.2 20080704 (Red Hat 4.1.2-54)] on linux2
  Type "help", "copyright", "credits" or "license" for more information.
  >>>
 3,然后下载redis的模板
  wget http://mysql-cacti-templates.googlecode.com/files/better-cacti-templates-1.1.8.tar.gz
  配置监控脚本
  mongodb或redis的监控所需到的是你下载目录中的better-cacti-templates-1.1.8\scripts下的
  ss_get_by_ssh.php 这个脚本 这个脚本需要放在cacti的服务端。
  如果你cacti是装到/var/www/html/cacti/目录下。
  把该文件放在其下面的scripts目录下。别忘了看下权限。要有执行权限。
  然后修改该文件。主要修改一下选项,大概在40行。
  # ============================================================================
  $ssh_user   = 'root';                          # SSH username
  $ssh_port   = 22;                               # SSH port
  $ssh_iden   = '-i /root/.ssh/id_rsa';   # SSH identity
  ##修改根据你的配置,你的ssh连接用户,还有认证私钥的位置。
  大该在50行,还可以修改其默认的去探测的端口(如果redis不是正常默认端口启动需要修改这些)。
  $redis_port    = 6379;                    # Which port redis listens on
  4,导入模板,模板目录为better-cacti-templates-1.1.8\templates
  在cacti界面导入界面,创建redis服务器的Graph,如下所示:
  5,去查看Graph效果图,如下所示:


顺其自然EVO 2014-09-05 11:00 发表评论

数据库系统load飙高问题解决思路

$
0
0
  工作过程中有时候会接收到 数据库服务器器load 飙高的报警,比如:
  load1 15.25 base: 8.52,collect time:2014-08-30
  如何处理load 异常飙高的报警呢? 本文尝试从原理,原因,解决方法来阐述这类问题的解决思路。
   一 原理分析
  CPU作为服务器的关键资源经常成为性能瓶颈的根源,CPU使用率高并不总是意味着CPU工作繁忙,它有可能是正在等待其他子系统。在进行性能分析时,将所有子系统当做一个整体来看是非常重要的,因为在子系统中可能会出现瀑布效应。衡量CPU 系统负载的指标是load,load 就是对计算机系统能够承担的多少负载的度量,简单的说是进程队列的长度。简单的例子比如食堂有五个窗口,当有小于五个学生来打饭,五个窗口都能及时处理,但是当学生个数超过5个,必然会出现等待的学生。请求大于当前的处理能力,会出现等待,引起load升高。
  Load Average 就是一段时间(1min,5min,15min)内平均Load。平均负载的最佳值是1,这意味着每个进程都可以在一个完整的CPU 周期内完成。
  14:50:31 up 166 days,  1:54, 295 users,  load average: 0.05, 0.04, 0.00
   二 原因分析
  一般导致 MySQL服务器load飙高的原因可能有以下几种情况:
  1 业务并发调用全表扫描/带有order by 排序的 SQL语句.
  2 SQL语句没有合适索引/执行计划出错/update/delete where扫描全表,阻塞其他访问相同表的sql执行.
  3 存在秒杀类似的业务比如聚划算10点开团或者双十一秒杀,瞬时海量访问给数据库带来冲击。
  4 数据库做逻辑备份(需要全表扫描)或者多实例的压缩备份(压缩时需要大量的cpu计算,会导致系统服务器load飙高)
  5 磁盘写入方式改变 比如有writeback 变为 write through
  RAID卡都有写cache(Battery Backed Write Cache),写cache对IO性能的提升非常明显,因为掉电会丢失数据,所以必须由电池提供支持。
  电池会定期充放电,一般为90天左右,当发现电量低于某个阀值时,会将写cache策略从writeback置为writethrough,相当于写cache会失效,这时如果系统有大量的IO操作,可能会明显感觉到IO响        应速度变慢,cpu 队列堆积系统load 飙高。
  6 其他 欢迎补充 。
   三 解决方法
  在Load average 高的情况下如何鉴别系统瓶颈?如何判断系统是否已经Over Load呢?要去检查判断是CPU不足,还是io不够快造成或是内存不足?
  这里笔者处理的方式 一般根据cpu数量去判断,也就是Load平均要小于CPU的数量,负载的正常值在不同的系统中有着很大的差别。在单核处理器的工作站中,1或2都是可以接受的。多核处理器的服务器(比如24核)上,load 会到达20 ,甚至更高。以多实例混合公用一台24核物理机为例,当DBA收到数据库服务器load 飙高报警后,一般的处理步骤
  a) 数据库层面
  1 top -u mysql -c 检查当前占用cpu资源最多的进程命令。-c 是为了显示出进程对应的执行命令语句,方便查看是什么操作导致系统load飙高。
  2 根据不同的情况获取pid 或者MySQL的端口号
  3 如果是MySQL 数据库服务导致laod 飙高,则可以使用如下命令
  show processlist;
  SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST WHERE COMMAND <> 'sleep' AND TIME>100;
  或
  orzdba 工具检查逻辑读/thread active的值。用法orzdba --help
  orztop 工具检查当前正在执行的慢sql,用法orztop -P $port
  4 获取异常的sql之后,剩下的比较好解决了。结合第一部分中的几条原因
  a 选择合适的索引
  b 调整sql 语句 比如对应order by 分页采用延迟关联
  c 业务层面增加缓存,减少对数据库的直接访问等
  b) OS 系统层面 检查系统IO
  使用iostat 命令查看r/s(读请求),w/s(写请求),avgrq-sz(平均请求大小),await(IO等待), svctm(IO响应时间)
  r/s ,w/s是每秒读/写请求的次数。
  util是设备的利用率。如果它接近100%,通常说明设备能力趋于饱和(并不绝对,比如设备有写缓存)。有时候可能会出现大于100%的情况,这多半是计算时四舍五入引起的。
  svctm是平均每次请求的服务时间。这里有一个公式:(r/s+w/s)*(svctm/1000)=util。举例子:如果util达到100%,那么此时  svctm=1000/(r/s+w/s),假设IOPS是1000,则svctm大概在1毫秒左右,如果长时间大于这个数值,说明系统出了问题。
  await是平均每次请求的等待时间。这个时间包括了队列时间和服务时间,也就是说,一般情况下,await大于svctm,它们的差值越小,队列时间越短,反之差值越大,队列时间越长,说明系统出了问题。
  avgqu-sz是平均请求队列的长度。毫无疑问,队列长度越短越好。


顺其自然EVO 2014-09-05 10:59 发表评论

PHP程序员最常犯的11个MySQL错误

$
0
0

对于大多数web应用来说,数据库都是一个十分基础性的部分。如果你在使用 PHP,那么你很可能也在使用 MySQL—LAMP系列中举足轻重的一份子。

对于很多新手们来说,使用PHP可以在短短几个小时之内轻松地写出具有特定功能的代码。但是,构建一个稳定可靠的数据库却需要花上一些时日和相关技能。下面列举了我曾经犯过的最严重的11个MySQL相关的错误(有些同样也反映在其他语言/数据库的使用上)。

1.使用MyISAM而不是InnoDB

MySQL有很多数据库引擎,但是你最可能碰到的就是MyISAM和InnoDB。

MySQL默认使用的是MyISAM。但是,很多情况下这都是一个很糟糕的选择,除非你在创建一个非常简单抑或实验性的数据库。外键约束或者事务处理对于数据完整性是非常重要的,但MyISAM都不支持这些。另外,当有一条记录在插入或者更新时,整个数据表都被锁定了,当使用量增加的时候这会产生非常差的运行效率。

结论很简单:使用InnoDB。

2.使用PHP的mysql函数

PHP自产生之日就提供了MySQL库函数(or near as makes no difference)。很多应用仍然在使用类似mysql_connect、mysql_query、mysql_fetch_assoc等的函数,尽管PHP手册上说:

如果你在使用MySQL v4.1.3或者更新版本,强烈推荐使用您使用mysqli扩展。

mysqli(MySQL的加强版扩展)有以下几个优点:

可选的面向对象接口

prepared表达式,这有利于阻止SQL注入攻击,还能提高性能

支持更多的表达式和事务处理

另外,如果你想支持多种数据库系统,你还可以考虑PDO。

3.没有处理用户输入

这或者可以这样说#1:永远不要相信用户的输入。用服务器端的PHP验证每个字符串,不要寄希望与JavaScript。最简单的SQL注入攻击会利用如下的代码:

$username = $_POST["name"];

$password = $_POST["password"];

$sql = “SELECT userid FROM usertable WHERE username=’$username’ AND password=’$password’;”;

// run query…

只要在username字段输入”admin’;–”,这样就会被黑到,相应的SQL语句如下:

SELECT userid FROM usertable WHERE username=’admin’;

狡猾的黑客可以以admin登录,他们不需要知道密码,因为密码段被注释掉了。

4.没有使用UTF-8

美国、英国和澳大利亚的我们很少考虑除英语之外的其他语言。我们很得意地完成了自己的”杰作”却发现它们并不能在其他地方正常运行。

UTF-8解决了很多国际化问题。虽然在PHP v6.0之前它还不能很好地被支持,但这并不影响你把MySQL字符集设为UTF-8。

5.相对于SQL,偏爱PHP

如果你接触MySQL不久,那么你会偏向于使用你已经掌握的语言来解决问题,这样会导致写出一些冗余、低效率的代码。比如,你不会使用MySQL自带的AVG()函数,却会先对记录集中的值求和然后用PHP循环来计算平均值。

此外,请注意PHP循环中的SQL查询。通常来说,执行一个查询比在结果中迭代更有效率。

所以,在分析数据的时候请利用数据库系统的优势,懂一些SQL的知识将大有裨益。

6.没有优化数据库查询

99%的PHP性能问题都是由数据库引起的,仅仅一个糟糕的SQL查询就能让你的web应用彻底瘫痪。MySQL的EXPLAIN statement、Query Profiler,还有很多其他的工具将会帮助你找出这些万恶的SELECT。

7.不能正确使用数据类型

MySQL提供了诸如numeric、string和date等的数据类型。如果你想存储一个时间,那么使用DATE或者DATETIME类型。如果这个时候用INTEGER或者STRING类型的话,那么将会使得SQL查询非常复杂,前提是你能使用INTEGER或者STRING来定义那个类型。

很多人倾向于擅自自定义一些数据的格式,比如,使用string来存储序列化的PHP对象。这样的话数据库管理起来可能会变得简单些,但会使得MySQL成为一个糟糕的数据存储而且之后很可能会引起故障。

8.在查询中使用*

永远不要使用*来返回一个数据表所有列的数据。这是懒惰:你应该提取你需要的数据。就算你需要所有字段,你的数据表也不可避免的会产生变化。

9.不使用索引或者过度使用索引

一般性原则是这样的:select语句中的任何一个where子句表示的字段都应该使用索引。

举个例子,假设我们有一个user表,包括numeric ID(主键)和email address。登录的时候,MySQL必须以一个email为依据查找正确的ID。如果使用了索引的话(这里指email),那么MySQL就能够使用更快的搜索算法来定位email,甚至可以说是即时实现。否则,MySQL就只能顺序地检查每一条记录直到找到正确的email address。

有的人会在每个字段上都添加索引,遗憾的是,执行了INSERT或者UPDATE之后这些索引都需要重新生成,这样就会影响性能。所以,只在需要的时候添加索引。

10.忘记备份

虽然比较罕见,但是数据库还是有崩溃的危险。硬盘有可能损坏,服务器有可能崩溃,web主机提供商有可能会破产!丢失MySQL数据将会是灾难性的,所以请确保你已经使用了自动备份或者已经复制到位。

11.Bonus mistake-不考虑使用其他数据库

对于PHP开发人员来说,MySQL可能是使用最广泛的数据库系统,但并不是唯一的选择。PostgreSQL和Firebird是最强有力的竞争者:这个两者都是开源的,而且都没有被公司收购。微软提供了sql server Express,甲骨文提供了10g Express,这两者都是企业级数据库的免费版本。有时候,对于一个较小的web应用或者嵌入式应用,SQLite也不失为一个可行的替代方案。

linux 下如何抓取HTTP流量包

$
0
0
基于某些原因你需要嗅探HTTP Web流量(即HTTP请求和响应)。例如,你可能会测试Web服务器的性能,或者x奥uy调试Web应用程序或RESTful服务 ,又或者试图解决PAC(代理自动配置)问题,或检查从网站上下载的任何恶意文件。甭管是什么原因,对于系统管理员,开发人员,甚至是最终用户,嗅探HTTP流量是非常有帮助的。 数据包嗅探工具如tcpdump是普遍用于实时数据包转储,需要设定一些过滤规则,只捕获HTTP流量,即便如此,它的输出内容很难理解,需要一定的协议基础知识。实时的Web服务器日志分析工具如ngxtop提供了可读的实时网络流量的痕迹,但仅适用于具有完全访问过的Web服务器的日志。 有没有一款功能强大且又只针对HTTP流量的工具呢?那就是httpry,HTTP数据包嗅探工具。捕获HTTP数据包,并显示可读格式的HTTP协议层面的内容。

安装httpry

在基于debian系统如Ubuntu,httpry没有包含在基础仓库中。
$ sudo apt-get install gcc make git libpcap0.8-dev
$ git clone https://github.com/jbittel/httpry.git
$ cd httpry
$ make
$ sudo make install
Fedora、centos、RHEL系统需要安装EPEL源
$ sudo yum install httpry
也可以源码编译
$ sudo yum install gcc make git libpcap-devel
$ git clone https://github.com/jbittel/httpry.git
$ cd httpry
$ make
$ sudo make install

httpry基本用法

$ sudo httpry -i <network-interface>
httpry监听在指定的网卡下,实时捕获并显示HTTP请求与响应的包 httpry-1 在大多数情况下,输出滚动非常快的,需要保存捕获的HTTP数据包进行离线分析。可以使用-b或-o选项。“-b”选项将原始的HTTP数据包保存到一个二进制文件,然后可以用httpry进行重播。 “-o”选项保存可读的输出到文本文件。 保存到二进制文件中:
$ sudo httpry -i eth0 -b output.dump
重放:
$ httpry -r output.dump
保存到文本文件:
$ sudo httpry -i eth0 -o output.txt

httpry高级用法

如果你要捕获特定的HTTP方法,如GET、POST、PUT、HEAD、CONNECT等等,可以使用‘-m'选项:
$ sudo httpry -i eth0 -m get,head
httpry-2 如果你下载httpry源码,在源码目录下,有一个perl脚本来帮助我们分析httpry输出。该脚本在httpry/scripts/plugins目录下。 如果你想编写一个httpry输出的定制解析器,这些脚本是个很好的例子。功能有:
  • hostname : 显示一些列唯一主机名
  • find_proxies:检测web代理
  • search_terms:查找并计算在搜索服务中输入搜索词
  • content_analysis:查找包含特定关键字的URI
  • xml_output:以xml格式输出
  • log_summary:生成日志摘要
  • db_dump:将日志转存到mysql数据库中
在使用这些脚本前,先使用’-o'选项运行一段时间。一旦得到输出,运行这些脚本分析:
$ cd httpry/scripts
$ perl parse_log.pl -d ./plugins <httpry-output-file>
parse_log.pl执行完后,会在httpry/scripts目录下生成一些分析结果文件(*.txt/xml)。例如,log_summary.txt看起来像下面这样: httpry-3

前台页面优化全攻略(二)

$
0
0

  在 上一篇文章中,我们讨论了一些基本的页面优化和减肥方案,现在我们的页面已经被缩减了30%-50%,如果你还没有阅读上一篇文章,我建议你完成那些基础热身之后再继续进阶的训练。

  如果你已经尝试了基础的热身,那我们就继续采取一些更极客的解决方案。

  1. 移除网站中社交网络的组件

  看到这个标题请不要惊讶,我并不是让你放弃第三方社交平台,而是希望你能放弃那些肥胖的官方组件。你的网站中有社交平台的分享按钮么?这些按钮会为你的网站增重大概0.5M。我们知道,这些分享功能都是由 JavaScript实现的,有些分享组件的网络连接会强制在加载页面之前进行。

  太大的社交组件完全没有必要,你完全可以添加一个轻量级的社交分享按钮在你的网页中,几行html代码就能搞定的事为什么要弄的这么复杂呢?很多人可能都没有在意到一个小细节,FaceBook的官方”赞“按钮就要270KB!现在你应该明白这么做的必要性了,我们应该 深入研究如何优化社交组件

  如果你觉得一个简单的按钮无法提供数据统计等功能,可以看一看 这篇文章,学习一下如果添加高性能的轻量级社交组件。

  2. 检查所有第三方组件的大小

  社交网络并不是唯一的原因,其它第三方的组件也大大增大了你网站的大小,这些组件有时候甚至会加载其它网站的内容,这些加载的数据可能高达几百KB。

  如果你必须要使用这个组件,那我们要考虑的就是如何更好的处理和简化这个组件了。理想情况下, JavaScript组件应该都是轻量级的,它们在页面底部被加载,

  3. 考虑使用懒加载或内容点播

  假设你的网站是用来显示视频供应商提供的视频。无论用户是否有意要播放,页面都会加载视频API和其它相关的资源。为什么不让用户请求之后再加载这些东西呢?

  你也可以采用滚动式页面,在用户往下拉滚动条时再开始加载新的内容,这样做虽然可能会对SEO造成影响,但是在特定的情况下,如照片展示,微博内容展示等都会有不错的效果。

  4. 用CSS取代图片

  你还在用切片技术创建图片的圆角边框等样式吗?我们都知道, CSS可以生成很多种前台效果,包括各种样式的按钮,背景……虽然他们在不同的浏览器中可能会有不同的展示样式,但用户并不会在意这些,他们不会像你一样开很多个浏览器对比同样的代码会有什么样的区别。

  你完全不用担心古代浏览器会对CSS样式造成影响,当你构建一个响应式设计的页面,你要通配各种大小的屏蔽,这个时候如果你还是用图片就会有很多问题,所以CSS是很好的选择。

  不过需要注意的是重绘CSS的阴影和梯度代价也是非常大的,特别是你同时在几十个元素中都添加了这些特性。所以你必须多次去实践,对比在你的网站中是用CSS好还是用图片好。这些都要因网站具体情况而定。

  5. 用CSS效果和动画取代JavaScript

  如果在你的 JavaScript代码中到处都是$("#x").fade() 和 $("#y").slideDown()这会对你的网站造成很大的影响。在几年前我们必须得这么做,但是现在不同了,我们可以选择用CSS3的 animationstransitions 和  transformations取代了JavaScript的效果,原因如下:

  1).  CSS3 animation是由本地浏览器自主绘制的,在没有错误的情况下,它会比 JavaScript效果好,而且快很多。

  2).  CSS3 animation代码更容易编写,而且代码量少。

  3). 如果 JavaScript不使用第三方类库,3D效果的实现会比 CSS3提供3D转换难很多。

  6. 使用可缩放矢量图(SVGs)

  SVGs 包括点,线和图形,它们被以矢量的形式被定义在XML中,SVGs是响应式设计中比更理解的解决方案,它们可以缩放成任意大小而且不会影响到显示的效果,而且文件大小一般都会小于bitmap。

  当然,SVGs并不是在任何情况下都适用,如果是相册或是混合通道的图片就应该使用JPG或是PNG格式。其他比如logo,图表可以放心选用SVGs。

  有一些工具可以直接把bitmaps格式的图转成矢量格式,但是多少影响到图片的效果。这里推荐 Inkscape 和  SVG edit,它们都是很不错的创建SVGs的工具包。 

  7. 用图标字体(icon fonts)代替图片

  利用字体工具把我们平时 Web 上用的图形图标(icons)转换成 web fonts,就成了 icon fonts,它可以借助 CSS 的 @font-face 嵌入到网页里,用以显示 icons。因为字体是矢量化图形,它天生具有「分辨率无关」的特性,在任何分辨率和PPI下面,都可以做到完美缩放,不会像传统位图,如:png,jpeg,放大后有锯齿或模糊现象。

  由于图标字体的灵活性和易用性使得图标字体使用越来越广泛了,我们经常可以看到不同的UI框架都整合了各种的图标字体。

  除了「分辨率无关」这个最大的优点之外,icon fonts 还具有:

  • 文件小:相比图片几十几百KB的容量,icon fonts 几乎是羽翼级轻量。
  • 加载性能好:因为图标都被打包进一套字体内,http request 减少。这如同我们常用的 css sprites 技术。
  • 支持CSS样式:和普通字体一样,你可以利用CSS来定义大小、颜色、阴影、hover状态、透明度、渐变等等…
  • 兼容性好:web fonts 起源很早,别说主流浏览器,连IE6/7都能良好支持。除了一些老的移动端浏览器,如Android 2.1以下的初代浏览器,Opera mini 这类自限型浏览器。

  当然 icon fonts 也有它的不足:

  • 样式单一,无法针对不同分辨率来调整icon 的细节,比如降低大尺寸icon 的线条粗细。
  • 颜色单一,CSS 无法方便的去定义彩色的 icon,倒是有通过叠加组合的方式来达到彩色图标的目的。
  • 移动端浏览器兼容性还不够完善,像Opera mini、Windows phone 7.0-7.8 都不能正常显示icon fonts。
  • 有少量的移动设备有可能会和 icon fonts 的字符编码冲突,导致icon 显示不正常(我们自己风车Android 版本就碰到了这个问题)。

  所以 icon fonts 也并不是一套完美的响应式图片的解决方案,当它适宜你的应用场景时,比如:

  • 你的网站是扁平化或简约风格,图标样式单一,颜色为纯色。
  • 你的目标用户使用桌面浏览器为主,或者,
  • 你愿意为非兼容设备做兼容hack。

  icon fonts 是一个令设计师和前端工程师都心花怒放的方案。

  icon fonts 的制作主要有两条思路:

  1. 利用字体工具手动制作
  2. 利用在线工具自动生成

  8. 使用sprite来优化图片资源

  Sprite”(精灵)这个词在计算机图形学中有它独特的定义,由于游戏、视频等画质越来越高,必须有一种技术可以智能的处理材质和贴图,并且要同时保持画面流畅。“Sprite”就是这样一种技术,它将许多图片组合到一个网格上,然后通过程序将每个网格的内容定位到画面上。

  Sprite被定位到一副静态图片上,并且通过简单的程序或硬件即可正确定位到画面上,一幅幅图片就像是被“变”出来的,他们并没有单独占用内存,所以被取名为“Sprite精灵”。

  时间进行到2000年,Web设计向着精致、巧妙的方向发展。设计师们开始考虑使用非 Javascript的方 式制作鼠标滑过、悬停菜单的效果,这时CSS Sprite应运而生,它基于同上文提到的游戏Sprite同样的原理,并且使用CSS更容易控制,很快的流行开来。

  当页面加载时,不是加载每个单独图片,而是一次加载整个组合图片。这是一个了不起的改进,它大大减少了HTTP请求的次数,减轻服务器压力,同时缩短了悬停加载图片所需要的时间延迟,使效果更流畅,不会停顿。

  CSS Sprites可以用在很多场合,大型网站可以将许多单独的图片,以有机的方式组合起来,从而使其便于维护和更新。图片之间通常会留出较大的空白,使 得图片不会影响网页的内容。但同时CSS Sprite大多使用于较固定的像素定位中,它的弹性较差,收到定位等因素的制约。所以,你需要在可维护性vs降低负载之间权衡利弊,选择最适合你的项目 的方式。

  在网站图片的解决方案中, CSS3应该是首选,其次是SVG和icon font,最后才是Bitmap。经常使用的Bitmap文件应该打包放在一个单独的sprite中,这样一来图片就可以在CSS中访问到了,像这样:

.sprite {
width: 16px;
height: 16px;
background: url("sprite.png") 0 0 no-repeat;
}
.sprite.help { background-position: 0 -16px; }
.sprite.info { background-position: 0 -32px; }
.sprite.user { background-position: 0 -48px; }

  9. 使用data URIs

  假设你有一个图片,把它在网页上显示出来的标准方法是:

<img src="http://gbtags.com/images/A.png"/>

  这种取得资料的方法称为 http URI scheme ,同样的效果使用 data URI scheme 可以写成:

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAIAAAA

7ljmRAAAAGElEQVQIW2P4DwcMDAxAfBvMAhEQMYgcACEHG8ELxtbPAAAAAElFTkSuQmCC" />

  换句话说我们把图像档案的内容内置在 HTML 档案中,节省了一个 HTTP 请求。

  data uri的主要优点是减少了http请求数,调用起来比css sprite更加灵活,缺点是增加了客户端的资源消耗。

  在所有浏览器的非缓存的模式下, CSS sprite 方式比 data URI 方式快了数百微秒。但事实上 CSS Sprite 比 Data URI 方式多发送了一次连接请求,包括 TCP 慢启动招致所有相关的连接开销。

  缓存条件下 Android 4.2 和 iOS 6 的 CSS sprite 模式都有大概 2 倍的速度提升,只是 iOS 条件下减少了 220ms 而 Android 减少了 70ms (原生浏览器)。相对来说,Chrome 和 Firefox 的情况平衡得好点,缓存和非缓存情况下只有 50% 到 60ms 左右的性能差异。

  在这里我建议将 data URIs 用于非常小的资源,并且不能在 CSS 和 内联 HTML 中多次使用它们。

  10. 使用网站评估工具

  检查是否减肥成功的最好方法就是站到称上称一下,同样,你需要使用网站评估工具评估一下你给网站瘦身的效果。很多开发者工具和免费的在线测试工具都不错,百度和Google的站长分析工具都很好用。

  总结

  大家可以明显的发现这篇文章比 第一篇不正常多了,更显极客范儿,相信能把实践跟到这的站长已经不多了。对于我们来说,极客的瘦身之道远不仅如此,在下一篇文章中,我会列出更加疯狂的瘦身技巧。成功的都是坚持到最后的那些人,共勉之~

这份工作并不浪漫!担任设计师一年,我所学到的十件事

$
0
0

过去一年,加入 K-12 教育新创公司 Edmodo 的设计团队中带给我无与伦比的经验,Edmodo 获得包括 Greylock Partners, Benchmark Capital, and Union Square Ventures 等众多创投支持。虽然以前在学校里我跟朋友执行了几项计划。但在这十二个月,与资深前辈共同推出世界级的软件,还是令我大开眼界。既然我已经参与不少产品迭代周期,与产品开发团队各种职位的成员合作,我从中学到了很多宝贵的经验,我想与刚毕业而且即将进入新创领域的朋友们分享:

1. 认清自己的任务是让优秀的设计成真

设计师的主要职责是什么?穿上紧身烟管裤、建立完美的 PSD 图层、上传不大不小刚好符合 Dribbble 400×300 尺寸的作品?我们很容易「浪漫化」自己的工作,如果对最终产品不满意,就把所有错误都归咎于工程师。然而正确的心态应该是,出得了大门的产品,就是已经可以见人的。要确保你的设计按照自己的意愿落实,最好的方式就是跟工程师密切合作,没错,请与他们并肩工作。

2. 不厌其烦地沟通

无论产品循环周期处于哪个阶段,团队成员彼此宁可沟通到烦人,也不要每个人都埋头苦干却静默不语。正在开发的产品目标、产品要求、产品被视为成功的条件⋯⋯我们对这些都应该有清楚的理解。过度沟通的成本是跟同事多聊天,或者多花一点时间发邮件,但是缺乏沟通的后果却是,浪费时间、努力可能付诸东流、大家相互指责,甚至导致天妒英才的「独角兽」黯然从设计舞台谢幕。

3. 随时掌握意见回馈,加速进入反覆打磨(iteration)的过程

从团队之间的沟通,到你个人的工作流程,都应该不断收集各种反馈。就内部「回馈循环(feedback loop)」而言,在自己设计的过程中,切记利用前端代码或高保真原型工具,随时掌握每个动作产生的结果,愈能模拟使用者与设计互动的实际状况,愈好。把范围拉大到公司,我们也希望尽快获得工程师、产品经理、以及其他设计师的回馈,以建立共识,并且辨识出瓶颈。外部回馈循环同样重要,当产品正式交付,设计师应与需求分析、用户研究、行销团队一起i一起合作,观察产品在使用者手中有怎么样的表现,此外,即使我们不需要每个意见都照单全收,但不妨训练自己以开放的心态接纳反馈,但以批判性思考看待反馈。我们应该有足够的自信想出缜密的解决方案,同时也能谦逊的舍弃。

4. 设身处地为其他团队成员着想

当一名体贴的设计师,努力培养同理心,能够用其他不同团队听得懂的语言解释你的设计,除非你能教育外行人理解美妙的设计术语。拆解你的设计,融入个别团队的特性或者公司目标,你得对他们各自的任务有基本的了解,并且懂得欣赏他们正在付诸实践的事情。比如产品经理,他们的主要职责,也许就是在「个人使用体验」与「在注册过程中加入『邀请朋友』的选项」之间做出取舍,抑或向所有人解释,如果为了打磨得更加完美,而想在产品发表前一刻踩煞车,导致上线延期,将会产生什么影响。而工程师呢,则是从转换(transition)、错误状态思考,设想各种使用者可能碰上的极端难题,防患未然。

5. 工程师是你最好的朋友

设计,关乎「关系(relationship)」。元素之间的关系是视觉层次,萤幕之间的关系是流程,使用者与产品之间的关系、最终极的,当属人与人之间的关系⋯⋯每个产品的每个核心都表明着设计师与工程师的关系。关系是每个新创公司赖以生存的根基——每个点子、每种设计、每次落实。归根结底,是工程师让我们的天马行空成了真实,少了他们,模型图(mockup)的细节纵使再怎么精细雕琢,终究仍然只是,一只模型图,而不是货真价实的产品。如果你有能耐,引导那些设计门外汉对你的设计惊叹不已,非常乐于将你的设计付诸实践,一切都会进行得更加顺利。试着认知工程师可能面对的技术限制,并且说明某个设计的来龙去脉,方便他们思考如何编写代码,假如未来有任何变动,调整起来会比较轻松。

6. 学习「偷得巧妙」

「好的设计师模彷,伟大的设计师盗窃」。剖析其他产品何以打动人心,仔细推敲他们做得好的地方以及原因,并且思考如何把这些产品的优点移植到你的设计之中,能够大大丰富你的作品库(repertoire)。被盛赞为伟大与新颖的设计,其实往往应用了其他领域的概念。当然,你当避免直接粗暴的拷贝其他人的视觉风格,但是找到产品之所以运作出色的元素,例如 UX 原则和互动形式,轮到自己创作时会发挥得更好。

7. 设计宛如弹奏钢琴

Google Ventrures 设计合伙人 Braden Kowitz 把设计类比成弹钢琴,我深感共鸣。我们可以阅读所有音乐理论,聆听所有乐曲的每个音符,然而,若非经过上千小时的练习,你永远无法成为一名在舞台上光芒四射的钢琴明星。同样的,我们可以阅读设计理论、把玩几百种产品、解构使用者经验以塑造并提升品味,但是亲自实作,是当一名设计师无可取代的关键。我们进入设计领域,是因我们拥有非凡的品味,但是最艰难也最令人困惑的部分是,在跨出第一步时,你会发觉「自己能够做到的」以及「自己认为的好设计」之间有道鸿沟,消弭两者落差唯一的方法,努力工作,彻夜匪懈的努力。

8. 美丽并非首要目标

设计与艺术不同,设计的主要目的在于解决问题,美学只是其次。两者也许相关,但是艺术家并不必然能够成为一名出色的设计师,倘若拥有艺术才华,利用它让你的设计更好,而非试图以它定义你的设计。

9. 苛求细节

魔鬼藏在细节里,谈到细节时,宁可吹毛求疵,最忌粗枝大叶。如果你没遇过任何一个工程师嘲笑你对小至像素的次次苛求,那就表示也许你该付出多点心力。

10. 没有「完成」这回事

也许我们都曾碰过设计还没臻至满意就得问世的情况,但不要太在意。因为未来未来一直来,马上便会进入不断反覆迭代的过程,没有任何东西可以宣告「完成」。这并不表示我们可以牺牲品质,比较好的方式是,推出已经达到标准的部分,而非虽然一次通通出笼,却处处都是无法妥协的瑕疵。

(一)hibernate 优化笔记:基础

$
0
0

前言:本文适合对hibernate有一定了解的人,未了解hibernate的读者可能会有点困难。众所周知,hibernate是个十分强大的ORM框架,然而越强大的东西规则就越多,hibernate也是,hibernate用得好那就是如虎添翼,用的不好会严重拖累系统性能,还不如直接用java的JDBC编程。我的博客主要写的是我在学习hibernate的过程中学习到的优化建议方法。将持续改进和更新。有一本畅销书《精通hibernate:java持久化对象技术详解》,写的非常好,本文章是个人的读书笔记。

一.基础优化建议

1.id一般都是用Long型。

 

2.包装类优先:由于在数据库中存在许多null值,在插入数据的时候也会有如果有某字段没有赋值就会默认为空,既然数据库支持,那hibernate也应该支持,所以一般在使用hibernate传参入到数据库的时候都使用包装类,因为包装类允许null值。典型的例如:session.get(Cunstom.class,new Long(1)),除此之外,类里面的属性定义都应该是用包装类类定义,比如使用Integer price;而不是int price。

 

3.访问类属性策略:

<property name=”name” column=”NAME” access=”field”/>

 

中配置access=”field”之后,hibernate就会直接访问该实例的name属性,而不是调用该方法。( 需要注意的是,hibernate是通过反射访问属性的,所以不论变量的修饰符是public还是private,hibernate都能访问)。access的另一个值是property,默认值,一般不用配置,表示hibernate通过市里的setXXX和GetXXX来访问属性。

 

4.派生属性:

<property name=”totalPrice” formula=”(select sum(0.price) from ORDERS o where o.CUSTEMER_ID=ID)”/>

在查询customer对象时,select语句会包含以上用于计算派生属性的子查询语句:

select ID,NAME,SEX,`CUSTOMER DESCRIPTION`,( select sum(0.price) from ORDERS o where o.CUSTEMER_ID=1) from CUSTOMERS。

 

(ps:上面这个“`CUSTOMER DESCRIPTION` “符号是引用标示符,如果字段名中包含空格或者特殊字符那么就需要使用这个引用标示符)

 

5.property的映射属性:

   insert属性:如果为false表示该字段永远不能被插入,默认为true;

   update属性:如果为false表示该字段永远不能被更新,默认为true;

 class的映射属性:

   dynamic-insert属性:如果为true,表示每当保存一个对象时,会动态生成insert语句,insert语句仅包含所有取值不为null的字段,默认值false.

   dynamic-update 属性:如果为true,表示每当更新一个对象时,会动态生成update语句,在update语句中仅包含所有取值需要更新的字段。

Tip:一般建议把dynamic-insert属性和dynamic-update 属性设置为true,这样可以节省数据库sql查询时的系统开销。

 

6.比较对象是否相等:

先看如下代码:

Customer c1=new Customer(“Tom”);
Customer c2=new Customer(“Tome”);
Cusomer c3=c1;

 

 如果打印”c1==c2”或者”c1.equals(c2)”结果都是false,这样应该是不对的,他俩应该是相等的,所以我们建议在类中重写equals方法以方便比较两个对象是否相等。如下:

public Boolean equals(Object o){
    if(this == o) return true;
    if(!(o instanceof CustomerId)) return false;
    final CustomerId other = (CustomerId) o;
    if(!this.getName.equals(other.getName()) return false;
    if(!companyId.equals(other.getCompanyId())) return false;
    return true;
}

 

 

  7.hibernate用OID来区分对象,该OID实际是关系映射文件中的id项,如下:

<id name=”MemoId” type=”Long” column=”ID”><generator class=”increament”/></id>

 

 

  8.hibernate的标示符生成器:

increament (常用): 由hibernate 自动以递增的方式生产标识符,每次增量为1;

identity:由数据库底层生产标识符;

sequence:由底层的序列来生产标识符,注意少数数据库可能不支持,例如mysql;

hilo:hibernate根据high/low算法来生成标识符;

native: 根据底层数据库对自动生成标识符的支持能力,来选择identity,sequence,hilo;

uuid.hex: hibernate采用128位UUID来生成算法标识符,UUID能够在网络环境中生成唯一的字符串标识符,但占用太多空间,一般不推荐;

assigned:自然主键,由java生成。一般不推荐;

 

foreign:用另一个关联的对象的标识符来作为当前对象的标识符,主要适用于一对一关联的场合。

 

二.hibernate的映射:一对多关联关系



已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



ZooKeeper-- 管理分布式环境中的数据

$
0
0

1.随着分布式应用的不断深入,需要对集群管理逐步透明化。监控集群和作业状态;可以充分的利用ZK的独有特性,熟悉程度决定应用高度


2.Service端具有fast fail特性,非常健壮,无单点,不超过半数Server挂掉不会影响提供服务


3.zookeeper名字空间由节点znode构成,其组织方式类似于文件系统, 其各个节点相当于目录和文件,通 过路径作为唯一标示。与文件系统不同的是,每个节点具有与之对用的数据内容,同时也可以具有子节点


4.ZK用于存储协调数据,如状态、配置、位置信息等。每个节点存储的数据量很小KB级别

 

5.节点维护一个状态stat结构(包括数据变化的版本号、ACL变化、时间戳),以允许缓存验证与协调更新。每当节点数据内容改变,多一个版本号类似Hbase。客户端获取数据的同时也会获取数据版本号,节点的数据内容以原子方式读写。节点具有一个访问控制列表来约束访问操作,即具有权限控制

 

6.Watches:
Zk对Node的CRUD都可以触发监听
watch事件是一次性触发器,当wacht监视的数据发生变化,通知设置了该watch的clietn,即wacther

watch事件是异步发送至观察者

wacth是一次性触发的并且在获取watch事件和设置新watch事件之间有延迟,所以有可能不能可靠的观察到节点的每一次变化

客户端监视一个节点,总是先获取watch事件再发现节点的数据变化

watch事件的顺序对应于ZK服务所见的数据更新的顺序

 

7.ZK在hadoop平台上的典型应用


storm集群:Zk作为nimbus(master)和supervisor(slave)的中间枢纽,保存strom集群和作业的所有信息。并负责nimbus和supervisor的全部通信
Hbase集群:Zk作为协调器,为hbase提供了稳定服务和failover机制,HRegionServer也会把自己以Ephemeral(临时节点)方式注入到ZK中,使得Hmaster可以随时感知到各个HRegionServer的健康状态(可用于监控RegionServer)此外Zk也避免了HMaster的单点问题

应用三大块:
strom应用开发,storm集群监控
MR应用开发
HBase应用开发

 

8.流行的场景应用:
分布式配置管理:
分布式订阅即所谓的配置管理,顾名思义就是将数据发布到ZK节点上,共订阅者动态的获取数据,实现配置信息的集中式管理和动态更新,例如全局的配置信息,地址列表等就非常适合使用

NameService
这个主要是作为分布式命名的服务,通过调用Zk的create node api,能够很容易的创建一个全局唯一的path,这个path就可以作为一个名称

分布式通知/协调
Zk中特有的watcher注册与异步通知机制,能够很好的实现分布式环境下不同系统之间的通知于协调,实现对数据变更的实时处理。
使用方法通常是不同系统都对ZK上同一个znode进行watch,监听znode的变化(包括znode本身内容及子节点)其中一个系统update了znode那么另一个系统能够收到通知,并作出相应处理

分布式锁
这个主要得益于ZK为我们保证了数据的强一致性,即用户只要相信每时每刻,ZK集群中任意节点上的相同znode的数据时一定相同的。锁服务可以分为两大类:1.保持独占 2.控制时序

Hbase Master选举是ZK经典使用场景


   Znode

Znode    Znode维护着数据、ACL(access control list,访问控制列表) 、时间戳等交换版本号等数据结构,它通过对这些数据的管理来让缓存生效并且令协调更新。每当Znode中的数据更新后它所维护的版本号将增加,这非常类似于数据库中计数器时间戳的操作方式。

另外Znode还具有原子性操作的特点:命名空间中,每一个Znode的数据将被原子地读写。读操作将读取与Znode相关的所有数据,写操作将替换掉所有的数据。除此之外,每一个节点都有一个访问控制列表,这个访问控制列表规定了用户操作的权限。

    ZooKeeper中同样存在临时节点。这些节点与session同时存在,当session生命周期结束,这些临时节点也将被删除。临时节点在某些场合也发挥着非常重要的作用

 

     Watch机制

 

    Watch机制就和单词本身的意思一样,看。看什么?具体来讲就是某一个或者一些Znode的变化。官方给出的定义:一个Watch事件是一个一次性的触发器,当被设置了Watch的数据发生了改变的时候,则服务器将这个改变发送给设置了Watch的客户端,以便通知它们。

Watch机制主要有以下三个特点:

  1 一次性的触发器(one-time trigger)

    当数据改变的时候,那么一个Watch事件会产生并且被发送到客户端中。但是客户端只会收到一次这样的通知,如果以后这个数据再次发生改变的时候,之前设置Watch的客户端将不会再次收到改变的通知,因为Watch机制规定了它是一个一次性的触发器。

  2 发送给客户端

    这个表明了Watch的通知事件是从服务器发送给客户端的,是异步的,这就表明不同的客户端收到的Watch的时间可能不同,但是ZooKeeper有保证:当一个客户端在看到Watch事件之前是不会看到结点数据的变化的。例如:A=3,此时在上面设置了一次Watch,如果A突然变成4了,那么客户端会先收到Watch事件的通知,然后才会看到A=4。

  3被设置Watch的数据

    这表明了一个结点可以变换的不同方式。一个Znode变化方式有两种,结点本身数据的变化以及结点孩子的变化。因此Watch也可以设置为这个Znode的结点数据,当然也可以设置为Znode结点孩子。

 

     使用API来访问ZooKeeper

    API访问ZooKeeper才是客户端主要的使用手段,通过在客户端编写丰富多彩的程序,来达到对ZooKeeper的利用。这里给出一个简单的例子:(深入的还没能力给出啊,例子是从网上找的很清晰明了)

 

1. import java.io.IOException;
2.
3. import org.apache.zookeeper.CreateMode;
4. import org.apache.zookeeper.KeeperException;
5. import org.apache.zookeeper.Watcher;
6. import org.apache.zookeeper.ZooDefs.Ids;
7. import org.apache.zookeeper.ZooKeeper;
8.
9. public class demo {
10.     // 会话超时时间,设置为与系统默认时间一致
11.     private static final int SESSION_TIMEOUT=30000;
12.    
13.     // 创建 ZooKeeper 实例
14.     ZooKeeper zk;
15.    
16.     // 创建 Watcher 实例
17.     Watcher wh=new Watcher(){
18.            public void process(org.apache.zookeeper.WatchedEvent event)
19.            {
20.                    System.out.println(event.toString());
21.            }
22.     };
23.    
24.     // 初始化 ZooKeeper 实例
25.     private void createZKInstance() throws IOException
26.     {             
27.            zk=new ZooKeeper("localhost:2181",demo.SESSION_TIMEOUT,this.wh);
28.           
29.     }
30.    
31.     private void ZKOperations() throws IOException,InterruptedException,KeeperException
32.     {
33.            System.out.println("\n1. 创建 ZooKeeper 节点 (znode : zoo2, 数据: myData2 ,权限: OPEN_ACL_UNSAFE ,节点类型: Persistent");
34.            zk.create("/zoo2","myData2".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
35.           
36.            System.out.println("\n2. 查看是否创建成功: ");
37.            System.out.println(new String(zk.getData("/zoo2",false,null)));
38.                           
39.            System.out.println("\n3. 修改节点数据 ");
40.            zk.setData("/zoo2", "shenlan211314".getBytes(), -1);
41.           
42.            System.out.println("\n4. 查看是否修改成功: ");
43.            System.out.println(new String(zk.getData("/zoo2", false, null)));
44.                           
45.            System.out.println("\n5. 删除节点 ");
46.            zk.delete("/zoo2", -1);
47.           
48.            System.out.println("\n6. 查看节点是否被删除: ");
49.            System.out.println(" 节点状态: ["+zk.exists("/zoo2", false)+"]");
50.     }
51.    
52.     private void ZKClose() throws  InterruptedException
53.     {
54.            zk.close();
55.     }
56.    
57.     public static void main(String[] args) throws IOException,InterruptedException,KeeperException {
58.            demo dm=new demo();
59.            dm.createZKInstance( );
60.            dm.ZKOperations();
61.            dm.ZKClose();
62.     }
63.}

 

 

 

此类包含两个主要的 ZooKeeper 函数,分别为 createZKInstance ()和 ZKOperations ()。其中 createZKInstance ()函数负责对 ZooKeeper 实例 zk 进行初始化。 ZooKeeper 类有两个构造函数,我们这里使用  “ ZooKeeper ( String connectString, , int sessionTimeout, , Watcher watcher )”对其进行初始化。因此,我们需要提供初始化所需的,连接字符串信息,会话超时时间,以及一个 watcher 实例。 17 行到 23 行代码,是程序所构造的一个 watcher 实例,它能够输出所发生的事件。

 

    ZKOperations ()函数是我们所定义的对节点的一系列操作。它包括:创建 ZooKeeper 节点( 33 行到 34 行代码)、查看节点( 36 行到 37 行代码)、修改节点数据( 39 行到 40 行代码)、查看修改后节点数据( 42 行到 43 行代码)、删除节点( 45 行到 46 行代码)、查看节点是否存在( 48 行到 49 行代码)。另外,需要注意的是:在创建节点的时候,需要提供节点的名称、数据、权限以及节点类型。此外,使用 exists 函数时,如果节点不存在将返回一

 

个 null 值。

 



已有 0人发表留言,猛击->> 这里<<-参与讨论


ITeye推荐



敏捷

$
0
0

对于敏捷开发,我前面其实已经有很多文章提到了,再次强调下敏捷的核心思想个人理解为三个重要的方面。其一是需求的条目化并以需求点进行的全程追踪和跟踪;其二是短周期迭代;其三是基于持续集成思想的进度和质量可视化。

 

对于敏捷开发本身,对于很多内容我仍然坚持自己的观点,具体如下:

 

对于大型全新系统的开发,如果是以底层数据为核心的业务系统,则不能单纯的应用敏捷开发。这类系统对全局业务建模和数据建模的要求会更高,以保证架构完整性和概念一致性。而不是任务已经并行分配下去,出现问题了再去做调整,敏捷的短周期迭代不是做这个用的。这类的总体设计个人理解主要包括了子系统或模块的划分,接口的识别,底层全局数据概念模型,这些必须一开始就要搞清楚。

 

对于新组建的团队,团队成员相互不了解或能力差异过大,团队没有历史项目实践的磨合和经验积累,没有比较成熟稳定的技术框架时候,建议慎用敏捷开发。敏捷开发是迭代计划和版本,但是当前的迭代版本仍然是需要我们能够做出合理的估算,而不是存在大量的不确定性。

 

敏捷开发里面有一个重要的实践,即CI持续集成,这里面会涉及到单元测试,但是这不是XP极限编程里面的TDD测试驱动开发。有人认为没有采用TDD就不是敏捷开发是相当教条型的错误。即使再CI持续集成和每日构建,冒烟里面我们仍然是多种做法。一种是只写能够冒烟测试通过的少量单元测试用例,一种是只对按界面展现和逻辑实现横向分工的团队要求对于技术组件接口的朝外提供要首先写单元测试代码。TDD测试驱动开发真正能够实践好能够坚持下来的多内基本很少,这个根本就不是熟悉了TDD就能降低工作量的问题,其次对于希望通过写测试代码来想清楚需求的方法不推荐,需求是需要可验证但是不代表必须测试代码能够写清楚需求才可验证;再次单元测试往往比较难到UI和展现层,即使有Junit自动跑了还是需要人工测试,这个工作量并没有省。

 

敏捷方法论本身的思想是重视沟通和协同,减少不必要的文档,因此敏捷并不是没有文档。当前还是很多人认为通过实施敏捷方法可以不写文档,认为文档没有用处这又是走到一个极端。那么什么叫不必要的文档?个人理解其一已经在项目团队里面形成规约性质的内容,则已经有历史规约可以追溯到;其二是各种日常沟通协调中形成的讨论,记录,白板等内容,不会太注重规范格式但是要能够记录下来;其三是对于他人看你的源代码就能够理解清楚的东西不必再文档化。

 

想到哪里就做到哪里,拿着需求点就马上去做,出现问题了不断的返工和修改还美其名曰重构,通过敏捷为幌子来逃避写文档,虽然第一个迭代快速能出来但是产品能够真正上线运行进度周期反而成倍增加,再者或强调我们是敏捷每周40小时工作时间。这些都是中敏捷的毒太深,还是那句话,传统的类似瀑布的软件生命周期模型都没有应用好,能够把敏捷应用好是不可能的。团队人员本身编程能力和经验就差距较大,对自我能力和生产率评估也很弱,相互也不了解情况下能够简单的通过敏捷来纠正这些问题也是不可能的。


  青春就应该这样绽放   游戏测试:三国时期谁是你最好的兄弟!!   你不得不信的星座秘密
Viewing all 15845 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>