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

网络监控平台Shinken

$
0
0

Shinken是一个网络监控平台,可以通过一系列直观的方式监控网络内的各种健康状况。Shinken,单单这个名字接近于日语发音的“新建”,Shinken脱胎于Nagios,其实Shinken这个项目本身就是一帮Nagios项目的人无法忍受Nagios,自己跳出来重新用Python重构了一下——较低的版本甚至完全兼容Nagios的配置文件。

要吐漕的是Litrin在尝试安装的时候用了N个版本,0.x的根本找不到文档;1.x的文档很全,插件兼容性有问题;2.x文档有,插件全,就是明显的有bug。只能自 己在github上fork之后提交补丁——好在当天就被采纳了。不过话说这也是开源项目的一个常态,一个项目一旦做到差不多,团队很快就会因为产品定义的不同出现分歧,然后一帮人就fork代码搞个新项目,最终的结果就是“一堆类似功能的项目,多的挑花眼却没有一个是完美的。”

安装前先简单了解下Shinken的架构,相比Shinken借鉴的Nagios,这个明显要复杂很多。

  • 多种角色:不同于传统C/S架构,应该是出于分布式的考虑。Shinken的结构真的有些变态了。
    1. Arbiter(仲裁): Arbiter节点读取本地的配置,然后将配置切分之后分发到多个合适的schedulers节点。
    2. Scheduler(调度): scheduler节点负责分别管理poller和reactionner节点的任务调度。 
    3. Poller(轮询): poller节点通过各类插件执行scheduler节点的任务,获取各种健康指标。
    4. Reactionner(响应): reactionner 节点的任务是一旦满足要求将触发event_handlers机制(比如发送通知等)。
    5. Broker(中间人): broker节点的任务真的是中间人——导出和管理scheduler节点中的数据。
    6. Receiver (接收人): 可选节点,在某些特定场景下可以通过reciver节点汇总数据(比如汇总私网内部数据,统一转发)。
  • 除了Arbiter节点之外,任何的节点都可以不是唯一的。节点之间的关系也都是多对多的。
  • 每一个节点都支持/依赖插件,或者说Shinken本身只是一个插件的框架而已。
  • 保障性能和可靠性——根据CAP法则,放弃了一致性。

Shinken architecture   说了这么多的理论,开始动手吧! 这次终于使用了Ubuntu1404的Server版。前边也介绍过,N多的版本都不完善,这里只能采用Ubuntu的apt方法来安装。这里为了省去前面的6种节点角色的复杂,只用“主控”和“受控”两种角色粗暴的示范安装过程。

主控端操作

#apt-get install shinken

看看哪些包被安装了

root@ubuntu14:~# dpkg -l | grep shinken
rc shinken 1.4-2 amd64 Flexible monitoring tool - Meta-package
ii shinken-common 1.4-2 amd64 Flexible monitoring tool - Common files
ii shinken-module-broker-webui 1.4-2 amd64 Shinken WebUI broker module
ii shinken-module-broker-webui-cfgpassword 1.4-2 amd64 Shinken cfg_password authentifcation module for WebUI broker
ii shinken-module-broker-webui-sqlitedb 1.4-2 amd64 Shinken Sqlite storage module for WebUI broker
ii shinken-module-retention-picklefile 1.4-2 amd64 Retention module for Arbiter, Scheduler or Broker

安装结束后,正常情况下,在你的/etc/init.d目录下将会有一系列以shinken开头的脚本。这个时候,如果你简单粗暴的server shinken start的话肯定是一堆的报错等着你。好吧,这个问题我找了很久才发现。 编辑/etc/default/shinken,将第34行修改为:

BIN=/usr/lib/python2.7/dist-packages/shinken/bin

这个时候再server shinken start应该会成功。其实shinken start的脚本是启动所有的关联的服务,你可以通过增加或删除/etc/default/shinken 配置中的AVAIL_MODULES选项起到变更角色的目的。 全部OK之后,你可以通过浏览器访问主节点7767端口看到一个Dashboard。不过目前仅仅只是监控本地的健康状况而已。 Shinken_dashboard下面就假定主控节点监控另一台主机nfs的网络连通状况 vi /etc/shinken/hosts/nfs.cfg

define host{
    use linux
    address 10.239.21.24 
    host_name nfs
}
define service{
    use ssh ; Name of service template to use

    host_name nfs
    service_description SSH check
    retry_interval 1
    check_interval 5
    max_check_attempts 2
   check_command check_ssh
   notifications_enabled 0
}

重起shinken之后就会看到一个对NFS主机SSH端口的监控。

如果你只需要拿到远端主机ping状态,TCP端口之类简单的几个指标的话,这种模式已经足够了,可如果需要知道远端主机的进程数量、磁盘空间等数据,那就需要在被控端上做文章。这里就简单的介绍下通过被控端上安装poller的方式实现。

被控端操作

开始都差不多,照贴

#apt-get install shinken

编辑/etc/default/shinken,将第34行修改为:

BIN=/usr/lib/python2.7/dist-packages/shinken/bin

由于被控端只需要一个poller即可,可以关闭其他服务,修改39行

AVAIL_MODULES="poller"

启动shinken:

root@ubuntu14:/etc/shinken/hosts# service shinken start
Starting poller:
 ...done.

启动列表确实短了很多

回到主控端操作

vi /etc/shinken/hosts/test.cfg,添加被控端指标

define host{
use linux
host_name test
address 10.239.21.49 #被控端IP
}

define service{

         use local-service ; Name of service template to use
         host_name test
         service_description PING
         check_command check_ping!100.0,20%!500.0,60%
}

define service{
         use local-service ; Name of service template to use
         host_name test
         service_description Root Partition
         check_command check_local_disk!20%!10%!/
       }
define service{
        use                             local-service         ; Name of service template to use
        host_name                       test
        service_description             Total Processes
        check_command                   check_local_procs!250!400!RSZDT
        }

vi /etc/shinken/shinken-specific/poller.cfg,追加一个新的poller

define poller {
    poller_name     poller-test  #poller名称
    address         10.239.21.49 #被控端IP
    port            7771         #端口,默认就是7771

    ## Optional
    manage_sub_realms   0   ; Does it take jobs from schedulers of sub-Realms?
    min_workers         0   ; Starts with N processes (0 = 1 per CPU)
    max_workers         0   ; No more than N processes (0 = 1 per CPU)
    processes_by_worker 256 ; Each worker manages N checks
    polling_interval    1   ; Get jobs from schedulers each N minutes
    timeout             3   ; Ping timeout
    data_timeout        120 ; Data send timeout
    max_check_attempts  3   ; If ping fails N or more, then the node is dead
    check_interval      60  ; Ping node every N seconds

    ## Interesting modules that can be used:
    # - NrpeBooster     = Replaces the check_nrpe binary. Therefore it
    #                       enhances performances when there are lot of NRPE
    #                       calls.
    # - CommandFile     = Allow the poller to read a nagios.cmd named pipe.
    #                       This permits the use of distributed check_mk checks
    #                       should you desire it.
    # - SnmpBooster     = Snmp bulk polling module
    #modules     NrpeBooster, CommandFile
    modules

    ## Advanced Features
    #passive         0       ; For DMZ monitoring, set to 1 so the connections
                            ; will be from scheduler -> poller.
    #poller_tags     None
    realm   All
}

重起主控端shinken服务,配置生效后,你会在webUI的’All’选项中发现新增test主机的各项指标。


十项将彻底改变你生活的新技术

$
0
0

十项将彻底改变你生活的新技术

技术的进步让你的生活与众不同

作者:亚当·牛津

保持对个人电脑和信息技术发展的全面了解对于一般人来说几乎是不可能的,但是下面介绍的十项技术你最应该了解,因为这些技术将最大限度的改变你的生活。

1.三维游戏

事实上带上一副特制的太阳镜就能从二维屏幕上看到各种各样的三维图像,更糟糕的是所谓的三维游戏并不如多点触摸以及自然用户界面的游戏更具说服力,尽管两者几乎是在同一时间商品化的。

目前一款采用三维显示的宏基Aspire 5738笔记本电脑大约售价550英镑,虽然取消了部分尖端技术,但是该机型添加了对任何DirectX 9游戏的支持新功能听起来还是不错的。屏幕为偏振过滤类型,它是额外维度的新准则。

通过使用色彩过滤将一副图像切分成两个-一只眼看一副图-垂直像素列在左右图像中透过一片偏振片交替呈现。一副具有相反偏光镜片的墨镜可以保证每只眼睛只能看到一副图像。三维技术给游戏带来的不同是可想见的,就像魔兽世界在低端图形硬件处理器运行之下看起来难以接受。

不过真正推动三维技术发展的动力来自于功能不断更新的电视领域,因为液晶电视的供应商不断地提高人们在休息室观看超现实电影的要求。相对于这里谈到的其他技术而言,虽然三维技术要求观众做出很大的努力(尤其那些讨厌戴眼镜的人而言),毕竟我们中的大多数人还是非常懒惰的;因此正当蓝光技术以及更高的音质解决标准辗转挣扎时,Mp3和标准清晰电影已经无处不在了。我们每次对于技术便捷性的评价往往高于技术质量本身。对于钟爱三维游戏的人而言,三维技术实际上并不游戏的开发商和出版商作任何工作,因为立体图像的展现是靠驱动水平来实现的。另一方面,这就意味着在鼓励大家采用三维技术这件事上游戏的开发人员和销售人员并没有起到应有的巨大推动作用。

2.流游戏

超高速宽带技术的进步不仅仅对于快速下载的游戏的原因起到作用。宽带对于流游戏的未来产生微小的影响,至少理论上是这样。

有几家公司正在追求一种理念,即某天,你珍贵的个人电脑几乎完全像游戏机一样多余,这些公司为这一理念投入了一笔相当可观的钱。

这个概念很简单:所有的游戏数据存放在一个中央服务器上,你所要做的只是接收显示和发送返回你输入的命令。它有点像大型多人在线角色扮演游戏中使用的技术,但渲染引擎不在你的个人电脑上,它实际上是将核心信息储存在同一个服务器上。

这个想法在几年以前就在幻影平台上酝酿而生,但从未推广到市场。它看起来不像OnLive网( www.onlive.com),Gaikai(一种通过浏览器在线玩游戏的技术)和微软自己的流工程将结束,尽管人们更多的关注输入的滞后:每次按下一个键都会出现延迟。信号已经发出几百英里了,人物才开始移动。

支持者声称即使是第一人称射击游戏也会出现游戏画面的抽搐,但我们对此更加怀疑。另外一个原因是至少在不久将来这些服务中的一个可能会被落实,这些将是游戏开发商的既得利益。

因为没有内容存储在你的机器里,当然,这样一来你就不可能剽窃流游戏的内容,这对于他们来说是一个极具吸引力的主张。不过在不久的将来,它更像是一种技术,如同运行Quake Live游戏那样,借助一些地方处理力量以及一些基于服务器的循环组合。这当然是微软采取的路线,看起来比现阶段依靠云技术更容易实现。

3.六核处理器

你不必为此等待很长时间。英特尔公司的Westmere处理器可能此时正徘徊在处理器工业的渣滓中,将集成了图像群的芯片嵌入到处理器中,但是他们希望成长和高速度。

有时,在未来数月英特尔公司将推出优于时下四核处理器的更高端的酷睿 i7 六核处理器版本。基于现有的Nehalem架构,它的首要特点是采用了32纳米的制造工艺,而其余的规格表功能大致相同。这可能是真正意义的升级。

CPU

游戏程序员越来越善于在开发中使用多线程代码,像大部分游戏中使用的,比如帝国:全面战争及即将上映的拿破仑续集,当加入额外内核时你将看到更高性能的提升,这种提升比我们看到的在结构上从双核变成四核要明显的多。

因为效益体现在核的数量上,而不是你立刻能做的提速事情上,英特尔公司正在鼓励一些开发商特别为六核处理器的用户增加额外的内容。我们最近几乎每一项技术都在许诺提高我们的帧频率,结果换来了太多的失望,我们将保留意见,直到生产出能够实现该技术的产品。

好消息是这些功能强大的16位处理器将通过一个简单的BIOS内存来兼容现在最流行的X58主板。坏消息是X58主板现在仍然价格不菲。

4.无线电源

几年钱,一个来自富尔顿创新的团队向我们展示了他们的作品eCoupled[1]。利用电磁感应原理,一个线圈里的电荷受到周边线圈的感应而被激活,疯狂的研究员们利用这一原理实现了无线电的传输。

尽管身处高电压中,他们说,这是安全,高效的,可以应用于任何表面。在这个没有插座的厨房演示室里,任何一个角落都布满了光线,一个平底锅只要放在柜台上就能对烹炸的食物进行加热。把手机放在同样的柜台上,手机就开始自动充电。显然,这就是未来。

富尔顿仍然致力于无线电源的研究,但是它是一个与众不同的公司,曾经击败很多商店, Powermat -其产品取代了五十便士的电源插头但却很昂贵。

好消息是,今年晚些时候无线电联盟将要完成无线电源标准“Qi”的制定。这将意味着有关产品价格的下降,制造商们有信心建立直接接入设备的技术,而不是需要一个适配器。

如果你认为这一定是疯了,那么,看看美国广播公司推出的Airnergy。这是一个很小的软件狗,可以把Wi – Fi信号转化为电能为电话电池充电等。

5.无线显示器

最后两个显示器标准,HDMI和DisplayPort,他们的出现并没有使我们疯狂到为其更新我们的电脑显示屏和图形卡。所以,可以肯定的打个赌,DVI接口仍是未来一段时间选择电缆连接的接口。那么没有线时我们用什么来连接电脑和显示器?

这一点值得遭到炮击。在CES【2】的站台上将会出现两种不同的技术,并且有可能在今年进行整合。

第一,WirelessHD作为HDMI的替代品,靠通常的有线电视和DVD播放器的制造商推动。它在超宽带(UWB)频谱下利用一种短距离,高带宽的方式,通过机顶盒或者媒体中心将高清音频和视频信号传输到电视屏幕上去。

这个想法并不新鲜,飞利浦有一个工具集在一段时间里做着同样的事情,但WirelessHD是一个适当的标准,并应确保制造商A的电视产品能够很好地兼容制造商B的蓝光机等。

但是,也许和我们更相关的是英特尔公司的新无线显示,或者叫做WiDi。它是专门为笔记本电脑设计的,当你需要对接一个合适的外接显示器时,它可以消除电缆带来的麻烦,就像WirelessHD将视频信号发送到接收盒一样。

不像WirelessHD,WiDi无法处理受保护的内容以及一些相关的内容,但它要简单得多,因为它无需再笔记本电脑添加新的硬件。WiDi是处在现有Wi – Fi芯片上的一个软件层,而不是使用一个单独的发射机,因此它的生产费更加低廉。考虑到引入图片时刷新速率没有延迟,使得它在未来可能是一个杀手。
6.OLED显示器

是的,你可能了解到。下一年,另一个承诺,OLED屏幕将要接管一切。我们也许以前没有听说过这些?但是这次可能是真的。

谷歌的Nexus手机刚刚推出的OLED屏幕,平静的说,对于所有账户来说它使谷歌手机相比iPhone更可取。鲜艳的颜色,更清晰的解决方式,黑白色更纯厚,为什么OLED技术如此有优势?

简单的说,OLED面板的每一个像素点都可以发出自己的光,而不是过滤来自屏幕后面的白色或者蓝色灯光。你不用从验光师的角度评判它的优点,但可以肯定的是生产费用相当昂贵。

不过,OLED屏比背光屏更加轻薄,原因是很明显的,尽管年底时我们还可能还无法使用OLED显示屏,然而技术更新让我们在笔记本上找到了很多替代方式。

7.超高速宽带

对于超高速宽带有两方面需要引起你的关注,第一要看大选前夕数字英国报告是否能够将罢工政策、暴力侵犯隐私、对带宽收取额外费用写入法律。

第二要看你的交流方式正在发生什么样的改变,截止到明年年初,我们中百分之七十五的人应该能够通过光纤连接到互联网的电话进行交流。这是英国BT公司21世纪网络工程计划的一部分。该工程为了适应21世纪的要求将取代全部的铜线电话以及单一以太网作为基础的互联网基础设施。

到目前为止、它一直因为种种问题而被拖延无法实施,但是最终还是会迎头赶上,此时互联网服务供应商在全国范围内对其进行测试。这个想法的实现会增加对高带宽的竞争,同时降低价格,以及带来如IPTV的服务,这类服务原来只能被原始客户独享,现在将面向所有人。

这并不意味着我们能够更容易的下载到大文件的游戏,降低原有的ping次数。我们最大的希望是通过这种方式来鼓励电话公司最终取消每月12英镑的电话线租用费,对于我们来说实际是没有使用的。

8.增强现实

其实我们一直再为这个问题与我们自己开玩笑,增强现实:能够通过实时视频覆盖世界上的所有信息的能力,听上去很酷,这也就是我们为什么喜欢诸如yelp这样的iphone应用程序,它通过点击地图上的大致位置,就能在细节和距离上将你拉近到最近的酒吧,了解最新的消息。

当你握着手机在你脸前三英尺出来回走动时,你是否感觉到保持这样的姿势有点可笑。也许它就像免提和蓝牙耳机一样。不久前,如果有人打电话不用将手机贴近耳朵,那么会有人窃笑。也是在不久之前,手机本身是为那些不善交际的销售怪胎设计的。

看着你周围的人举着手机,通过个人动态GPS系统找寻美食或酒吧,亦或是查看周围人的最新近况,附近建筑物的有趣见闻。这些在几年的时间里,可能是世界上最自然不过的事情了。现在确实也成为了现实。

Twitter 360 是一个iPhone的应用程序,指导你地理标注你的朋友列表。同时TAT( www.tat.se)公司正在致力于增强身份证项目的开发,未来如果人们在你的头像上开一个摄像机,你社会反馈来的各种信息将浮现在你的头像上。了解你变得很容易,但听上去有相当可怕。

9.自然用户界面

在消费电子展主题演讲上,史蒂夫鲍尔默几次提到自然用户界面(NUI),wii游戏机魔棒是一种能够方便捕捉一切可以描述出来的挥舞的手持工具,多触摸点,纳塔尔式项目健身操。

当键盘和鼠标的设计一沉不变时,廉价的笔记本和多触点的一体机屏幕的出现,让我们相信办公时台式机模式的改变离我们不远了。

例如,在美国以外,定制笔记本制造商IBuyPower已经开始销售具有多点触摸屏幕的高端游戏笔记本电脑,于此同时,法国开发商,尤金系统将win7多点触摸控制纳入到即将举行的R.U.S.E战略中。这一切都是令人激动的,除了一件事。

多点触控对于Win7来说是原生的,但是它的实现远不如IPHONE上显得平顺。PCFormat已经使用了这项技术,并没有出现触摸不精确等问题。正如NUI字头缩写描述的那样,对于使用者来说它是自然的,非强迫的,不可见的。就像应用于IPHONE上一样,window也必将实现该技术,前提是鼠标仍然更加快速准确的进行定位。

同样还有一些非常棒的设想,比如说纳塔尔项目,微软公司将全身三维姿态识别技术引入XBOX 360,这是迄今为止最雄心勃勃的原型想法,对于等待PC破解再去享受这项技术的玩家们真是件难熬的事情。

在CES展会上,来自于 Light Blue Optics (lightblueoptics.com)公司的轻触式投影机的原型机成为了展会上最吸引人的产品。它使用了一种叫做全息激光投影技术,这个微小的投影仪能将任何一个10寸的表面无论是平面还是曲面都能变成一个尖锐的多点触摸屏。

10 .长期演进技术

通过WiMAX高速,超可靠的移动宽带从一个单元塔传送到您的笔记本电脑或电话的想法不会淹死在水中,但它确实需要一个嘴对嘴的传输。

几年前,WiMAX曾经作为“下一件大事”吹捧多年,这是一段充满痛苦和创伤的潜伏期。因为已将有一些美国的运营商开始采用这种技术,事实上不少企业开始用它做点对点的通信,但是公开的接入点从开始的试验区域简少到最后几乎没有。

一部分原因在于该公司拥有几个城市的WiMAX的经营许可权,最近Freedom4被收购,新业主没有急于通过该项技术获利,更有可能的时,移动电话公司都很满意当前的HSPDA的速度以及替代技术,即4G,或长期演进(LTE)技术提供的不需要为WiMAX进行网络改造依然能够获得数量几乎相投的带宽。

生活在在斯德哥尔摩或奥斯陆幸运的斯堪的纳维亚与TeliaSonera签署了LTE的合同,同时O2今年在英国推出一个150Mbps的LTE包一段时间。虽然没有激烈的竞争,但我们并不期望的从此放弃WiMAX技术。

在美国,由于3G承载量有限,使得移动网络使用量开始跌落,而WiMAX的新架构很可能成为增加容量,以应付需求的方法。在这种情况下,我们期望看到它开始发芽,遍地开花。

更快的比特和字节

相比之前文章中提到的诸多技术,对你的电脑内部进行修订显得更加平淡,其中对于硬盘驱动器SATA标准的修订以及增加在主板上的USB 3.0加快了默认连接的外围设备。

motherboards

当今技术正在实现跨越式的飞跃,SATA III 对于内存可获得带宽增加了一倍,从理论上的3Gbps提高到6Gbps,而在学术论文中USB 3.0作为有线外设传输素的提高了10倍,从480Mbps提高到4.8Gbps 。

现在大多数厂家都会在主板上预留两种不同爱好的端口,虽然这两种技术与以前技术快了很多,但是这些技术对于PC用于的影响却没有多大。

在商业世界里毫秒就是金钱,升级产品可能意味着有所改善,但更我们更想看到的是一个能够兼容的驱动器和外设的到来。

 

注释:

【1】eCoupled是富尔顿创新公司的一项专利,是一种近场无线传输的技术。

【2】国际消费电子展

来源:http://article.yeeyan.org/view/151767/104725


© 推荐 for 互联网的那点事. | 猛击下载: iPhone客户端猛击下载: Android客户端

为什么你该找一个程序员的男友

$
0
0

一、条件好

  1. 吸金能力:挣得多。朝阳行业,同龄人里的土豪。
  2. 性格:踏实不浮夸。做技术,讲究的是长期的积累,所以能够耐得住寂寞的程序员一般性格都很踏实靠谱。
  3. 智商:非常聪明。搞IT的是最聪明的一批人。

二、忠诚度高

  1. 不会打扮,很少有花痴妹子主动投怀送抱。T恤牛仔拖鞋,随性而为,带出去或放在公司,请放100个心。
  2. 业余时间少,没时间勾搭其他妹子。每天加班够累了,很少有时间和精力去捣鼓乱七八糟的事儿。
  3. 吹牛能力较差,很多妹子无法欣赏他们的美。因为长期用机器语言与计算机打交道,所以在现实世界中很少会出现他们眉飞色舞吹牛的时刻,也就少了很多花痴妹子的膜拜眼光。

话说回来,程序媛也很靠谱,理由同上。 如果碰到长得还很漂亮的程序媛,那就娶了吧!哈哈。

附上看到的一个段子,一个程序员写的:

“老婆最近又开始抽风,说要通过控制经济大权来防二奶防小三。她一直没闹明白,她最大的优势在于比绝大多数女人讲理,有事可以简单地和她讲道理,不必动手;二是她比绝大多数女人省事,不会成天闹这个纪念日那个纪念日。找个二十多岁成天幻想各种浪漫的小三来烦我,我疯啦?有那功夫写几行代码多好。”

想第一时间看到本站更新?请订阅RSS: 花痴痴的网站 | 女程序员园地

原创文章,转载请注明:转载自 花痴痴的网站 | 女程序员园地

本文链接地址:为什么你该找一个程序员的男友

你不可不看的20个营销思维

$
0
0

当你懂得怎样在微信和微博,在不同的时间段发不同(相同)的内容,然后都可以获得最多的点赞、评论,你就真的懂怎样做社会化的传播了。你会好好利用微博群、微信群、朋友圈、意见领袖的群……吗?社会化传播不是只有一条公式的!要懂内容分流、懂扩散策略、懂掌握时机!
333333

1. #社会化营销#当你懂得怎样在微信和微博,在不同的时间段发不同(相同)的内容,然后都可以获得最多的点赞、评论,你就真的懂怎样做社会化的传播了。你会好好利用微博群、微信群、朋友圈、意见领袖的群。。吗?社会化传播不是只有一条公式的!要懂内容分流、懂扩散策略、懂掌握时机!

2. #社会化营销#有好的内容,懂得利用微博的功能跟用户互动,可以产生不错的营销效果。微博的弱势,是大部分用户都不愿意以真实身份分享内容,社交功能被微信胜过了。微信呢?大家都知道谁是好友,分享必然有回应,口碑可靠,但是传播力就输给微博。要懂这些基本属性,不能老说微博输给微信!

3. #营销#永远不变的智慧:满意的顾客永远就是最好的推广媒体。(Thebest advertising is done by satisfied customers.) 社会化媒体能够让满意的顾客帮助迅速传播,力度惊人,这是传统媒体怎样也及不上的。反过来说,不满意的顾客也可以把品牌毫不留情的破坏。今天品牌不懂做社会化营销,输了一半!

4. 移动营销是不是不可忽视?问一下自己和身边的人,每天花多少时间玩手机就知道了。

5. #营销#在飞机上看了《乔布斯》,电影一般但是对白算是忠于原著。其中让我最深刻的一句话是:“我们不是要比竞争对手做得更好,我们是要比他们做得不一样。“(Notbetter, but different.) 人家做什么自己就做什么的企业没有持续竞争力,只有不断创新的企业才会脱颖而出,才会真正伟大!

6. #社会化营销#一切的营销,其实都是针对满足人性的各种需求、焦虑和欲望而做的:冲动、贪婪、功能、满足、炫耀、自豪、面子等等,所以要做好社会化营销,就是要把用户当作普通人,跟她们沟通互动,满足她们的这些需求、焦虑和欲望:营销就是这么简单,不要想的太复杂,不要过份曲高和寡,哗众取宠!

7. #营销#微信支付、微博支付、支付宝、拉卡拉、财付通。。我只能说,社会化商务时代是真正来临,不再只是想像了。品牌啊!你们究竟知不知道不进则退,要追赶竞争,抢夺顾客,已经到了寸土必争,刻不容缓的时间了?社会化营销的最后一公里路,今年一定会成熟!

8. #互联网思维#每一个品牌都是媒体,每一个消费者都为品牌创造内容。传统媒体已经被颠覆,要有营销人的思维,以受众的利益做主导,才有基本的生存空间。

9. #营销#很多品牌都知道大部分消费者的主要媒体是手机和电脑,知道移动营销很重要,互联网营销不可忽视,传统媒体的ROI低,难以衡量而且浪费率高。可是,大部分品牌还是把大部分预算分配到投放在传统媒体,是什么原因呢?1.不懂;2.不想解释;3.不同意这个说法;4.不变就不会错。

10. #分享#最近深深体会到营销人的挑战:1.反应速度比有序规划重要;2.不懂移动营销根本没有竞争力;3.口碑最能影响购物决定;4.要做强做大,创新比创意重要;5.用户体验将会是一切购物者营销的核心;6.传统媒体的挑战前所未有;7.互联网思维虽然已经讲到烂了,但是品牌没有互联网思维倒不如烂掉吧!

11. #营销#如果今天还以为只是在单一平台(比如微博或微信)上做社会化营销,就能达到远大的效果的话,企业就实在是太天真了。要达到效果,必须整合各种触点,利用不同的自家、免费、付费媒体,要有好的创意,要给消费者一个有价值的理由参与。要不然,营销就是无效。

12. #营销#记住我说的这句话:几年后,品牌不再需要付费媒体,因为品牌自己就是媒体,可以在各大平台上发出声音,引起口碑。输的品牌,就是不相信这个道理。

13. #营销#企业和品牌一个最错误的概念,以为在微博豆瓣优酷开一个帐号,就是找了一个媒体做营销。实情是:他们自己应该定位为一个自媒体,找到一个很多用户的平台去做各种营销。一句经典的老话:Think like a publisher, not a marketer. (这是社会化营销101)

14. 从传播到解决客户的生意难题,这才是营销公司的创新,要提升核心竞争力!

15. #营销#跟其他人一样,一成不变的把过往一套用在今天,最多只是普通的品牌;营销没有突破,最大的障碍就是传统的营销思维

16. #营销#就是为了创造价值。为消费者、品牌和任何在营销价值链上的利益攸关者创造共赢,就是营销的真正意义。

17. 我觉得InfluencerMarketing并不局限于微博微信等流行平台的,而且更是社会化口碑营销中最被低估的一环。它的作用并不是口碑扩散那么简单,最重要的是产生可靠的口碑。记住,多少人转发不是最重要,多少人以后会成为消费者才重要。

18. #营销#迷笛和草莓音乐节,真的是社会化营销的好时机,特别是针对年轻一代。其实,可能比世界杯更有效

19. #感悟#一个人的成功,是踩着不断失败的路而来的。不要因为挫折就放弃追求成功,没有经历过失败的人,是永远不知道成功的滋味的。想不经过艰苦努力就成功的人,是痴心妄想。我说的。

20. 乔布斯认为,苹果的产品是不需要看说明书你就会懂用的。试问,你需要多长时间去理解iPhone怎么用?你需要多长时间去明白微博怎样发帖?短信怎样发?我认为,假如有一个产品需要解释1小时都不能说服其他人这是一个好的产品的话,就把它忘记吧!
文章来源:市场部


(关注更多人人都是产品经理观点,参与微信互动(微信搜索“人人都是产品经理”或“woshipm”)

微信之父张小龙的书单:大学生读完《失控》我肯定录用

$
0
0

222222

导语:张小龙会要求他的产品经理人手一本《乔布斯传》,也曾有人说过,如果求职者对他说自己看完了凯文·凯利的《失控》,面试就可以结束了。

“微信之父”张小龙会要求他的产品经理人手一本《乔布斯传》,也曾有人说过,如果求职者说自己看完了凯文·凯利的《失控》,面试就可以结束了。不禁让人好奇,张小龙平日里会看哪些书?这些书又如何影响着他对“微信”的构想?

本文主体部分根据《壹读》“失控的微信先生”与《商业周刊中文版》“张小龙的盗梦空间”整理。

1.《失控》

凯文·凯利,一位在亚洲游荡了近10年的美国人,东方激发了他对于技术的思考,最终通往哲学的终极命题。在他笔下,失控,往往意味着不确定性,容易使人感到不安,但正是不确定性和不可控性,成就了创新的源泉与进化的动因。

在广研,产品经理们人手一本《失控》,因为张小龙说过:不读《失控》的产品经理,知识结构是不完整的。在腾讯内部的演讲中,张小龙反复提及这本书启发了他的产品观:不与用户产生互动的产品,是失败的产品。产品规则越简单,才越能让群体形成自发的互动。产品上线后,就有了自己的生命,会自己与海量用户互动,最后会互动出什么结果,是产品设计者不能控制的。

张小龙:凯文·凯利的《失控》我给很多人推荐。这本书很厚,所以很多人都没有耐心的看完它,我自己也是,可是如果我们面试一个大学生,他告诉我他看完了这本书,我肯定就录用他—— 不过他们不知道这个秘诀。如果做互联网产品的不看一下这本书,我认为知识是不全面的。他从生物学、社会学的角度描述了一种群体效应,总的来说,结论是群体的智商低于个体智商。这个观点不在那本书里,而是在另外一本书里,我不记得书名。一个人在组织里,组织的平均智商是低于个体智商的,个体的智商更高一些,群体会拉平这个智商。比如说在微博里,微博上多了你的智商会降低,大家认同吗?你没有发现这个变化,因为你每天降低一点。很简单的,你每天在微博上说的话,你会发现跟大众越来越一致,别人在说什么,你也在说什么。

2.《科技想要什么》

凯文·凯利向我们介绍了一种全新的科技观。他认为,作为整体,科技不是由线路和金属构成的一团乱麻,而是有生命力的自然形成的系统,它的起源完全可以回溯到生命的初始时期。张小龙对原始人的生活方式充满兴趣,花工夫研究了人类的起源,人类为什么会直立行走,他还曾在知乎上提问:原始人用什么来剪指甲?广研内部对摇一摇有个专门的称呼:撸一撸。这是人类最原始的姿势,最原始的,体验往往是最好的。

为什么?张小龙说自己平时会非常留心观察三四岁小孩子,他发现他们很喜欢用iPhone与iPad,因为这两款电子产品很容易学,比如开机,虽然看不懂“滑动来解锁”,但因为触摸是人的天性,他们会下意识顺着箭头的方向用手指去滑动。“越简单,越原始,就越人性化”。

3.《乔布斯传》

在腾讯公司内部,张小龙被称为继马化腾之后的第二个超级产品经理,中国的乔布斯。微信4 .0推出时张小龙更新了微博签名:越简单,但越好。这是德国工业设计大师Dieter Ram崇尚的设计理念,也是乔布斯“至繁归于至简”的精神。4.0初期的朋友圈甚至没有滤镜,因为他认为:照片真实、不加修饰地反映生活即可。微信发展早期,一些创意常被竞争对手模仿,并进化出新功能,马化腾曾问张小龙:是不是要做细化,免得别人做了那些我们没有想到的功能。张坚决否定,他说:只有做到极简,才无法被超越。一位微信团队前成员透露,微信每个版本的设计,张小龙都会鼓励大家先做加法,再做减法,“现在你正在用的一个功能,很可能就是我们砍了 300多个功能后留下的。”他说。

微信的开机画面,起初做过许多方案,大家比较倾向于两个人站在地球前,张小龙坚持就一个人,否则无法传递这款应用的用意:人很孤独,所以需要沟通。朋友圈也是一款充满极简主义的产品,它的主色调是蓝灰色,这也是张小龙平时常穿的T恤以及广研办公室的色调。拍照片,按一下右上角相机按钮;写纯文本,长按右上角相机按钮即可,这一功能许多用户起初并不知道。“按住说话”的功能也是,说话时,其实按三秒就可以放开了。但张小龙从不说,也不担心用户不会用,“你去找,自然就能找到”。

4.《女人的起源》

以男性为中心的生物学家,则用人类起源于丛林并进化为以狩猎为生的肉食动物的学说,来证明女性无论在体力和智力上,都处于从属的地位。对此,《女人的起源》首次为女性在人类进化史中的平等地位据理力争。它开一代风气之先,力图解开人类,特别是女性的演化和起源之谜;而它提供的答案,则从女性的角度对人类的史前史做出了推测性的重构,极富革命性和破坏力。在张小龙的演讲里,他曾经向听众推荐这本书,他说:“如果你们对女性的心理研究不透彻的话,你就损失了一半的用户。”

5.《黑客》

Steven Levy这部经典力作的25周年版从20世纪50年代早期跨越到80年代后期,追述了计算机革命中初期黑客的丰功伟绩,他们都是最聪明和最富有个性的精英。他们勇于承担风险,勇于挑战规则,并把世界推向了一个全新的发展方向。本书更新了一些著名黑客的最新资料,包括比尔·盖茨、马克·扎克伯格、理查德· 斯托曼和史蒂夫·沃兹尼亚克,并讲述了从早期计算机研究实验室到最初的家用计算机期间一些妙趣横生的故事。在Levy的笔下,他们都是聪明而勤奋的人,他们极富想象力,他们另辟蹊径,发现了计算机工程问题的巧妙解决方案。他们都有一个共同的价值观,那就是至今仍然长盛不衰的“黑客道德”。

6.《异类》

在《异类》一书中,作家格拉德威尔对社会中那些成功人士进行的分析,让读者看到了一连串颇感意外的统计结果:英超联赛大部分球员都在9月至11月出生;比尔·盖茨和史蒂夫·乔布斯都出生在1955年;纽约很多著名律师事务所的开创者竟然都是犹太人后裔,并且他们的祖辈大多是在纽约的服装行业谋生。那些奇才异类,他们之所以神奇,得感谢机遇的眷顾。

不过,除了机遇之外,他们的成功还需要上辈人的文化熏陶。因此,从《异类》一书中,你能体会到机遇对成功是如此的重要。格拉德威尔为读者指出了成功之路的方向,但怎样把握这份机遇,每个人都需要仔细思考,毕竟,不同人拥有不同的机遇。在这本书中,张小龙最欣赏的则是“1万小时定律”,即一个人必须经过超过1万小时的训练才能达到一定的专业高度。

7.《信息简史》

现如今,信息如洪流般淹没了我们,使我们深陷信息焦虑、信息过载、信息疲劳的困扰。但回顾历史,这并不是件新鲜事,人们也总是能想出应对手段。维基百科 、Google便是我们的应对之一。无论对于信息的未来持何态度,有一点是确定无疑的,即我们人类是信息的造物。作为《混沌》、《费曼传》、《越来越快》、《牛顿传》等畅销书的作者,格雷克不仅在书中细致还原了历史细节,通俗解释了各种理论,还生动刻画了几位不为大众所知的人物:可编程计算机先驱、超越时代的查尔斯·巴贝奇,第一位程序员、诗人拜伦之女爱达·拜伦,计算机科学之父、天妒英才的阿兰·图灵,以及全书的主人公、信息论之父克劳德·香农。

8.《数字乌托邦》

20世纪60年代早期,在美国大众眼中,计算机只是冷战中冰冷的机器,然而到了90年代互联网到来之时,计算机却呈现出一个截然不同的世界——它们模拟出了一个数字乌托邦般的协同体,而这正是曾经最反对冷战的嬉皮士们的共同愿景。本书正是探索这次非同寻常,且颇具讽刺意味的变革的第一本书。作者挖掘出那些在旧金山湾区的先驱者——斯图尔特·布兰德和他的“全球网络”鲜为人知的故事。1968年到1998年期间,通过《全球概览》、“全球电子链接(WELL)”和最终取得巨大成功的《连线》杂志,布兰德和他的伙伴们长期扮演着旧金山嬉皮士运动和新兴科技聚集区硅谷的中间人的角色。正由于他们富有远见的努力,反主流文化分子和科技人士一同重新定义了计算机的形象:计算机是解放自我的武器,计算机建筑了令人耳目一新的虚拟社区,计算机还让人们能更大胆地拓展社会的新疆界。

文章来源:创业邦


(关注更多人人都是产品经理观点,参与微信互动(微信搜索“人人都是产品经理”或“woshipm”)

高吞吐低延迟Java应用的垃圾回收优化

$
0
0

高性能应用构成了现代网络的支柱。LinkedIn有许多内部高吞吐量服务来满足每秒数千次的用户请求。要优化用户体验,低延迟地响应这些请求非常重要。

比如说,用户经常用到的一个功能是了解动态信息——不断更新的专业活动和内容的列表。动态信息在LinkedIn随处可见,包括公司页面,学校页面以及最重要的主页。基础动态信息数据平台为我们的经济图谱(会员,公司,群组等等)中各种实体的更新建立索引,它必须高吞吐低延迟地实现相关的更新。

图1 LinkedIn 动态信息图1 LinkedIn 动态信息

这些高吞吐低延迟的Java应用转变为产品,开发人员必须确保应用开发周期的每个阶段一致的性能。确定优化垃圾回收(Garbage Collection,GC)的设置对达到这些指标非常关键。

本文章通过一系列步骤来明确需求并优化GC,目标读者是为实现应用的高吞吐低延迟,对使用系统方法优化GC感兴趣的开发人员。文章中的方法来自于LinkedIn构建下一代动态信息数据平台过程。这些方法包括但不局限于以下几点:并发标记清除(Concurrent Mark Sweep,CMS)和 G1垃圾回收器的CPU和内存开销,避免长期存活对象引起的持续GC周期,优化GC线程任务分配使性能提升,以及GC停顿时间可预测所需的OS设置。

优化GC的正确时机?

GC运行随着代码级的优化和工作负载而发生变化。因此在一个已实施性能优化的接近完成的代码库上调整GC非常重要。但是在端到端的基本原型上进行初步分析也很有必要,该原型系统使用存根代码并模拟了可代表产品环境的工作负载。这样可以捕捉该架构延迟和吞吐量的真实边界,进而决定是否纵向或横向扩展。

在下一代动态信息数据平台的原型阶段,几乎实现了所有端到端的功能,并且模拟了当前产品基础架构所服务的查询负载。从中我们获得了多种用来衡量应用性能的工作负载特征和足够长时间运行情况下的GC特征。

优化GC的步骤

下面是为满足高吞吐,低延迟需求优化GC的总体步骤。也包括在动态信息数据平台原型实施的具体细节。可以看到在ParNew/CMS有最好的性能,但我们也实验了G1垃圾回收器。

1.理解GC基础知识

理解GC工作机制非常重要,因为需要调整大量的参数。Oracle的Hotspot JVM 内存管理 白皮书是开始学习Hotspot JVM GC算法非常好的资料。了解G1垃圾回收器,请查看该 论文

2. 仔细考量GC需求

为降低应用性能的GC开销,可以优化GC的一些特征。吞吐量、延迟等这些GC特征应该长时间测试运行观察,确保特征数据来自于应用程序的处理对象数量发生变化的多个GC周期。

  • Stop-the-world回收器回收垃圾时会暂停应用线程。停顿的时长和频率不应该对应用遵守SLA产生不利的影响。
  • 并发GC算法与应用线程竞争CPU周期。这个开销不应该影响应用吞吐量。
  • 不压缩GC算法会引起堆碎片化,导致full GC长时间Stop-the-world停顿。
  • 垃圾回收工作需要占用内存。一些GC算法产生更高的内存占用。如果应用程序需要较大的堆空间,要确保GC的内存开销不能太大。
  • 清晰地了解GC日志和常用的JVM参数对简单调整GC运行很有必要。GC运行随着代码复杂度增长或者工作特性变化而改变。

我们使用Linux OS的Hotspot Java7u51,32GB堆内存,6GB新生代(young generation)和 -XX:CMSInitiatingOccupancyFraction值为70(老年代GC触发时其空间占用率)开始实验。设置较大的堆内存用来维持长期存活对象的对象缓存。一旦这个缓存被填充,提升到老年代的对象比例显著下降。

使用初始的GC配置,每三秒发生一次80ms的新生代GC停顿,超过百分之99.9的应用延迟100ms。这样的GC很可能适合于SLA不太严格要求延迟的许多应用。然而,我们的目标是尽可能降低百分之99.9应用的延迟,为此GC优化是必不可少的。

3.理解GC指标

优化之前要先衡量。了解GC日志的详细细节(使用这些选项: -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintTenuringDistribution -XX:+PrintGCApplicationStoppedTime)可以对该应用的GC特征有总体的把握。

LinkedIn的内部监控和报表系统, inGraphsNaarad,生成了各种有用的指标可视化图形,比如GC停顿时间百分比,一次停顿最大持续时间,长时间内GC频率。除了Naarad,有很多开源工具比如 gclogviewer可以从GC日志创建可视化图形。

在这个阶段,需要确定GC频率和停顿时长是否影响应用满足延迟性需求的能力。

4.降低GC频率

在分代GC算法中,降低回收频率可以通过:(1)降低对象分配/提升率;(2)增加代空间的大小。

在Hotspot JVM中,新生代GC停顿时间取决于一次垃圾回收后对象的数量,而不是新生代自身的大小。增加新生代大小对于应用性能的影响需要仔细评估:

  • 如果更多的数据存活而且被复制到survivor区域,或者每次垃圾回收更多的数据提升到老年代,增加新生代大小可能导致更长的新生代GC停顿。
  • 另一方面,如果每次垃圾回收后存活对象数量不会大幅增加,停顿时间可能不会延长。在这种情况下,减少GC频率可能使应用总体延迟降低和(或)吞吐量增加。

对于大部分为短期存活对象的应用,仅仅需要控制前面所说的参数。对于创建长期存活对象的应用,就需要注意,被提升的对象可能很长时间都不能被老年代GC周期回收。如果老年代GC触发阈值(老年代空间占用率百分比)比较低,应用将陷入不断的GC周期。设置高的GC触发阈值可避免这一问题。

由于我们的应用在堆中维持了长期存活对象的较大缓存,将老年代GC触发阈值设置为 -XX:CMSInitiatingOccupancyFraction=92 -XX:+UseCMSInitiatingOccupancyOnly。我们也试图增加新生代大小来减少新生代回收频率,但是并没有采用,因为这增加了应用延迟。

5.缩短GC停顿时间

减少新生代大小可以缩短新生代GC停顿时间,因为这样被复制到survivor区域或者被提升的数据更少。但是,正如前面提到的,我们要观察减少新生代大小和由此导致的GC频率增加对于整体应用吞吐量和延迟的影响。新生代GC停顿时间也依赖于tenuring threshold(提升阈值)和空间大小(见第6步)。

使用CMS尝试最小化堆碎片和与之关联的老年代垃圾回收full GC停顿时间。通过控制对象提升比例和减小 -XX:CMSInitiatingOccupancyFraction的值使老年代GC在低阈值时触发。所有选项的细节调整和他们相关的权衡,请查看 Web Services的Java 垃圾回收Java 垃圾回收精粹

我们观察到Eden区域的大部分新生代被回收,几乎没有对象在survivor区域死亡,所以我们将tenuring threshold从8降低到2(使用选项: -XX:MaxTenuringThreshold=2),为的是缩短新生代垃圾回收消耗在数据复制上的时间。

我们也注意到新生代回收停顿时间随着老年代空间占用率上升而延长。这意味着来自老年代的压力使得对象提升花费更多的时间。为解决这个问题,将总的堆内存大小增加到40GB,减小 -XX:CMSInitiatingOccupancyFraction的值到80,更快地开始老年代回收。尽管 -XX:CMSInitiatingOccupancyFraction的值减小了,增大堆内存可以避免不断的老年代GC。在本阶段,我们获得了70ms新生代回收停顿和百分之99.9延迟80ms。

6.优化GC工作线程的任务分配

进一步缩短新生代停顿时间,我们决定研究优化与GC线程绑定任务的选项。

-XX:ParGCCardsPerStrideChunk选项控制GC工作线程的任务粒度,可以帮助不使用 补丁而获得最佳性能,这个补丁用来优化新生代垃圾回收的 卡表扫描时间。有趣的是新生代GC时间随着老年代空间的增加而延长。将这个选项值设为32678,新生代回收停顿时间降低到平均50ms。此时百分之99.9应用延迟60ms。

也有其他选项将任务映射到GC线程,如果OS允许的话, -XX:+BindGCTaskThreadsToCPUs选项绑定GC线程到个别的CPU核。 -XX:+UseGCTaskAffinity使用affinity参数将任务分配给GC工作线程。然而,我们的应用并没有从这些选项发现任何益处。实际上,一些调查显示这些选项在Linux系统不起作用[1,2]。

7.了解GC的CPU和内存开销

并发GC通常会增加CPU的使用。我们观察了运行良好的CMS默认设置,并发GC和G1垃圾回收器共同工作引起的CPU使用增加显著降低了应用的吞吐量和延迟。与CMS相比,G1可能占用了应用更多的内存开销。对于低吞吐量的非计算密集型应用,GC的高CPU使用率可能不需要担心。

图2 ParNew/CMS和G1的CPU使用百分数%:相对来说CPU使用率变化明显的节点使用G1<br/>选项-XX:G1RSetUpdatingPauseTimePercent=20图2 ParNew/CMS和G1的CPU使用百分数%:相对来说CPU使用率变化明显的节点使用G1
选项-XX:G1RSetUpdatingPauseTimePercent=20 图3 ParNew/CMS和G1每秒服务的请求数:吞吐量较低的节点使用G1<br/>选项-XX:G1RSetUpdatingPauseTimePercent=20图3 ParNew/CMS和G1每秒服务的请求数:吞吐量较低的节点使用G1
选项-XX:G1RSetUpdatingPauseTimePercent=20

8.为GC优化系统内存和I/O管理

通常来说,GC停顿发生在(1)低用户时间,高系统时间和高时钟时间和(2)低用户时间,低系统时间和高时钟时间。这意味着基础的进程/OS设置存在问题。情况(1)可能说明Linux从JVM偷页,情况(2)可能说明清除磁盘缓存时Linux启动GC线程,等待I/O时线程陷入内核。在这些情况下如何设置参数可以参考 该PPT

为避免运行时性能损失,启动应用时使用JVM选项 -XX:+AlwaysPreTouch访问和清零页面。设置 vm.swappiness为零,除非在绝对必要时,OS不会交换页面。

可能你会使用 mlock将JVM页pin在内存中,使OS不换出页面。但是,如果系统用尽了所有的内存和交换空间,OS通过kill进程来回收内存。通常情况下,Linux内核会选择高驻留内存占用但还没有长时间运行的进程( OOM情况下killing进程的工作流)。对我们而言,这个进程很有可能就是我们的应用程序。一个服务具备优雅降级(适度退化)的特点会更好,服务突然故障预示着不太好的可操作性——因此,我们没有使用 mlock而是 vm.swappiness避免可能的交换惩罚。

LinkedIn动态信息数据平台的GC优化

对于该平台原型系统,我们使用Hotspot JVM的两个算法优化垃圾回收:

  • 新生代垃圾回收使用ParNew,老年代垃圾回收使用CMS。
  • 新生代和老年代使用G1。G1用来解决堆大小为6GB或者更大时存在的低于0.5秒稳定的、可预测停顿时间的问题。在我们用G1实验过程中,尽管调整了各种参数,但没有得到像ParNew/CMS一样的GC性能或停顿时间的可预测值。我们查询了使用G1发生内存泄漏相关的一个bug[3],但还不能确定根本原因。

使用ParNew/CMS,应用每三秒40-60ms的新生代停顿和每小时一个CMS周期。JVM选项如下:

// JVM sizing options
-server -Xms40g -Xmx40g -XX:MaxDirectMemorySize=4096m -XX:PermSize=256m -XX:MaxPermSize=256m   
// Young generation options
-XX:NewSize=6g -XX:MaxNewSize=6g -XX:+UseParNewGC -XX:MaxTenuringThreshold=2 -XX:SurvivorRatio=8 -XX:+UnlockDiagnosticVMOptions -XX:ParGCCardsPerStrideChunk=32768
// Old generation  options
-XX:+UseConcMarkSweepGC -XX:CMSParallelRemarkEnabled -XX:+ParallelRefProcEnabled -XX:+CMSClassUnloadingEnabled  -XX:CMSInitiatingOccupancyFraction=80 -XX:+UseCMSInitiatingOccupancyOnly   
// Other options
-XX:+AlwaysPreTouch -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintTenuringDistribution -XX:+PrintGCApplicationStoppedTime -XX:-OmitStackTraceInFastThrow

使用这些选项,对于几千次读请求的吞吐量,应用百分之99.9的延迟降低到60ms。

参考:

[1] -XX:+BindGCTaskThreadsToCPUs似乎在Linux系统上不起作用,因为 hotspot/src/os/linux/vm/os_linux.cppdistribute_processes方法在JDK7或JDK8没有实现。
[2] -XX:+UseGCTaskAffinity选项在JDK7和JDK8的所有平台似乎都不起作用,因为任务的affinity属性永远被设置为 sentinel_worker = (uint) -1。源码见 hotspot/src/share/vm/gc_implementation/parallelScavenge/{gcTaskManager.cpp,gcTaskThread.cpp, gcTaskManager.cpp}
[3] G1存在一些内存泄露的bug,可能Java7u51没有修改。这个 bug仅在Java 8修正了。

相关文章

9款基于HTML5/SVG/Canvas的折线图表应用

$
0
0

利用 HTML5制作精美而实用的折线图表比较简单,因为我们除了可以利用HTML/CSS/Javascript外,还可以使用功能强大的SVG和Canvas动画特性,今天我们就来分享9款基于HTML5/SVG/Canvas的折线图表应用。

1、HTML5折线图表Aristochart 图表配置简单

之前我已经向大家分享了几款HTML5图表应用, HTML5 Canvas图表应用RGraphHTML5 Canvas饼状图表。利用这些HTML5图表可以很方便的展示各种数据,而且非常直观。今天要向大家分享一款HTML5折线图表插件Aristochart,Aristochart扩展非常灵活,配置也比较简单,是一款很实用的HTML5图表应用。

aristochart-html5-chart

在线演示1   在线演示2   在线演示3   在线演示4   源码下载

2、华丽的HTML5图表 可展示实时数据

HTML5在图表应用中也十分广泛,比起以前的网页图表,HTML5图表制作更便捷,功能更强大。这款HTML5图表插件外观十分华丽和专业,在数据展示方面也很有优势,图表不仅支持多维数据展示,而且支持区域选择数据功能,利用该HTML5图表可以更加方便地管理你的数据。

html5-chart-data

在线演示         源码下载

3、HTML5 D3图表 超酷的图表初始化动画效果

今天已经向大家分享过一款基于HTML5和CSS3的柱状图表应用了,接下来同样是一款HTML5图表应用,图表名称叫HTML5 D3 Chart,作者是一位德国开发者Brian Hanby。这款HTML5图表展现了一款环状图和折线图,图表的特点是在初始化数据的时候会出现很酷的动画效果,环状图和折线图的动画效果是不一样的。

html5-d3-chart

在线演示         源码下载

4、HTML5 SVG多折线图表 图表可缩放显示

今天我们要来介绍一款基于 HTML5 SVG的折线图表,该款图片支持多条折线重叠在一起显示,可以方便地比较不同颜色折线的数据。另外图表还有一个特点,就是可以缩放和移动,这大大方便了用户浏览图表数据,非常人性化。更多图表应用,请移步至 HTML5图表栏目。

html5-svg-multi-line-chart

在线演示         源码下载

5、HTML5 Canvas发光折线图表应用

之前我们分享过很多HTML5折线图表,像 HTML5 SVG多折线图表HTML5/CSS3动态折线图表等。今天我们要分享一款基于HTML5 Canvas的折线图表应用,其实我们仅仅是在canvas上面绘制了一条发光的折线,当然图表的x、y坐标你可以自己绘制上去。

html5-canvas-line-chart

在线演示         源码下载

6、HTML5数学函数图形绘制插件XCalc

XCalc是一款基于HTML5的数学函数图形绘制插件,这款函数图形绘制插件不仅可以绘制简单的加减乘除运算的函数图形,也可以绘制乘方运算和正弦余弦运算的函数图形。XCalc的配置也非常简单,在HTML5图表中应用十分广泛。

html5-xcalc-demo

在线演示         源码下载

7、HTML5/CSS3动态折线图表 图表数据切换动画

前面我们刚刚分享过一款很不错的 HTML5/SVG折线图表,这次我们依然要来分享一款带超酷动画的 HTML5/CSS3动态折线图表,图表数据会定时切换,图表数据在切换的时候有很酷的切换动画,感觉数据模拟非常真实。另外,更多的HTML5图表应用可以到 HTML5图表栏目下查看。

html5-css3-animated-graph

在线演示         源码下载

8、HTML5/SVG线性图表 可绘制图表区域颜色

今天要分享的这款HTML5图表应用是一款线性图表,它主要是有SVG构造出来的,这款SVG线性图表可以用不同的颜色绘制出图表的数据区域。另外,这款图表和之前分享的 HTML5线性图表iGrapher 类似,只是功能没那么强大而已。

html5-svg-line-chart

在线演示         源码下载

9、HTML5线性图表iGrapher 功能非常强大

iGrapher是一款基于HTML5的线性图表应用,和之前分享的 HTML5线性图表 图表数据区域可着色类似,iGrapher也可以按不同的统计范围来绘制曲线,同时我们在iGrapher中可以利用鼠标滚轮来缩放统计区间,同时我们可以在menu栏中选择需要显示的统计数据。

html5-chart-igrapher

在线演示         源码下载

以上就是9款基于HTML5/SVG/Canvas的折线图表应用,欢迎收藏分享。

Java 8的元空间

$
0
0

本文我们将会介绍JVM的一个更新,这就是持久代的移除。我们会介绍为什么需要移除持久代,以及它的替代者,元空间(metaspace)。这是上一篇文章 内存管理之垃圾回收的续集。

Java 6中的堆结构是这样的:

持久代

持久代中包含了虚拟机中所有可通过反射获取到的数据,比如Class和Method对象。不同的Java虚拟机之间可能会进行类共享,因此持久代又分为只读区和读写区。

JVM用于描述应用程序中用到的类和方法的元数据也存储在持久代中。JVM运行时会用到多少持久代的空间取决于应用程序用到了多少类。除此之外,Java SE库中的类和方法也都存储在这里。

如果JVM发现有的类已经不再需要了,它会去回收(卸载)这些类,将它们的空间释放出来给其它类使用。Full GC会进行持久代的回收。

  • JVM中类的元数据在Java堆中的存储区域。
  • Java类对应的HotSpot虚拟机中的内部表示也存储在这里。
  • 类的层级信息,字段,名字。
  • 方法的编译信息及字节码。
  • 变量
  • 常量池和符号解析

持久代的大小

  • 它的上限是MaxPermSize,默认是64M
  • Java堆中的连续区域 : 如果存储在非连续的堆空间中的话,要定位出持久代到新对象的引用非常复杂并且耗时。卡表(card table),是一种记忆集(Remembered Set),它用来记录某个内存代中普通对象指针(oops)的修改。
  • 持久代用完后,会抛出OutOfMemoryError "PermGen space"异常。解决方案:应用程序清理引用来触发类卸载;增加MaxPermSize的大小。
  • 需要多大的持久代空间取决于类的数量,方法的大小,以及常量池的大小。

为什么移除持久代

  • 它的大小是在启动时固定好的——很难进行调优。-XX:MaxPermSize,设置成多少好呢?
  • HotSpot的内部类型也是Java对象:它可能会在Full GC中被移动,同时它对应用不透明,且是非强类型的,难以跟踪调试,还需要存储元数据的元数据信息(meta-metadata)。
  • 简化Full GC:每一个回收器有专门的元数据迭代器。
  • 可以在GC不进行暂停的情况下并发地释放类数据。
  • 使得原来受限于持久代的一些改进未来有可能实现

那么JVM的元数据都去哪儿了?

元空间(metaspace)

持久代的空间被彻底地删除了,它被一个叫元空间的区域所替代了。持久代删除了之后,很明显,JVM会忽略PermSize和MaxPermSize这两个参数,还有就是你再也看不到java.lang.OutOfMemoryError: PermGen error的异常了。

JDK 8的HotSpot JVM现在使用的是本地内存来表示类的元数据,这个区域就叫做元空间。

元空间的特点:

  • 充分利用了Java语言规范中的好处:类及相关的元数据的生命周期与类加载器的一致。
  • 每个加载器有专门的存储空间
  • 只进行线性分配
  • 不会单独回收某个类
  • 省掉了GC扫描及压缩的时间
  • 元空间里的对象的位置是固定的
  • 如果GC发现某个类加载器不再存活了,会把相关的空间整个回收掉

元空间的内存分配模型

  • 绝大多数的类元数据的空间都从本地内存中分配
  • 用来描述类元数据的类也被删除了
  • 分元数据分配了多个虚拟内存空间
  • 给每个类加载器分配一个内存块的列表。块的大小取决于类加载器的类型; sun/反射/代理对应的类加载器的块会小一些
  • 归还内存块,释放内存块列表
  • 一旦元空间的数据被清空了,虚拟内存的空间会被回收掉
  • 减少碎片的策略

我们来看下JVM是如何给元数据分配虚拟内存的空间的

你可以看到虚拟内存空间是如何分配的(vs1,vs2,vs3) ,以及类加载器的内存块是如何分配的。CL是Class Loader的缩写。

理解_mark和_klass指针

要想理解下面这张图,你得搞清楚这些指针都是什么东西。

JVM中,每个对象都有一个指向它自身类的指针,不过这个指针只是指向具体的实现类,而不是接口或者抽象类。

对于32位的JVM:

_mark : 4字节常量

_klass: 指向类的4字节指针 对象的内存布局中的第二个字段( _klass,在32位JVM中,相对对象在内存中的位置的偏移量是4,64位的是8)指向的是内存中对象的类定义。

64位的JVM:

_mark : 8字节常量

_klass: 指向类的8字节的指针

开启了指针压缩的64位JVM: _mark : 8字节常量

_klass: 指向类的4字节的指针

Java对象的内存布局

类指针压缩空间(Compressed Class Pointer Space)

只有是64位平台上启用了类指针压缩才会存在这个区域。对于64位平台,为了压缩JVM对象中的_klass指针的大小,引入了类指针压缩空间(Compressed Class Pointer Space)。

压缩指针后的内存布局

指针压缩概要

  • 64位平台上默认打开
  • 使用-XX:+UseCompressedOops压缩对象指针 "oops"指的是普通对象指针("ordinary" object pointers)。 Java堆中对象指针会被压缩成32位。 使用堆基地址(如果堆在低26G内存中的话,基地址为0)

  • 使用-XX:+UseCompressedClassPointers选项来压缩类指针

  • 对象中指向类元数据的指针会被压缩成32位

  • 类指针压缩空间会有一个基地址

元空间和类指针压缩空间的区别

  • 类指针压缩空间只包含类的元数据,比如InstanceKlass, ArrayKlass 仅当打开了UseCompressedClassPointers选项才生效 为了提高性能,Java中的虚方法表也存放到这里 这里到底存放哪些元数据的类型,目前仍在减少

  • 元空间包含类的其它比较大的元数据,比如方法,字节码,常量池等。

元空间的调优

使用-XX:MaxMetaspaceSize参数可以设置元空间的最大值,默认是没有上限的,也就是说你的系统内存上限是多少它就是多少。-XX:MetaspaceSize选项指定的是元空间的初始大小,如果没有指定的话,元空间会根据应用程序运行时的需要动态地调整大小。

MaxMetaspaceSize的调优

  • -XX:MaxMetaspaceSize={unlimited}
  • 元空间的大小受限于你机器的内存
  • 限制类的元数据使用的内存大小,以免出现虚拟内存切换以及本地内存分配失败。如果怀疑有类加载器出现泄露,应当使用这个参数;32位机器上,如果地址空间可能会被耗尽,也应当设置这个参数。
  • 元空间的初始大小是21M——这是GC的初始的高水位线,超过这个大小会进行Full GC来进行类的回收。
  • 如果启动后GC过于频繁,请将该值设置得大一些
  • 可以设置成和持久代一样的大小,以便推迟GC的执行时间

CompressedClassSpaceSize的调优

  • 只有当-XX:+UseCompressedClassPointers开启了才有效
  • -XX:CompressedClassSpaceSize=1G
  • 由于这个大小在启动的时候就固定了的,因此最好设置得大点。
  • 没有使用到的话不要进行设置
  • JVM后续可能会让这个区可以动态的增长。不需要是连续的区域,只要从基地址可达就行;可能会将更多的类元信息放回到元空间中;未来会基于PredictedLoadedClassCount的值来自动的设置该空间的大小

元空间的一些工具

  • jmap -permstat改成了jmap -clstats。它用来打印Java堆的类加载器的统计数据。对每一个类加载器,会输出它的名字,是否存活,地址,父类加载器,以及它已经加载的类的数量及大小。除此之外,驻留的字符串(intern)的数量及大小也会打印出来。
  • jstat -gc,这个命令输出的是元空间的信息而非持久代的
  • jcmd GC.class_stats提供类元数据大小的详细信息。使用这个功能启动程序时需要加上-XX:+UnlockDiagnosticVMOptions选项。

提高GC的性能

如果你理解了元空间的概念,很容易发现GC的性能得到了提升。

  • Full GC中,元数据指向元数据的那些指针都不用再扫描了。很多复杂的元数据扫描的代码(尤其是CMS里面的那些)都删除了。
  • 元空间只有少量的指针指向Java堆。这包括:类的元数据中指向java/lang/Class实例的指针;数组类的元数据中,指向java/lang/Class集合的指针。
  • 没有元数据压缩的开销
  • 减少了根对象的扫描(不再扫描虚拟机里面的已加载类的字典以及其它的内部哈希表)
  • 减少了Full GC的时间
  • G1回收器中,并发标记阶段完成后可以进行类的卸载

总结

  • Hotspot中的元数据现在存储到了元空间里。mmap中的内存块的生命周期与类加载器的一致。
  • 类指针压缩空间(Compressed class pointer space)目前仍然是固定大小的,但它的空间较大
  • 可以进行参数的调优,不过这不是必需的。
  • 未来可能会增加其它的优化及新特性。比如, 应用程序类数据共享;新生代GC优化,G1回收器进行类的回收;减少元数据的大小,以及JVM内部对象的内存占用量。

译注:这有点像一篇读书笔记,比较琐碎。。

原创文章转载请注明出处: Java 8的元空间英文原文链接


应对高并发攻击

$
0
0

近半个月过得很痛苦,主要是产品上线后,引来无数机器用户恶意攻击,不停的刷新产品各个服务入口,制造垃圾数据,消耗资源。他们的最好成绩,1秒钟 可以并发6次,赶在Database入库前,Cache进行Missing Loading前,强占这其中十几毫秒的时间,进行恶意攻击。


为了应对上述情况,做了如下调整:

 

  1. 更新数据时,先写Cache,然后写Database(双写),如果可以,写操作交给队列后续完成。
  2. 限制统一帐号,同一动作,同一秒钟并发次数,超过1次不做做动作,返回操作失败。
  3. 限制统一用户,每日动作次数,超限返回操作失败。

要完成上述操作,同事给我支招。用Memcached的add方法,就可以很快速的解决问题。不需要很繁琐的开发,也不需要依赖数据库记录,完全内存操作。

以下实现一个判定冲突的方法:

 

Java代码   收藏代码
  1. /** 
  2.  * 冲突延时 1秒 
  3.  */  
  4. public static final int MUTEX_EXP = 1;  
  5. /** 
  6.  * 冲突键 
  7.  */  
  8. public static final String MUTEX_KEY_PREFIX = "MUTEX_";  
  9.   
  10. /** 
  11.  * 冲突判定 
  12.  *  
  13.  * @param key 
  14.  */  
  15. public boolean isMutex(String key) {  
  16.     return isMutex(key, MUTEX_EXP);  
  17. }  
  18.   
  19. /** 
  20.  * 冲突判定 
  21.  *  
  22.  * @param key 
  23.  * @param exp 
  24.  * @return true 冲突 
  25.  */  
  26. public boolean isMutex(String key, int exp) {  
  27.     boolean status = true;  
  28.     try {  
  29.         if (memcachedClient.add(MUTEX_KEY_PREFIX + key, exp, "true")) {  
  30.             status = false;  
  31.         }  
  32.     } catch (Exception e) {  
  33.         logger.error(e.getMessage(), e);  
  34.     }  
  35.     return status;  
  36. }  

 

做个说明:

 

选项说明
add仅当存储空间中不存在键相同的数据时才保存
replace仅当存储空间中存在键相同的数据时才保存
set与add和replace不同,无论何时都保存

也就是说,如果add操作返回为true,则认为当前不冲突!

 

回归场景,恶意用户1秒钟操作6次,遇到上述这个方法,只有乖乖地1秒后再来。别小看这1秒钟,一个数据库操作不过几毫秒。1秒延迟,足以降低系统负载,增加恶意用户成本。

 

附我用到的基于XMemcached实现:

 

Java代码   收藏代码
  1. import net.rubyeye.xmemcached.MemcachedClient;  
  2.   
  3. import org.apache.log4j.Logger;  
  4. import org.springframework.beans.factory.annotation.Autowired;  
  5. import org.springframework.stereotype.Component;  
  6.   
  7. /** 
  8.  *  
  9.  * @author Snowolf 
  10.  * @version 1.0 
  11.  * @since 1.0 
  12.  */  
  13. @Component  
  14. public class MemcachedManager {  
  15.   
  16.     /** 
  17.      * 缓存时效 1天 
  18.      */  
  19.     public static final int CACHE_EXP_DAY = 3600 * 24;  
  20.   
  21.     /** 
  22.      * 缓存时效 1周 
  23.      */  
  24.     public static final int CACHE_EXP_WEEK = 3600 * 24 * 7;  
  25.   
  26.     /** 
  27.      * 缓存时效 1月 
  28.      */  
  29.     public static final int CACHE_EXP_MONTH = 3600 * 24 * 30 * 7;  
  30.   
  31.     /** 
  32.      * 缓存时效 永久 
  33.      */  
  34.     public static final int CACHE_EXP_FOREVER = 0;  
  35.   
  36.     /** 
  37.      * 冲突延时 1秒 
  38.      */  
  39.     public static final int MUTEX_EXP = 1;  
  40.     /** 
  41.      * 冲突键 
  42.      */  
  43.     public static final String MUTEX_KEY_PREFIX = "MUTEX_";  
  44.     /** 
  45.      * Logger for this class 
  46.      */  
  47.     private static final Logger logger = Logger  
  48.             .getLogger(MemcachedManager.class);  
  49.   
  50.     /** 
  51.      * Memcached Client 
  52.      */  
  53.     @Autowired  
  54.     private MemcachedClient memcachedClient;  
  55.   
  56.     /** 
  57.      * 缓存 
  58.      *  
  59.      * @param key 
  60.      * @param value 
  61.      * @param exp 
  62.      *            失效时间 
  63.      */  
  64.     public void cacheObject(String key, Object value, int exp) {  
  65.         try {  
  66.             memcachedClient.set(key, exp, value);  
  67.         } catch (Exception e) {  
  68.             logger.error(e.getMessage(), e);  
  69.         }  
  70.         logger.info("Cache Object: [" + key + "]");  
  71.     }  
  72.   
  73.     /** 
  74.      * Shut down the Memcached Cilent. 
  75.      */  
  76.     public void finalize() {  
  77.         if (memcachedClient != null) {  
  78.             try {  
  79.                 if (!memcachedClient.isShutdown()) {  
  80.                     memcachedClient.shutdown();  
  81.                     logger.debug("Shutdown MemcachedManager...");  
  82.                 }  
  83.             } catch (Exception e) {  
  84.                 logger.error(e.getMessage(), e);  
  85.             }  
  86.         }  
  87.     }  
  88.   
  89.     /** 
  90.      * 清理对象 
  91.      *  
  92.      * @param key 
  93.      */  
  94.     public void flushObject(String key) {  
  95.         try {  
  96.             memcachedClient.deleteWithNoReply(key);  
  97.         } catch (Exception e) {  
  98.             logger.error(e.getMessage(), e);  
  99.         }  
  100.         logger.info("Flush Object: [" + key + "]");  
  101.     }  
  102.   
  103.     /** 
  104.      * 冲突判定 
  105.      *  
  106.      * @param key 
  107.      */  
  108.     public boolean isMutex(String key) {  
  109.         return isMutex(key, MUTEX_EXP);  
  110.     }  
  111.   
  112.     /** 
  113.      * 冲突判定 
  114.      *  
  115.      * @param key 
  116.      * @param exp 
  117.      * @return true 冲突 
  118.      */  
  119.     public boolean isMutex(String key, int exp) {  
  120.         boolean status = true;  
  121.         try {  
  122.             if (memcachedClient.add(MUTEX_KEY_PREFIX + key, exp, "true")) {  
  123.                 status = false;  
  124.             }  
  125.         } catch (Exception e) {  
  126.             logger.error(e.getMessage(), e);  
  127.         }  
  128.         return status;  
  129.     }  
  130.   
  131.     /** 
  132.      * 加载缓存对象 
  133.      *  
  134.      * @param key 
  135.      * @return 
  136.      */  
  137.     public <T> T loadObject(String key) {  
  138.         T object = null;  
  139.         try {  
  140.             object = memcachedClient.<T> get(key);  
  141.         } catch (Exception e) {  
  142.             logger.error(e.getMessage(), e);  
  143.         }  
  144.         logger.info("Load Object: [" + key + "]");  
  145.         return object;  
  146.     }  
  147.   



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


ITeye推荐



程序员初学机器学习的四种方式

$
0
0

学习机器学习有很多方法,大多数人选择从理论开始。

如果你是个程序员,那么你已经掌握了把问题拆分成相应组成部分及设计小项目原型的能力,这些能力能帮助你学习新的技术、类库和方法。这些对任何一个职业程序员来说都是重要的能力,现在它们也能用在初学机器学习上。

要想有效地学习机器学习你必须学习相关理论,但是你可以利用你的兴趣及对知识的渴望,来激励你从实际例子学起,然后再步入对算法的数学理解。

通过本文你可以学习到程序员初学机器学习的四种方式。这是给技术人员设计的实用方法,并以实验为依据,你需要做调研并且完成实验才能建立自己的感性知识。

这四种方法分别是:

  1. 学习一个机器学习工具
  2. 学习一个机器学习数据集
  3. 学习一个机器学习算法
  4. 实现一个机器学习算法

你应该通读一下这些方法的策略,然后选择你觉得最适合自己的一个,并且有选择性地执行。

1. 学习一个机器学习工具

选一个你喜欢的工具或者类库,然后学着用好它。

我推荐你从一个自带数据预处理工具,机器学习算法并且能呈现结果的工作平台开始学习。学习这样一个工作平台能让你更熟悉机器学习从头到尾的整个过程,这比学习一个特定的数据处理技术或者一个机器学习算法更有价值。

或者,也许你感兴趣的是一个特定技术或者一类技术。你可以利用这个机会更深入地学习一个提供这些方法的类库或工具,掌握了提供这些技术的类库能帮助你掌握相应的技术。

一些你可以采取的策略有:

  • 比较一些可选的工具。
  • 总结你选定的那个工具的能力。
  • 阅读并总结这个工具的文档。
  • 完成学习这个工具的文字或视频教程,并且总结每个教程中你重点学到了什么。
  • 制作关于这个工具的功能或者特性的教程。选一些你不太了解的功能,然后写下得到结果的过程,或者把如何使用这个功能的过程录个五分钟的截屏视频。

一些值得考虑的工作平台有: RWekascikit-learnwaffles, 和  orange.

2. 学习一个机器学习数据集

选一个数据集,然后深入地理解它,发掘究竟哪类算法最适合处理它。

我推荐你选择一个中等大小的,内存能放下的,可能被很多人研究过的数据集。现在有很多非常好的包含数据的类库,你可以浏览它们并且从中选择。你的目的是尝试理解这个数据集背后的问题,它的结构,和哪些种类的解决方法最适合这个问题。

用一个机器学习或者统计的工作平台来研究这个数据集。这样你能专心解答关于这个数据集你要研究的问题,而不是分心去学习某个特定的技术或者如何写代码来实现它。

一些可以帮助你学习实验性的机器学习数据集的策略有:

  • 清晰地描述这个数据集所呈现的问题。
  • 用描述性的统计数据来总结数据。
  • 描述你从数据中观察到的结构,并且提出对数据间关系的假设。
  • 简单地在这个数据集上测试一些常用的机器学习算法,然后发掘哪些类别的算法比其他的表现好
  • 调整表现好的算法的参数,然后发掘什么算法及算法参数设置在这个问题上表现得好

你可以从这些包含高质量数据集的库中选择:  UCI ML Repository, Kaggle 和  data.gov.

3. 学习一个机器学习算法

选择一个算法,深入理解它,发掘什么样的参数设置在不同数据集上都稳定。

我推荐你从一个中等复杂度的算法开始学起。选一个已经被人充分理解了的,有许多可选的开源实现,并且需要你探索的参数数目较少的算法。你的目的是建立有关这个算法在不同问题和不同参数设定下表现如何的直觉。

使用一个机器学习平台或者类库。这样能让你把这个算法当成一个“系统”,专心研究它的表现,而不是分心研究数学公式描述或者相关论文。

一些学习你选定的机器学习算法时可采取的策略有:

  • 总结系统的参数,及它们对算法可能有什么影响
  • 选一系列适合这个算法,可能导致不同表现的数据库
  • 选择一些你认为能导致不同结果的算法的参数设置,然后列出你认为系统可能的表现
  • 考虑在迭代过程或不同时间段内能被监察到的算法表现
  • 用一个或多个数据集,算法设置和结果衡量方式来设计解决特定问题的小实验,并且汇报结果

你可以学简单点,也可以学复杂点。想多学一点的话,你可以探索所谓的启发式规则或经验法则来使用算法,并且以实验为依据来展示它们好不好用,及如果好用的话在什么条件下他们与成功的结果有关联。

一些你可以考虑学习的算法有:最小平方线性回归,逻辑回归,K最近邻分类算法,感知器算法。

4. 实现一个机器学习算法

选一个算法,然后选一个编程语言来实现它,或者把一个已有的实现移植到你选定的编程语言上。

你应选择一个中等复杂度的算法来实现。我推荐你仔细研究你想要实现的算法,或选择一个你喜欢的已有实现然后把它移植到你选定的编程语言。

从头开始实现一个算法,是学习那些关于把算法描述转换成一个可行的系统的过程中必须要做的无数的小决定的好方法。在不同算法上重复这个过程,很快你就能对读懂论文和书里面算法的数学描述有感觉了。

五个能帮助你从头开始实现机器学习算法的策略有:

  • 从代码移植开始。把开源的算法实现从一种语言移植到另外一种语言能教会你算法是如何实现的,并且你能拥有并掌握它。这是开始学习的最快的途径,非常值得推荐。
  • 从一个算法描述开始,然后采集一些其他的描述来帮助你排除歧义并且理解主要的那个参考材料。
  • 多读该算法的不同实现。学习不同程序员是如何理解算法描述并且如何把它转换成代码的。
  • 不要陷入过炫的方法太深。许多机器学习算法的内核用的都是高级优化算法。不要尝试重新实现这些方法,除非这就是你做这个项目的本意。你应该用一个提供优化算法的类库,或者用一个更容易实现的或者类库里就有的简单点的优化算法(如梯度下降算法)。

小型项目方法论

以上四个策略属于我称为“小型项目”的方法论。你用这个方法可以很快建立在技术领域(比如机器学习)方面的实用技能。大意就是你设计并且亲手完成解决特定问题的小项目。

小型项目在几个方面应该足够小,才能保证你能完成它们并且从中学习,然后好步入到下一个项目中去。下面是一些你应该考虑加在项目上的一些限制:

  • 时间短:一个项目从头到最后能有可展现的结果不应超过5-15 小时。这样利用一周中不上班的晚上和周末时间你就能完成一个小项目。
  • 范围小:一个项目应该有意义,但同时应该是你感兴趣的问题的范围最小的版本。举个例子,与其解决广义的“写一个能告诉我微博是否会被转发的程序”,还不如去研究这个问题在一个特定的账号在一个特定的时间段内的表现。
  • 所需资源少:一个项目应该能用你的可联网的台式或者笔记本电脑完成。你不应该需要奇葩的软件,网络架构,或者第三方数据或者服务。你应搜集需要的数据,读入内存,用开源工具来解决你那个小问题。

额外有关项目的小贴士

这些策略的原则是让你利用你的程序员技能开始行动。下面是三条帮助你调整思维模式,有助你开始行动的小贴士:

  • 写下你学到的东西。我推荐你每个步骤都产生一个有形的劳动成果。它可以是本子里的笔记,微博,博客文章或者是开源项目。每个劳动成果都可以作为一个里程碑或锚。
  • 除非项目的目的是写代码,否则不要写。这条不是那么显而易见,但却是最能帮助你加快理解机器学习的速度的建议。
  • 目的是学到东西,而不是产生独一无二的资源。不要管是否有人读你关于一个算法的研究、教程或是笔记。这些都是你的观点,是你的劳动成果,他们证明你现在掌握到了知识。

总结

下面是这些策略的一句话清晰总结,可以帮助你选择适合自己的那个。

  1. 学习一个机器学习工具:选择一个你喜欢的工具或类库,学习如何很好的使用它。。
  2. 学习一个机器学习数据集:选择一个数据集,深入地离家它,发掘哪类算法处理它最有效。
  3. 学习一个机器学习算法:选择一个算法,深入理解它,发掘什么样的参数设置在不同数据集上都稳定。
  4. 实现一个机器学习算法:选择一个算法,用你选定的语言实现它或者是把已有的实现移植到你选定的语言上。

选一个吧!

PDF 指导手册

如果你喜欢这篇自学策略文章,作者创建了一个 32 页的有关学习并实践应用机器学习的 PDF 指导手册。看这里:

小项目方法论:学习并实践应用机器学习

作者还创建了一个包含 90 个项目想法的清单,作为附加福利加在这个指导里面了。

英文原文: 4 Self-Study Machine Learning Projects
翻译:  伯乐在线 XiaoxiaoLi
译文链接:  http://blog.jobbole.com/67621/

Nutch1.8+Hadoop1.2+Solr4.3分布式集群配置

$
0
0
Nutch 是一个开源Java 实现的搜索引擎。它提供了我们运行自己的搜索引擎所需的全部工具。包括全文搜索和Web爬虫。当然在百度百科上这种方法在Nutch1.2之后,已经不再适合这样描述Nutch了,因为在1.2版本之后,Nutch专注的只是爬取数据,而全文检索的部分彻底的交给Lucene和Solr,ES来做了,当然因为他们都是近亲关系,所以Nutch抓取完后的数据,非常easy的就能生成全文索引。

下面散仙,进入正题,Nutch目前最新的版本是2.2.1,其中2.x的版本支持gora提供多种存储方式,1.x版本最新的是1.8只支持HDFS存储,散仙在这里用的还是Nutch1.8,那么,散仙为什么选择1.x系列呢? 这其实和自己的Hadoop环境有关系,2.x的Nutch用的Hadoop2.x的版本,当然如果你不嫌麻烦,你完全可以改改jar的配置,使Nutch2.x跑在Hadoop1.x的集群上。使用1.x的Nutch就可以很轻松的跑在1.x的hadoop里。下面是散仙,本次测试Nutch+Hadoop+Solr集群的配置情况:

序号名称职责描述
1Nutch1.8主要负责爬取数据,支持分布式
2Hadoop1.2.0使用MapReduce进行并行爬取,使用HDFS存储数据,Nutch的任务提交在Hadoop集群上,支持分布式
3Solr4.3.1主要负责检索,对爬完后的数据进行搜索,查询,海量数据支持分布式
4IK4.3主要负责,对网页内容与标题进行分词,便于全文检索
5Centos6.5Linux系统,在上面运行nutch,hadoop等应用
6Tomcat7.0应用服务器,给Solr提供容器运行
7JDK1.7提供JAVA运行环境
8Ant1.9提供Nutch等源码编译
9屌丝软件工程师一名主角



下面开始,正式的启程
1, 首先确保你的ant环境配置成功,一切的进行,最好在Linux下进行,windows上出问题的几率比较大,下载完的nutch源码,进入nutch的根目录下,执行ant,等待编译完成。编译完后,会有runtime目录,里面有Nutch启动的命令,local模式和deploy分布式集群模式






2, 配置nutch-site.xml加入如下内容:

<?xml version="1.0"?><?xml-stylesheet type="text/xsl" href="configuration.xsl"?><!-- Put site-specific property overrides in this file. --><configuration><property><name>http.agent.name</name><value>mynutch</value></property><property><name>http.robots.agents</name><value>mynutch,*</value><description>The agent strings we'll look for in robots.txt files,
  comma-separated, in decreasing order of precedence. You should
  put the value of http.agent.name as the first agent name, and keep the
  default * at the end of the list. E.g.: BlurflDev,Blurfl,*</description></property><property><name>plugin.folders</name><!--  local模式下使用下面的配置 --><value>./src/plugin</value><!--  集群模式下,使用下面的配置   --> <value>plugins</value> <!--  <value>D:\nutch编译好的1.8\Nutch1.8\src\plugin</value> --><description>Directories where nutch plugins are located.  Each
  element may be a relative or absolute path.  If absolute, it is used
  as is.  If relative, it is searched for on the classpath.</description></property></configuration>

3, 在hadoop集群上创建urls文件夹和mydir文件夹
,前者用于存储种子文件地址,后者存放爬取完后的数据。
hadoop fs -mkdir urls --创建文件夹
hadoop fs -put  HDFS路径 本地路径  --上传种子文件到HDFS上。
hadoop fs -ls  /      ---查看路径下内容


4,配置好hadoop集群,以及它的环境变量HADOOP_HOME这个很重要,Nutch运行时候,会根据Hadoop的环境变量,提交作业。

export  HADOOP_HOME=/root/hadoop1.2
export PATH=$HADOOP_HOME/bin:$PATH 
ANT_HOME=/root/apache-ant-1.9.2
export PATH USER LOGNAME MAIL HOSTNAME HISTSIZE HISTCONTROL
export JAVA_HOME=/root/jdk1.7
export PATH=$JAVA_HOME/bin:$ANT_HOME/bin:$PATH 
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar 

配置完成之后,可以使用which hadoop命令,检测是否配置正确:
[root@master bin]# which hadoop
/root/hadoop1.2/bin/hadoop
[root@master bin]# 

5, 配置solr服务,需要将Nutch的conf下的schema.xml文件,拷贝到solr的里面,覆盖掉solr原来的schema.xml文件,并加入IK分词,内容如下:

<?xml version="1.0" encoding="UTF-8" ?><!--
        Licensed to the Apache Software Foundation (ASF) under one or
        more contributor license agreements. See the NOTICE file
        distributed with this work for additional information regarding
        copyright ownership. The ASF licenses this file to You under the
        Apache License, Version 2.0 (the "License"); you may not use
        this file except in compliance with the License. You may obtain
        a copy of the License at
        http://www.apache.org/licenses/LICENSE-2.0 Unless required by
        applicable law or agreed to in writing, software distributed
        under the License is distributed on an "AS IS" BASIS, WITHOUT
        WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
        See the License for the specific language governing permissions
        and limitations under the License.
    --><!--
        Description: This document contains Solr 3.1 schema definition to
        be used with Solr integration currently build into Nutch. See
        https://issues.apache.org/jira/browse/NUTCH-442
        https://issues.apache.org/jira/browse/NUTCH-699
        https://issues.apache.org/jira/browse/NUTCH-994
        https://issues.apache.org/jira/browse/NUTCH-997
        https://issues.apache.org/jira/browse/NUTCH-1058
        https://issues.apache.org/jira/browse/NUTCH-1232
        and
        http://svn.apache.org/viewvc/lucene/dev/branches/branch_3x/solr/
        example/solr/conf/schema.xml?view=markup
        for more info.
    --><schema name="nutch" version="1.5"><types><fieldType name="string" class="solr.StrField" sortMissingLast="true"
            omitNorms="true"/> <fieldType name="long" class="solr.TrieLongField" precisionStep="0"
            omitNorms="true" positionIncrementGap="0"/><fieldType name="float" class="solr.TrieFloatField" precisionStep="0"
            omitNorms="true" positionIncrementGap="0"/><fieldType name="date" class="solr.TrieDateField" precisionStep="0"
            omitNorms="true" positionIncrementGap="0"/><!--  配置IK分词 --><fieldType name="ik" class="solr.TextField" positionIncrementGap="100"><analyzer type="index"><tokenizer class="org.wltea.analyzer.lucene.IKTokenizerFactory" useSmart="false" /><!-- in this example, we will only use synonyms at query time<filter class="solr.SynonymFilterFactory" synonyms="index_synonyms.txt" ignoreCase="true" expand="false"/>
        --><!-- <filter class="solr.LowerCaseFilterFactory"/> --></analyzer><analyzer type="query"><tokenizer class="org.wltea.analyzer.lucene.IKTokenizerFactory"  useSmart="false" /><!--<filter class="org.wltea.analyzer.lucene.IKSynonymFilterFactory" autoupdate="false" synonyms="synonyms.txt" flushtime="20"  /> --><!--<filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true"/> --><!--<filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true"/> --><!-- <filter class="solr.LowerCaseFilterFactory"/> --></analyzer></fieldType><fieldType name="text" class="solr.TextField" positionIncrementGap="100"><analyzer type="index"><tokenizer class="solr.StandardTokenizerFactory"/><filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt" enablePositionIncrements="true" /><!-- in this example, we will only use synonyms at query time<filter class="solr.SynonymFilterFactory" synonyms="index_synonyms.txt" ignoreCase="true" expand="false"/>
        --><filter class="solr.LowerCaseFilterFactory"/></analyzer><analyzer type="query"><tokenizer class="solr.StandardTokenizerFactory"/><filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt" enablePositionIncrements="true" /><filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true"/><filter class="solr.LowerCaseFilterFactory"/></analyzer></fieldType><fieldType name="url" class="solr.TextField"
            positionIncrementGap="100"><analyzer><tokenizer class="solr.StandardTokenizerFactory"/><filter class="solr.LowerCaseFilterFactory"/><filter class="solr.WordDelimiterFilterFactory"
                    generateWordParts="1" generateNumberParts="1"/></analyzer></fieldType></types><fields><field name="_version_" type="long" indexed="true" stored="true"/><field name="id" type="string" stored="true" indexed="true"/><!-- core fields --><field name="segment" type="string" stored="true" indexed="false"/><field name="text" type="string" stored="true" indexed="false"/><field name="digest" type="string" stored="true" indexed="false"/><field name="boost" type="float" stored="true" indexed="false"/><!-- fields for index-basic plugin --><field name="host" type="string" stored="false" indexed="true"/><field name="url" type="url" stored="true" indexed="true"
            required="true"/><field name="content" type="ik" stored="true" indexed="true"/><field name="title" type="ik" stored="true" indexed="true"/><field name="cache" type="string" stored="true" indexed="false"/><field name="tstamp" type="date" stored="true" indexed="false"/><!-- fields for index-anchor plugin --><field name="anchor" type="string" stored="true" indexed="true"
            multiValued="true"/><!-- fields for index-more plugin --><field name="type" type="string" stored="true" indexed="true"
            multiValued="true"/><field name="contentLength" type="long" stored="true"
            indexed="false"/><field name="lastModified" type="date" stored="true"
            indexed="false"/><field name="date" type="date" stored="true" indexed="true"/><!-- fields for languageidentifier plugin --><field name="lang" type="string" stored="true" indexed="true"/><!-- fields for subcollection plugin --><field name="subcollection" type="string" stored="true"
            indexed="true" multiValued="true"/><!-- fields for feed plugin (tag is also used by microformats-reltag)--><field name="author" type="string" stored="true" indexed="true"/><field name="tag" type="string" stored="true" indexed="true" multiValued="true"/><field name="feed" type="string" stored="true" indexed="true"/><field name="publishedDate" type="date" stored="true"
            indexed="true"/><field name="updatedDate" type="date" stored="true"
            indexed="true"/><!-- fields for creativecommons plugin --><field name="cc" type="string" stored="true" indexed="true"
            multiValued="true"/><!-- fields for tld plugin -->    <field name="tld" type="string" stored="false" indexed="false"/></fields><uniqueKey>id</uniqueKey><defaultSearchField>content</defaultSearchField><solrQueryParser defaultOperator="OR"/></schema>

6, 配置好后,进行nutch的/root/apache-nutch-1.8/runtime/deploy/bin目录下

执行如下命令:
./crawl urls mydir http://192.168.211.36:9001/solr/   2
启动集群抓取任务。
抓取中的MapReduce截图如下:


抓取完,我们就可以去solr中查看抓取的内容了,截图如下:


至此,一个简单的抓取,搜索系统就搞定了,非常轻松,使用都是Lucene系列开源的工程。

总结:配置过程中遇到几个比较典型的错误,记录如下:
java.lang.Exception: java.lang.RuntimeException: Error in configuring object
	at org.apache.hadoop.mapred.LocalJobRunner$Job.run(LocalJobRunner.java:354)
Caused by: java.lang.RuntimeException: Error in configuring object
	at org.apache.hadoop.util.ReflectionUtils.setJobConf(ReflectionUtils.java:93)
	at org.apache.hadoop.util.ReflectionUtils.setConf(ReflectionUtils.java:64)
	at org.apache.hadoop.util.ReflectionUtils.newInstance(ReflectionUtils.java:117)
	at org.apache.hadoop.mapred.MapTask.runOldMapper(MapTask.java:426)
	at org.apache.hadoop.mapred.MapTask.run(MapTask.java:366)
	at org.apache.hadoop.mapred.LocalJobRunner$Job$MapTaskRunnable.run(LocalJobRunner.java:223)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
	at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
	at java.util.concurrent.FutureTask.run(FutureTask.java:138)
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
	at java.lang.Thread.run(Thread.java:662)
Caused by: java.lang.reflect.InvocationTargetException
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at org.apache.hadoop.util.ReflectionUtils.setJobConf(ReflectionUtils.java:88)
	... 11 more
Caused by: java.lang.RuntimeException: Error in configuring object
	at org.apache.hadoop.util.ReflectionUtils.setJobConf(ReflectionUtils.java:93)
	at org.apache.hadoop.util.ReflectionUtils.setConf(ReflectionUtils.java:64)
	at org.apache.hadoop.util.ReflectionUtils.newInstance(ReflectionUtils.java:117)
	at org.apache.hadoop.mapred.MapRunner.configure(MapRunner.java:34)
	... 16 more
Caused by: java.lang.reflect.InvocationTargetException
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at org.apache.hadoop.util.ReflectionUtils.setJobConf(ReflectionUtils.java:88)
	... 19 more
Caused by: java.lang.RuntimeException: x point org.apache.nutch.net.URLNormalizer not found.
	at org.apache.nutch.net.URLNormalizers.<init>(URLNormalizers.java:123)
	at org.apache.nutch.crawl.Injector$InjectMapper.configure(Injector.java:74)
	... 24 more
2013-09-05 20:40:49,329 INFO  mapred.JobClient (JobClient.java:monitorAndPrintJob(1393)) -  map 0% reduce 0%
2013-09-05 20:40:49,332 INFO  mapred.JobClient (JobClient.java:monitorAndPrintJob(1448)) - Job complete: job_local1315110785_0001
2013-09-05 20:40:49,332 INFO  mapred.JobClient (Counters.java:log(585)) - Counters: 0
2013-09-05 20:40:49,333 INFO  mapred.JobClient (JobClient.java:runJob(1356)) - Job Failed: NA
Exception in thread "main" java.io.IOException: Job failed!
	at org.apache.hadoop.mapred.JobClient.runJob(JobClient.java:1357)
	at org.apache.nutch.crawl.Injector.inject(Injector.java:281)
	at org.apache.nutch.crawl.Crawl.run(Crawl.java:132)
	at org.apache.hadoop.util.ToolRunner.run(ToolRunner.java:65)
	at org.apache.nutch.crawl.Crawl.main(Crawl.java:55)
	==========================================================================解决方法:在nutch-site.xml里面加入如下配置。
	<property><name>plugin.folders</name><value>./src/plugin</value><description>Directories where nutch plugins are located.  Each
  element may be a relative or absolute path.  If absolute, it is used
  as is.  If relative, it is searched for on the classpath.</description></property>


在执行抓取的shell命令时,发现
使用 bin/crawl urls mydir http://192.168.211.36:9001/solr/   2 命令有时候会出现,一些HDFS上的目录不能正确访问的问题,所以推荐使用下面的这个命令:
./crawl urls mydir http://192.168.211.36:9001/solr/   2



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


ITeye推荐



js/jQuery插件开发及规范

$
0
0

当我们画出了UI之后就可以正式编写jQuery插件代码了,不过在着之前我们还需要对jQuery插件开发的一些规范性有一些了解。

 

1. 使用闭包:

(function($){
	//Code goes here
})(jQuery);

 这是来自jQuery官方的插件开发规范要求,使用这种编写方式有什么好处呢?

a) 避免全局依赖。

b) 避免第三方破坏。

c) 兼容jQuery操作符'$'和'jQuery'

我们知道这段代码在被解析时会形同如下代码:

var fun = function($) {
	//Code goes here
};
fun(jQuery);

 这样效果就一目了然了。

 

2. 扩展

jQuery提供了2个供用户扩展的‘基类’ - $.extend和$.fn.extend.

$.extend 用于扩展自身方法,如$.ajax, $.getJSON等,$.fn.extend则是用于扩展jQuery类,包括方法和对jQuery对象的操作。为了保持jQuery的完整性,我比较 趋向于使用$.fn.extend进行插件开发而尽量少使用$.extend.

 

3. 选择器

jQuery提供了功能强大,并兼容多种css版本的选择器,不过发现很多同学在使用选择器时并未注重效率的问题。

a) 尽量使用Id选择器,jQuery的选择器使用的API都是基于getElementById或getElementsByTagName,因此可以知道 效率最高的是Id选择器,因为jQuery会直接调用getElementById去获取dom,而通过样式选择器获取jQuery对象时往往会使用 getElementsByTagName去获取然后筛选。

b) 样式选择器应该尽量明确指定tagName, 如果开发人员使用样式选择器来获取dom,且这些dom属于同一类型,例如获取所有className为jquery的div,那么我们应该使用的写法 是$('div.jquery')而不是$('.jquery'),这样写的好处非常明显,在获取dom时jQuery会获取div然后进行筛选,而不是 获取所有dom再筛选。

c) 避免迭代,很多同学在使用jQuery获取指定上下文中的dom时喜欢使用迭代方式,如$('.jquery .child'),获取className为jquery的dom下的所有className为child的节点,其实这样编写代码付出的代价是非常大 的,jQuery会不断的进行深层遍历来获取需要的元素,即使确实需要,我们也应该使用诸如$(selector,context), $('selector1>selector2'), $(selector1).children(selector2), $(selctor1).find(selector2)之类的方式。

 

js插件开发的一种方法:

 

js代码:

<html><script language="javascript" src="jquery.js"></script><script type="text/javascript">
(function ($) {
	//默认参数(放在插件外面, 避免每次调用插件都调用一次, 节省内存)
	var defaults = {
		color: '红色'
	};
	//扩展
	$.fn.extend({
		//插件名称
		height: function(options) {
			//覆盖默认参数
			var opts = $.extend(defaults, options);
			//主函数
			return this.each(function(){
				//激活事件
				var obj = $(this);
				obj.click(function(){
					alert(opts.color);
				});
			});
		}
	});
})(jQuery);

$(function(){
	$("p").height({color: 'black'});
});</script><body><p>
	click here</p></body><html>

 

参考:http://www.360doc.com/content/14/0307/09/15605563_358431277.shtml



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


ITeye推荐



如何面试一名程序员?

$
0
0

STAR面试法中“STAR”是SITUATION(背景)、TASK(任务)、ACTION(行动)和RESULT(结果)四个英文字母的首字母组合。在招聘面试中,仅仅通过应聘者的简历无法全面了解应聘者的知识、经验、技能的掌握程度及其工作风格、性格特点等方面的情况。而使用STAR技巧则可以对应聘者做出全面而客观的评价。

  1. 了解 背景(SITUATION),通过不断提问与工作业绩有关的背景问题,可以全面了解该应聘者取得优秀业绩的前提,从而获知所取得的业绩有多少是与应聘者个人有关,多少是和市场的状况、行业的特点有关。
  2. 了解 任务(TASK),每项任务的具体内容是什么样的。通过这些可以了解应聘者的工作经历和经验,以确定他所从事的工作与获得的经验是否适合所空缺的职位。
  3. 了解 行动(ACTION),即了解他是如何完成工作的,都采取了哪些行动,所采取的行动是如何帮助他完成工作的。通过这些,可以进一步了解他的工作方式、思维方式和行为方式。
  4. 关注 结果(RESULT),每项任务在采取了行动之后的结果是什么,是好还是不好,好是因为什么,不好又是因为什么。

通过STAR式发问的四个步骤,一步步将应聘者的陈述引向深入,一步步挖掘出应聘者潜在的信息,通过应聘者过去的经历来预测其是否胜任目标职位。所以,确保应聘者提供的事件信息真实有效,就成了追问的另一目的。要通过得到更多、更详细的信息,来保证应聘者回答的真实性,因为所得到的结果越具体,说明事件越真实,做出的评价也就越准确。

面试其实说白了就是根据一个人之前的经历,来判断出后续这人会做得怎样,如果你之前从没做成过一件事情,凭什么让别人相信你之后能做成呢?因此无论哪里的面试都会问你之前做过的项目。需要注意的是两个平庸的项目不如做了一个好项目。针对STAR面试法设计的问题:

  1. 你做过最满意的项目是什么?可以是多人协助开发一个产品,也可以是自己个人做过的业余应用。
  2. 项目背景是什么?为什么要做这件事情?
  3. 你在项目中处于什么样的角色,起到了什么方面的作用?
  4. 在项目中遇到什么技术问题?具体是如何解决的?
  5. 此项目最终达到什么效果?
  6. 如果再做这个项目,你会在哪些方面进行改善?

除了STAR面试外,还需要对面试者的技能及其他内容做深入了解。比如技术相关问题,探测面试者基础知识的掌握程度及技术深度和广度的了解。技术相关问题:

  1. 描述一个你遇到过的技术问题,你是如何解决的?有没有遇到过很不常见的问题?比如在网上根本搜不到解决方法的?
  2. 是否有设计过通用的组件?你会提供什么接口?调用过程是怎样的?可能会遇到什么细节问题?
  3. 你最擅长的技术是什么?你觉得你在这个技术上的水平到什么程度了?你觉得最高级别应该是怎样的?
  4. 在制作一个Web应用或Web站点的过程中,你是如何考虑他的UI、安全性、高性能、SEO、可维护性以及技术因素的?
  5. 你最熟悉哪一套版本控制系统?

除此之外,还需要问一些非技术相关问题:

  1. 如果你参与到一个项目中,发现他们使用 Tab 来缩进代码,但是你喜欢空格,你会怎么做?
  2. 在之前做过的项目中,有没有什么功能或改进点是由你提出来的?是否有参与和改进其它开源项目?
  3. 编写代码的哪些方面能够使你兴奋或感兴趣?做什么方面的事情最让你有成就感?需求设计?规划?具体开发?
  4. 你在昨天/本周学到了什么?接下来半年你打算学习什么?如果今年你打算熟练掌握一项新技术,那会是什么?
  5. 后续想做什么?3 年后你希望自己是什么水平?

以上为个人梳理的面试的一些技巧。期望多多交流。

https单向/双向认证及tomcat配置https方法

$
0
0

https单向/双向认证及tomcat配置https方法
tomcat6配置:
1.单向认证,就是传输的数据加密过了,但是不会校验客户端的来源
2.双向认证,如果客户端浏览器没有导入客户端证书,是访问不了web系统的,找不到地址
如果只是加密,单向就行
如果想要用系统的人没有证书就访问不了系统的话,就采用双向

命令格式:
keytool -genkeypair -alias tomcat -keyalg RSA -keysize 1024 -dname "CN=localhost, OU=Organization, O=Company Name, L=City, S=State, C=US" -validity 365 -keystore  e:/tomcat.keystore

单向配置:
第一步:为服务器生成证书
使用keytool为Tomcat生成证书,假定目标机器的域名是“localhost”,keystore文件存放在“C:\OctopusStoreKey\SP2014.keystore”,口令为“123456”,使用如下命令生成:
keytool -genkey -v -alias SPClient -keyalg RSA -validity 3650 -keystore c:\OctopusStoreKey\SP2014.keystore

keytool -genkey -v -alias SPClient -keyalg RSA -validity 3650 -keystore c:\OctopusStoreKey\SP2014.keystore -dname "CN=localhost,OU=cn,O=cn,L=cn,ST=cn,c=cn" -storepass 123456 -keypass 123456

这个SP2014CA.cer是为了解决不信任时要导入的
keytool -genkey -v -alias SPClient -keyalg RSA -validity 3650 -keystore c:\OctopusStoreKey\SP2014.keystore

打开Tomcat 根目录下的 /conf/server.xml ,找到如下配置段,修改如下:

<Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol" SSLEnabled="true"  
               maxThreads="150" scheme="https" secure="true"  
    clientAuth="false" sslProtocol="TLS"  
    keystoreFile="c:\OctopusStoreKey\SP2014.keystore" keystorePass="123456" >

注意:protocol里面的值,如果用http 1.1,那么https的链接就会打不开
需要在应用程序的web.xml可以加上这句话

<login-config><!-- Authorization setting for SSL --><auth-method>CLIENT-CERT</auth-method><realm-name>Client Cert Users-only Area</realm-name></login-config><security-constraint><!-- Authorization setting for SSL --><web-resource-collection><web-resource-name>SSL</web-resource-name><url-pattern>/*</url-pattern></web-resource-collection><user-data-constraint><transport-guarantee>CONFIDENTIAL</transport-guarantee></user-data-constraint></security-constraint>

然后启动tomcat,输入 https://localhost:8443/
这时打开会弹出一个提示框:证书不可信任,有一个警告,说什么需要机构颁发。直接导入SP2014.keystore即可

双向配置:
第一步:为服务器生成证书
使用keytool为Tomcat生成证书,假定目标机器的域名是“localhost”,keystore文件存放在“C:\OctopusStoreKey\SP2014.keystore”,口令为“123456”,使用如下命令生成:
keytool -genkeypair -alias tomcat -keyalg RSA -keysize 1024 -dname "CN=localhost, OU=Organization, O=Company Name, L=City, S=State, C=US" -validity 365 -keystore  e:/tomcat.keystore

keytool -genkey -v -alias SPClient -keyalg RSA -validity 3650 -keystore c:\OctopusStoreKey\SP2014.keystore -dname "CN=localhost,OU=cn,O=cn,L=cn,ST=cn,c=cn" -storepass 123456 -keypass 123456

第二步:为客户端生成证书
下一步是为浏览器生成证书,以便让服务器来验证它。为了能将证书顺利导入至IE 和 Firefox ,证书格式应该是 PKCS12 ,因此,使用如下命令生成:
keytool -genkey -v -alias SP0200 -keyalg RSA -storetype PKCS12 -keystore c:\OctopusStoreKey\SP2014.p12(SP0200为自定义)。

keytool -genkey -v -alias SP0200 -keyalg RSA -storetype PKCS12 -validity 3650 -keystore c:\OctopusStoreKey\SP2014.p12 -dname "CN=SP0200,OU=cn,O=cn,L=cn,ST=cn,c=cn" -storepass 123456 -keypass 123456

双击SP2014.p12文件,即可将证书导入至浏览器(客户端)。

第三步:让服务器信任客户端证书
由于是双向SSL认证,服务器必须要信任客户端证书,因此,必须把客户端证书添加为服务器的信任认证。由于不能直接将PKCS12格式的证书库导入,必须先把客户端证书导出为一个单独的CER文件,使用如下命令:
keytool -export -alias SP0200 -keystore c:\OctopusStoreKey\SP2014.p12 -storetype PKCS12 -storepass 123456 -rfc -file C:\OctopusStoreKey\SP2014SubCA.cer

(SP0200为自定义与客户端定义的SP0200要一致,password是你设置的密码)。通过以上命令,客户端证书就被我们导出到“C:\OctopusStoreKey\SP2014SubCA.cer”文件了。

下一步,是将该文件导入到服务器的证书库,添加为一个信任证书使用命令如下:

     keytool -import -v -file C:\OctopusStoreKey\SP2014SubCA.cer -keystore C:\OctopusStoreKey\SP2014.keystore

通过list命令查看服务器的证书库,可以看到两个证书,一个是服务器证书,一个是受信任的客户端证书:

keytool -list -keystore C:\OctopusStoreKey\SP2014.keystore

第四步:配置Tomcat 服务器
打开Tomcat 根目录下的 /conf/server.xml ,找到如下配置段,修改如下:
<Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol" SSLEnabled="true"
               maxThreads="150" scheme="https" secure="true" clientAuth="true" sslProtocol="TLS"
    keystoreFile="C:\OctopusStoreKey\SP2014.keystore" keystorePass="123456"
    truststoreFile="C:\OctopusStoreKey\SP2014.keystore" truststorePass="123456"/>

(SP2014要与生成的服务端证书名一致)

属性说明:
clientAuth:设置是否双向验证,默认为false,设置为true代表双向验证
keystoreFile:服务器证书文件路径
keystorePass:服务器证书密码
truststoreFile:用来验证客户端证书的根证书,此例中就是服务器证书
truststorePass:根证书密码

应用程序的web.xml可以加上这句话:
<login-config><!-- Authorization setting for SSL --><auth-method>CLIENT-CERT</auth-method><realm-name>Client Cert Users-only Area</realm-name></login-config><security-constraint><!-- Authorization setting for SSL --><web-resource-collection><web-resource-name>SSL</web-resource-name><url-pattern>/*</url-pattern></web-resource-collection><user-data-constraint><transport-guarantee>CONFIDENTIAL</transport-guarantee></user-data-constraint></security-constraint><!--
Require HTTPS for everything except /img (favicon) and /css.
--><security-constraint><web-resource-collection><web-resource-name>HTTPSOrHTTP</web-resource-name><url-pattern>*.ico</url-pattern><url-pattern>/img/*</url-pattern><url-pattern>/css/*</url-pattern></web-resource-collection><user-data-constraint><transport-guarantee>NONE</transport-guarantee></user-data-constraint></security-constraint>
 
测试
在浏览器中输入:https://localhost:8443/,会弹出选择客户端证书界面,点击“确定”,会进入tomcat主页,地址栏后会有“锁”图标,表示本次会话已经通过HTTPS双向验证,接下来的会话过程中所传输的信息都已经过SSL信息加密。

 



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


ITeye推荐



Windows平台网站图片服务器架构的演进

$
0
0

  构建在Windows平台之上的网站,往往会被业内众多架构师认为很“保守”。很大部分原因,是由于微软技术体系的封闭和部分技术人员的短视造成的。由于长期缺乏开源支持,所以只能“闭门造车”,这样很容易形成思维局限性和短板。就拿图片服务器为例子,如果前期没有容量规划和可扩展的设计,那么随着图片文件的不断增多和访问量的上升,由于在性能、容错/容灾、扩展性等方面的设计不足,后续将会给开发、运维工作带来很多问题,严重时甚至会影响到网站业务正常运作和互联网公司的发展(这绝不是在危言耸听)。

  之所以选择Windows平台来构建网站和图片服务器,很大部分由创始团队的技术背景决定的,早期的技术人员可能更熟悉.NET,或者负责人认为Windows/.NET的易用性、“短平快”的开发模式、人才成本等方面都比较符合创业初期的团队,自然就选择了Windows。后期业务发展到一定规模,也很难轻易将整体架构迁移到其它平台上了。当然,对于构建大规模互联网,更建议首选开源架构,因为有很多成熟的案例和开源生态的支持,避免重复造轮子和支出授权费用。对于迁移难度较大的应用,比较推荐Linux、Mono、Mysql、Memcahed……混搭的架构,同样能支撑高并发访问和大数据量。

   单机时代的图片服务器架构(集中式)

  初创时期由于时间紧迫,开发人员水平也很有限等原因。所以通常就直接在website文件所在的目录下,建立1个upload子目录,用于保存用户上传的图片文件。如果按业务再细分,可以在upload目录下再建立不同的子目录来区分。例如:upload\QA,upload\Face等。

  在数据库表中保存的也是”upload/qa/test.jpg”这类相对路径。

  用户的访问方式如下:

  http://www.yourdomain.com/upload/qa/test.jpg

  程序上传和写入方式:

  程序员A通过在web.config中配置物理目录D:\Web\yourdomain\upload 然后通过stream的方式写入文件;

  程序员B通过Server.MapPath等方式,根据相对路径获取物理目录 然后也通过stream的方式写入文件。

  优点:实现起来最简单,无需任何复杂技术,就能成功将用户上传的文件写入指定目录。保存数据库记录和访问起来倒是也很方便。

  缺点:上传方式混乱,严重不利于网站的扩展。

  针对上述最原始的架构,主要面临着如下问题:

  1. 随着upload目录中文件越来越多,所在分区(例如D盘)如果出现容量不足,则很难扩容。只能停机后更换更大容量的存储设备,再将旧数据导入。
  2. 在部署新版本(部署新版本前通过需要备份)和日常备份website文件的时候,需要同时操作upload目录中的文件,如果考虑到访问量上升,后边部署由多台Web服务器组成的负载均衡集群,集群节点之间如果做好文件实时同步将是个难题。

   集群时代的图片服务器架构(实时同步)

  在website站点下面,新建一个名为upload的虚拟目录,由于虚拟目录的灵活性,能在一定程度上取代物理目录,并兼容原有的图片上传和访问方式。用户的访问方式依然是:

  http://www.yourdomain.com/upload/qa/test.jpg

  优点:配置更加灵活,也能兼容老版本的上传和访问方式。

  因为虚拟目录,可以指向本地任意盘符下的任意目录。这样一来,还可以通过接入外置存储,来进行单机的容量扩展。

  缺点:部署成由多台Web服务器组成的集群,各个Web服务器(集群节点)之间(虚拟目录下的)需要实时的去同步文件,由于同步效率和实时性的限制,很难保证某一时刻各节点上文件是完全一致的。

  基本架构如下图所示:

  从上图可看出,整个Web服务器架构已经具备“可扩展、高可用”了,主要问题和瓶颈都集中在多台服务器之间的文件同步上。

  上述架构中只能在这几台Web服务器上互相“增量同步”,这样一来,就不支持文件的“删除、更新”操作的同步了。

  早期的想法是,在应用程序层面做控制,当用户请求在web1服务器进行上传写入的同时,也同步去调用其它web服务器上的上传接口,这显然是得不偿失的。所以我们选择使用Rsync类的软件来做定时文件同步的,从而省去了“重复造轮子”的成本,也降低了风险性。

  同步操作里面,一般有比较经典的两种模型,即推拉模型:所谓“拉”,就是指轮询地去获取更新,所谓推,就是发生更改后主动的“推”给其它机器。当然,也可以采用加高级的事件通知机制来完成此类动作。

  在高并发写入的场景中,同步都会出现效率和实时性问题,而且大量文件同步也是很消耗系统和带宽资源的(跨网段则更明显)。

   集群时代的图片服务器架构改进(共享存储)

  沿用虚拟目录的方式,通过UNC(网络路径)的方式实现共享存储(将upload虚拟目录指向UNC)

  用户的访问方式1:

  http://www.yourdomain.com/upload/qa/test.jpg

  用户的访问方式2(可以配置独立域名):

  http://img.yourdomain.com/upload/qa/test.jpg

  支持UNC所在server上配置独立域名指向,并配置轻量级的web服务器,来实现独立图片服务器。

  优点: 通过UNC(网络路径)的方式来进行读写操作,可以避免多服务器之间同步相关的问题。相对来讲很灵活,也支持扩容/扩展。支持配置成独立图片服务器和域名访问,也完整兼容旧版本的访问规则。

  缺点 :但是UNC配置有些繁琐,而且会造成一定的(读写和安全)性能损失。可能会出现“单点故障”。如果存储级别没有raid或者更高级的灾备措施,还会造成数据丢失。

  基本架构如下图所示:

  在早期的很多基于Linux开源架构的网站中,如果不想同步图片,可能会利用NFS来实现。事实证明,NFS在高并发读写和海量存储方面,效率上存在一定问题,并非最佳的选择,所以大部分互联网公司都不会使用NFS来实现此类应用。当然,也可以通过Windows自带的DFS来实现,缺点是“配置复杂,效率未知,而且缺乏资料大量的实际案例”。另外,也有一些公司采用FTP或Samba来实现。

  上面提到的几种架构,在上传/下载操作时,都经过了Web服务器(虽然共享存储的这种架构,也可以配置独立域名和站点来提供图片访问,但上传写入仍然得经过Web服务器上的应用程序来处理),这对Web服务器来讲无疑是造成巨大的压力。所以,更建议使用独立的图片服务器和独立的域名,来提供用户图片的上传和访问。

   独立图片服务器/独立域名的好处

  • 图片访问是很消耗服务器资源的(因为会涉及到操作系统的上下文切换和磁盘I/O操作)。分离出来后,Web/App服务器可以更专注发挥动态处理的能力。
  • 独立存储,更方便做扩容、容灾和数据迁移。
  • 浏览器(相同域名下的)并发策略限制,性能损失。
  • 访问图片时,请求信息中总带cookie信息,也会造成性能损失。
  • 方便做图片访问请求的负载均衡,方便应用各种缓存策略(HTTP Header、Proxy Cache等),也更加方便迁移到CDN。

  ......

  我们可以使用Lighttpd或者Nginx等轻量级的web服务器来架构独立图片服务器。

   当前的图片服务器架构(分布式文件系统+CDN)

  在构建当前的图片服务器架构之前,可以先彻底撇开web服务器,直接配置单独的图片服务器/域名。但面临如下的问题:

  1. 旧图片数据怎么办?能否继续兼容旧图片路径访问规则?
  2. 独立的图片服务器上需要提供单独的上传写入的接口(服务API对外发布),安全问题如何保证?
  3. 同理,假如有多台独立图片服务器,是使用可扩展的共享存储方案,还是采用实时同步机制?

  直到应用级别的(非系统级) DFS(例如FastDFS HDFS MogileFs MooseFS、TFS)的流行,简化了这个问题:执行冗余备份、支持自动同步、支持线性扩展、支持主流语言的客户端api上传/下载/删除等操作,部分支持文件索引,部分支持提供Web的方式来访问。

  考虑到各DFS的特点,客户端API语言支持情况(需要支持C#),文档和案例,以及社区的支持度,我们最终选择了FastDFS来部署。

  唯一的问题是:可能会不兼容旧版本的访问规则。如果将旧图片一次性导入FastDFS,但由于旧图片访问路径分布存储在不同业务数据库的各个表中,整体更新起来也十分困难,所以必须得兼容旧版本的访问规则。架构升级往往比做全新架构更有难度,就是因为还要兼容之前版本的问题。(给飞机在空中换引擎可比造架飞机难得多)

   解决方案如下:

  首先,关闭旧版本上传入口(避免继续使用导致数据不一致)。将旧图片数据通过rsync工具一次性迁移到独立的图片服务器上(即下图中描述的Old Image Server)。在最前端(七层代理,如Haproxy、Nginx)用ACL(访问规则控制),将旧图片对应URL规则的请求(正则)匹配到,然后将请求直接转发指定的web 服务器列表,在该列表中的服务器上配置好提供图片(以Web方式)访问的站点,并加入缓存策略。这样实现旧图片服务器的分离和缓存,兼容了旧图片的访问规则并提升旧图片访问效率,也避免了实时同步所带来的问题。

  整体架构如图:

  基于FastDFS的独立图片服务器集群架构,虽然已经非常的成熟,但是由于国内“南北互联”和IDC带宽成本等问题(图片是非常消耗流量的),我们最终还是选择了商用的CDN技术,实现起来也非常容易,原理其实也很简单,我这里只做个简单的介绍:

  将img域名cname到CDN厂商指定的域名上,用户请求访问图片时,则由CDN厂商提供智能DNS解析,将最近的(当然也可能有其它更复杂的策略,例如负载情况、健康状态等)服务节点地址返回给用户,用户请求到达指定的服务器节点上,该节点上提供了类似Squid/Vanish的代理缓存服务,如果是第一次请求该路径,则会从源站获取图片资源返回客户端浏览器,如果缓存中存在,则直接从缓存中获取并返回给客户端浏览器,完成请求/响应过程。

  由于采用了商用CDN服务,所以我们并没有考虑用Squid/Vanish来重复构建前置代理缓存。

  上面的整个集群架构,可以很方便的做横向扩展,能满足一般垂直领域大型网站的图片服务需求(当然,像taobao这样超大规模的可能另当别论)。经测试,提供图片访问的单台Nginx服务器(至强E5四核CPU、16G内存、SSD),对小静态页面(压缩后的)可以扛住上万的并发且毫无压力。当然,由于图片本身体积比纯文本的静态页面大很多,提供图片访问的服务器的抗并发能力,往往会受限于磁盘的I/O处理能力和IDC提供的带宽。Nginx的抗并发能力还是非常强的,而且对资源占用很低,尤其是处理静态资源,似乎都不需要有过多担心了。可以根据实际访问量的需求,通过调整Nginx参数,Linux内核调优、缓存策略等手段做更大程度的优化,也可以通过增加服务器或者升级服务器配置来做扩展,最直接的是通过购买更高级的存储设备和更大的带宽,以满足更大访问量的需求。

  值得一提的是,在“云计算”流行的当下,也推荐高速发展期间的网站,使用“云存储”这样的方案,既能帮你解决各类存储、扩展、备灾的问题,又能做好CDN加速。最重要的是,价格也不贵。

  总结,有关图片服务器架构扩展,大致围绕这些问题展开:

  1. 容量规划和扩展问题。
  2. 数据的同步、冗余和容灾。
  3. 硬件设备的成本和可靠性(是普通机械硬盘,还是SSD,或者更高端的存储设备和方案)。
  4. 文件系统的选择。根据文件特性(例如文件大小、读写比例等)选择是用ext3/4或者NFS/GFS/TFS这些开源的(分布式)文件系统。
  5. 图片的加速访问。采用商用CDN或者自建的代理缓存、web静态缓存架构。
  6. 旧图片路径和访问规则的兼容性,应用程序层面的可扩展,上传和访问的性能和安全性等。

   作者介绍

  丁浪,技术架构师。擅长大规模(高并发、高可用、海量数据)互联网架构,专注于打造“高性能,可扩展/伸缩,稳定,安全”的技术架构。 热衷于技术研究和分享,曾分享和独立撰写过大量技术文章。


MapReduce编程实战之“高级特性”

$
0
0


本篇介绍MapReduce的一些高级特性,如计数器、数据集的排序和连接。计数器是一种收集作业统计信息的有效手段,排序是MapReduce的核心技术,MapReduce也能够执行大型数据集间的“”连接(join)操作。


计数器


计数器是一种收集作业统计信息的有效手段,用于质量控制或应用级统计。计数器还可用于辅助诊断系统故障。对于大型分布式系统来说,获取计数器比分析日志文件容易的多。


示例一:气温缺失及不规则数据计数器


import java.io.IOException;
import java.util.Iterator;

import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.io.*;
import org.apache.hadoop.mapred.JobClient;
import org.apache.hadoop.mapred.JobConf;
import org.apache.hadoop.mapred.MapReduceBase;
import org.apache.hadoop.mapred.Mapper;
import org.apache.hadoop.mapred.OutputCollector;
import org.apache.hadoop.mapred.Reducer;
import org.apache.hadoop.mapred.Reporter;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;

//统计最高气温的作业,也统计气温值缺少的记录,不规范的记录
public class MaxTemperatureWithCounters extends Configured implements Tool {

	enum Temperature {
		MiSSING, MALFORMED
	}

	static class MaxTemeratureMapperWithCounters extends MapReduceBase implements
			Mapper<LongWritable, Text, Text, IntWritable> {

		private NcdcRecordParser parser = new NcdcRecordParser();

		@Override
		public void map(LongWritable key, Text value,
				OutputCollector<Text, IntWritable> output, Reporter reporter)
				throws IOException {
			parser.parse(value);
			if (parser.isValidTemperature()) {
				int airTemperature = parser.getAirTemperature();
				output.collect(new Text(parser.getYear()), new IntWritable(
						airTemperature));
			} else if (parser.isMa1formedTemperature()) {
				reporter.incrCounter(Temperature.MALFORMED, 1);
			} else if (parser.IsMissingTemperature()) {
				reporter.incrCounter(Temperature.MALFORMED, 1);
			}

		}

	}

	static class MaxTemperatureReduceWithCounters extends MapReduceBase implements
			Reducer<Text, IntWritable, Text, IntWritable> {
		public void reduce(Text key, Iterator<IntWritable> values,
				OutputCollector<Text, IntWritable> output, Reporter reporter)
				throws IOException {
			int maxValue = Integer.MIN_VALUE;
			while (values.hasNext()) {
				maxValue = Math.max(maxValue, values.next().get());
			}
			output.collect(key, new IntWritable(maxValue));

		}
	}

	@Override
	public int run(String[] args) throws Exception {
		args = new String[] { "/test/input/t", "/test/output/t" }; // 给定输入输出路径
		JobConf conf = JobBuilder.parseInputAndOutput(this, getConf(), args);
		if (conf == null) {
			return -1;
		}
		conf.setOutputKeyClass(Text.class);
		conf.setOutputValueClass(IntWritable.class);
		conf.setMapperClass(MaxTemeratureMapperWithCounters.class);
		conf.setCombinerClass(MaxTemperatureReduceWithCounters.class);
		conf.setReducerClass(MaxTemperatureReduceWithCounters.class);
		JobClient.runJob(conf);
		return 0;
	}

	public static void main(String[] args) throws Exception {
		int exitCode = ToolRunner.run(new MaxTemperatureWithCounters(), args);
		System.exit(exitCode);
	}
}

示例二:统计气温信息缺失记录所占比例


import org.apache.hadoop.conf.*;
import org.apache.hadoop.mapred.*;
import org.apache.hadoop.util.*;
//统计气温缺失记录所占比例

public class MissingTemperatureFields extends Configured implements Tool {

	@Override
	public int run(String[] args) throws Exception {
		String jobID = args[0];
		JobClient jobClient = new JobClient(new JobConf(getConf()));
		RunningJob job = jobClient.getJob(JobID.forName(jobID));
		if (job == null) {
			System.err.printf("No job with ID %s found.\n", jobID);
			return -1;
		}
		if (!job.isComplete()) {
			System.err.printf("Job %s is not complete.\n", jobID);
			return -1;
		}
		Counters counters = job.getCounters();
		long missing = counters
				.getCounter(MaxTemperatureWithCounters.Temperature.MiSSING);
		long total = counters.findCounter("org.apache.hadoop.mapred.Task$Counter", "MAP_INPUT_RECORDS")
				.getCounter();
		System.out.printf("Records with missing temperature fields:%.2f%%\n",
				100.0 * missing / total);
		return 0;
	}

	public static void main(String[] args) throws Exception {
		int exitCode = ToolRunner.run(new MissingTemperatureFields(), args);
		System.exit(exitCode);
	}
}

hadoop jar xx.jar MissingTemperatureFields job_1400072670556_0001


排序


排序是MapReduce的核心技术。尽管应用本身可能并不需要对数据排序,但仍可能使用MapReduce的排序功能来组织数据。下面将讨论几种不同的数据集排序方法,以及如何控制MapReduce的排序。


实例一、数据准备:将天气数据转成顺序文件格式


import java.io.IOException;

import org.apache.hadoop.conf.*;
import org.apache.hadoop.io.*;
import org.apache.hadoop.io.SequenceFile.CompressionType;
import org.apache.hadoop.io.compress.GzipCodec;
import org.apache.hadoop.mapred.*;
import org.apache.hadoop.util.*;

public class SortDataPreprocessor extends Configured implements Tool {
	static class CleanerMapper extends MapReduceBase implements
			Mapper<LongWritable, Text, IntWritable, Text> {

		private NcdcRecordParser parser = new NcdcRecordParser();

		@Override
		public void map(LongWritable key, Text value,
				OutputCollector<IntWritable, Text> output, Reporter reporter)
				throws IOException {
			parser.parse(value);
			if (parser.isValidTemperature()) {
				output.collect(new IntWritable(parser.getAirTemperature()),
						value);
			}
		}
	}

	@Override
	public int run(String[] args) throws Exception {
		args = new String[] { "/test/input/t", "/test/input/seq" };
		JobConf conf = JobBuilder.parseInputAndOutput(this, getConf(), args);
		if (conf == null) {
			return -1;
		}
		conf.setMapperClass(CleanerMapper.class);
		conf.setOutputKeyClass(IntWritable.class);
		conf.setOutputValueClass(Text.class);
		conf.setNumReduceTasks(0);
		conf.setOutputFormat(SequenceFileOutputFormat.class);
		SequenceFileOutputFormat.setCompressOutput(conf, true);
		SequenceFileOutputFormat
				.setOutputCompressorClass(conf, GzipCodec.class);
		SequenceFileOutputFormat.setOutputCompressionType(conf,
				CompressionType.BLOCK);
		JobClient.runJob(conf);
		return 0;
	}

	public static void main(String[] args) throws Exception {
		int exitCode = ToolRunner.run(new SortDataPreprocessor(), args);
		System.exit(exitCode);
	}
}

示例二、部分排序


import org.apache.hadoop.conf.*;
import org.apache.hadoop.io.*;
import org.apache.hadoop.io.SequenceFile.CompressionType;
import org.apache.hadoop.io.compress.GzipCodec;
import org.apache.hadoop.mapred.*;
import org.apache.hadoop.util.*;

public class SortByTemperatureUsingHashPartitioner extends Configured implements
		Tool {

	@Override
	public int run(String[] args) throws Exception {
		args = new String[] { "/test/input/seq", "/test/output/t" };
		JobConf conf = JobBuilder.parseInputAndOutput(this, getConf(), args);
		if (conf == null) {
			return -1;
		}
		conf.setInputFormat(SequenceFileInputFormat.class);
		conf.setOutputKeyClass(IntWritable.class);
		conf.setOutputFormat(SequenceFileOutputFormat.class);
		conf.setNumReduceTasks(5);//设置5个reduce任务,输出5个文件
		SequenceFileOutputFormat.setCompressOutput(conf, true);
		SequenceFileOutputFormat
				.setOutputCompressorClass(conf, GzipCodec.class);
		SequenceFileOutputFormat.setOutputCompressionType(conf,
				CompressionType.BLOCK);
		JobClient.runJob(conf);
		return 0;
	}

	public static void main(String[] args) throws Exception {
		int exitCode = ToolRunner.run(
				new SortByTemperatureUsingHashPartitioner(), args);
		System.exit(exitCode);
	}

}

hadoop jar test.jar SortByTemperatureUsingHashPartitioner -D mapred.reduce.tasks=30

产生多个已经排好序的小文件。


连接


MapReduce能够执行大型数据集间的“”连接(join)操作,但是从头编写相关代码来执行连接比较麻烦。也可以考虑使用一个更高级的框架,如Pig、Hive或Casading等,它们都将连接操作视为整个实现的核心部分。


本章的代码用到的基础工具类


其他章节也可能用到:)


JobBuilder


import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.mapred.FileInputFormat;
import org.apache.hadoop.mapred.FileOutputFormat;
import org.apache.hadoop.mapred.JobConf;
import org.apache.hadoop.util.Tool;

public class JobBuilder {

	public static JobConf parseInputAndOutput(Tool tool, Configuration conf,
			String[] args) {
		if (args.length != 2) {
			printUsage(tool, "<input><output>");
			return null;
		}
		JobConf jobConf = new JobConf(conf, tool.getClass());
		FileInputFormat.addInputPath(jobConf, new Path(args[0]));
		FileOutputFormat.setOutputPath(jobConf, new Path(args[1]));
		return jobConf;
	}

	public static void printUsage(Tool tool, String extraArgsUsage) {
		System.err.printf("Usage:%s [genericOptions] %s\n\n", tool.getClass()
				.getSimpleName(), extraArgsUsage);
	}
}

NcdcRecordParser

 

import org.apache.hadoop.io.Text;

public class NcdcRecordParser {
	private static final int MISSING_TEMPERATURE = 9999;

	private String year;
	private int airTemperature;
	private String quality;

	public void parse(String record) {
		year = record.substring(15, 19);
		String airTemperatureString;
		// Remove leading plus sign as parseInt doesn't like them
		if (record.charAt(87) == '+') {
			airTemperatureString = record.substring(88, 92);
		} else {
			airTemperatureString = record.substring(87, 92);
		}
		airTemperature = Integer.parseInt(airTemperatureString);
		quality = record.substring(92, 93);
	}

	public void parse(Text record) {
		parse(record.toString());
	}

	public boolean isValidTemperature() {
		return airTemperature != MISSING_TEMPERATURE
				&& quality.matches("[01459]");
	}

	public boolean isMa1formedTemperature() {
		return !quality.matches("[01459]");
	}

	public boolean IsMissingTemperature() {
		return airTemperature == MISSING_TEMPERATURE;
	}

	public String getYear() {
		return year;
	}

	public int getAirTemperature() {
		return airTemperature;
	}
}

这一篇是《Hadoop权威指南》第八章的学习笔记,好久没看Hadoop,工作中也没使用,前不久学习的东西,忘记了很多。学以致用是非常重要的,没用应用的学习,最终会忘记大部分,感兴趣的就需要多多温习了。
作者:puma_dong 发表于2014-5-14 22:20:53 原文链接
阅读:78 评论:0 查看评论

select、poll、epoll之间的区别总结

$
0
0

select、poll、epoll之间的区别总结

  • 05/05. 2014

select,poll,epoll都是IO多路复用的机制。I/O多路复用就通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。 但select,poll,epoll本质上都是同步I/O,因为他们都需要在读写事件就绪后自己负责进行读写,也就是说这个读写过程是阻塞的,而异步I/O则无需自己负责进行读写,异步I/O的实现会负责把数据从内核拷贝到用户空间。关于这三种IO多路复用的用法,前面三篇总结写的很清楚,并用服务器回射echo程序进行了测试。连接如下所示:

select: http://www.cnblogs.com/Anker/archive/2013/08/14/3258674.html

poll: http://www.cnblogs.com/Anker/archive/2013/08/15/3261006.html

epoll: http://www.cnblogs.com/Anker/archive/2013/08/17/3263780.html

今天对这三种IO多路复用进行对比,参考网上和书上面的资料,整理如下:

1、select实现

select的调用过程如下所示:

a1

 

(1)使用copy_from_user从用户空间拷贝fd_set到内核空间

(2)注册回调函数__pollwait

(3)遍历所有fd,调用其对应的poll方法(对于socket,这个poll方法是sock_poll,sock_poll根据情况会调用到tcp_poll,udp_poll或者datagram_poll)

(4)以tcp_poll为例,其核心实现就是__pollwait,也就是上面注册的回调函数。

(5)__pollwait的主要工作就是把current(当前进程)挂到设备的等待队列中,不同的设备有不同的等待队列,对于tcp_poll来说,其等待队列是sk->sk_sleep(注意把进程挂到等待队列中并不代表进程已经睡眠了)。在设备收到一条消息(网络设备)或填写完文件数据(磁盘设备)后,会唤醒设备等待队列上睡眠的进程,这时current便被唤醒了。

(6)poll方法返回时会返回一个描述读写操作是否就绪的mask掩码,根据这个mask掩码给fd_set赋值。

(7)如果遍历完所有的fd,还没有返回一个可读写的mask掩码,则会调用schedule_timeout是调用select的进程(也就是current)进入睡眠。当设备驱动发生自身资源可读写后,会唤醒其等待队列上睡眠的进程。如果超过一定的超时时间(schedule_timeout指定),还是没人唤醒,则调用select的进程会重新被唤醒获得CPU,进而重新遍历fd,判断有没有就绪的fd。

(8)把fd_set从内核空间拷贝到用户空间。

总结:

select的几大缺点:

(1)每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大

(2)同时每次调用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大

(3)select支持的文件描述符数量太小了,默认是1024

2 poll实现

poll的实现和select非常相似,只是描述fd集合的方式不同,poll使用pollfd结构而不是select的fd_set结构,其他的都差不多。

关于select和poll的实现分析,可以参考下面几篇博文:

http://blog.csdn.net/lizhiguo0532/article/details/6568964#comments

http://blog.csdn.net/lizhiguo0532/article/details/6568968

http://blog.csdn.net/lizhiguo0532/article/details/6568969

http://www.ibm.com/developerworks/cn/linux/l-cn-edntwk/index.html?ca=drs-

http://linux.chinaunix.net/techdoc/net/2009/05/03/1109887.shtml

3、epoll

epoll既然是对select和poll的改进,就应该能避免上述的三个缺点。那epoll都是怎么解决的呢?在此之前,我们先看一下epoll和select和poll的调用接口上的不同,select和poll都只提供了一个函数——select或者poll函数。而epoll提供了三个函数,epoll_create,epoll_ctl和epoll_wait,epoll_create是创建一个epoll句柄;epoll_ctl是注册要监听的事件类型;epoll_wait则是等待事件的产生。

对于第一个缺点,epoll的解决方案在epoll_ctl函数中。每次注册新的事件到epoll句柄中时(在epoll_ctl中指定EPOLL_CTL_ADD),会把所有的fd拷贝进内核,而不是在epoll_wait的时候重复拷贝。epoll保证了每个fd在整个过程中只会拷贝一次。

对于第二个缺点,epoll的解决方案不像select或poll一样每次都把current轮流加入fd对应的设备等待队列中,而只在epoll_ctl时把current挂一遍(这一遍必不可少)并为每个fd指定一个回调函数,当设备就绪,唤醒等待队列上的等待者时,就会调用这个回调函数,而这个回调函数会把就绪的fd加入一个就绪链表)。epoll_wait的工作实际上就是在这个就绪链表中查看有没有就绪的fd(利用schedule_timeout()实现睡一会,判断一会的效果,和select实现中的第7步是类似的)。

对于第三个缺点,epoll没有这个限制,它所支持的FD上限是最大可以打开文件的数目,这个数字一般远大于2048,举个例子,在1GB内存的机器上大约是10万左右,具体数目可以cat /proc/sys/fs/file-max察看,一般来说这个数目和系统内存关系很大。

总结:

(1)select,poll实现需要自己不断轮询所有fd集合,直到设备就绪,期间可能要睡眠和唤醒多次交替。而epoll其实也需要调用epoll_wait不断轮询就绪链表,期间也可能多次睡眠和唤醒交替,但是它是设备就绪时,调用回调函数,把就绪fd放入就绪链表中,并唤醒在epoll_wait中进入睡眠的进程。虽然都要睡眠和交替,但是select和poll在“醒着”的时候要遍历整个fd集合,而epoll在“醒着”的时候只要判断一下就绪链表是否为空就行了,这节省了大量的CPU时间。这就是回调机制带来的性能提升。

(2)select,poll每次调用都要把fd集合从用户态往内核态拷贝一次,并且要把current往设备等待队列中挂一次,而epoll只要一次拷贝,而且把current往等待队列上挂也只挂一次(在epoll_wait的开始,注意这里的等待队列并不是设备等待队列,只是一个epoll内部定义的等待队列)。这也能节省不少的开销。

参考资料:

http://www.cnblogs.com/apprentice89/archive/2013/05/09/3070051.html

http://www.linuxidc.com/Linux/2012-05/59873p3.htm

http://xingyunbaijunwei.blog.163.com/blog/static/76538067201241685556302/

http://blog.csdn.net/kkxgx/article/details/7717125

https://banu.com/blog/2/how-to-use-epoll-a-complete-example-in-c/epoll-example.c

本文来自: http://www.cnblogs.com/Anker/p/3265058.html



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


ITeye推荐



理解前端开发中的优雅降级及渐进增强

$
0
0

在前端开发中,遇到最麻烦的事情就是浏览器的兼容性问题。对于这个问题的解决,通常有如下两种思路:

优雅降级

优雅降级指的是一开始就构建站点的完整功能,然后针对浏览器测试和修复。

“优雅降级”观点认为应该针对那些最高级、最完善的浏览器来开发网站。而将那些被认为“过时”或有功能缺失的浏览器下的测试工作安排在开发周期的最后阶段,并把测试对象限定为主流浏览器(如 IE、Mozilla 等)的前一个版本。在这种设计范例下,旧版的浏览器被认为仅能提供“简陋却无妨 (poor, but passable)” 的浏览体验。你可以做一些小的调整来适应某个特定的浏览器。但由于它们并非我们所关注的焦点,因此除了修复较大的错误之外,其它的差异将被直接忽略。

渐进增强

渐进增强一开始只构建站点的最少特性,然后不断针对各浏览器追加功能。

我们应该先让网站能够正常工作于尽可能旧的浏览器上,然后不断为它在新型浏览器上实现更多的增强和改进。随着时间的推移,当越来越多的人开始升级浏览器而浏览器本身的支持度也不断提升时,就会有越来越多的人体验到这些增强和改进,它持续有效的使网站越来越好,却如需你刻意做什么。只需要一次实现,它就让网站的体验与时俱进。

使用渐进增强时,无需为了一个已成型的网站在旧式浏览器下正常工作而做逆向工程。首先,只需要为所有的设备和浏览器准备好清晰且语义化的 HTML 以及完善的内容,然后再以无侵入(unobtrusive)的方式向页面增加无害于基础浏览器的额外样式和功能。当浏览器升级时,它们会自动地呈现出来并发挥作用。

“渐进增强”观点认为应关注于内容本身。内容是我们建立网站的诱因。有的网站展示它,有的则收集它,有的寻求,有的操作,还有的网站甚至会包含以上的种种,但相同点是它们全都涉及到内容。这使得“渐进增强”成为一种更为合理的设计范例。这也是它立即被 Yahoo! 所采纳并用以构建其“ 分级式浏览器支持 (Graded Browser Support)”策略的原因所在。

两个之间的区别

对于优雅降级,功能衰减是从复杂的现状开始,并试图减少用户体验的供给,而渐进增强则是从一个非常基础的,能够起作用的版本开始,并不断扩充,以适应未来环境的需要。功能衰减意味着往回看;而渐进增强则意味着朝前看,同时保证其根基处于安全地带。

“它们是看待同种事物的两种观点”。“优雅降级”和“渐进增强”都关注于同一网站在不同设备里不同浏览器下的表现程度。关键的区别则在于它们各自关注于何处,以及这种关注如何影响工作的流程。

本文链接

oracle表之间的连接之------>排序合并连接(Merge Sort Join)

$
0
0

排序合并连接 (Sort Merge Join)是一种两个表在做连接时用排序操作(Sort)和合并操作(Merge)来得到连接结果集的连接方法。

对于排序合并连接的优缺点及适用场景如下:

a,通常情况下,排序合并连接的执行效率远不如哈希连接,但前者的使用范围更广,因为哈希连接只能用于等值连接条件,而排序合并连接还能用于其他连接条件(如<,<=,>.>=)

b,通常情况下,排序合并连接并不适合OLTP类型的系统,其本质原因是对于因为OLTP类型系统而言,排序是非常昂贵的操作,当然,如果能避免排序操作就例外了。

 

oracle表之间的连接之排序合并连接(Merge Sort Join),其特点如下:

1,驱动表和被驱动表都是最多只被访问一次。

2,排序合并连接的表无驱动顺序。

3,排序合并连接的表需要排序,用到SORT_AREA_SIZE。

4,排序合并连接不适用于的连接条件是:不等于<>,like,其中大于>,小于<,大于等于>=,小于等于<=,是可以适用于排序合并连接

5,排序合并连接,如果有索引就可以排除排序。

 

下面我来做个实验来证实如上的结论:

具体的测试基础表请查看本人Blog 如下链接:

oracle表连接之----〉嵌套循环(Nested Loops Join)

SQL> select /*+ ordered use_merge(t2)*/ * from t1,t2 where t1.id=t2.t1_id;

SQL> select sql_id, child_number, sql_text from v$sql where sql_text like '%use_merge%';
 
SQL_ID        CHILD_NUMBER SQL_TEXT
------------- ------------ --------------------------------------------------------------------------------
85u4h9hfqa5ar            0  select sql_id, child_number, sql_text from v$sql where sql_text like '%use_merg
6xph9fhapys39            0  select /*+ ordered use_merge(t2)*/ * from t1,t2 where t1.id=t2.t1_id
 
SQL> select * from table(dbms_xplan.display_cursor('6xph9fhapys39',0,'allstats last'));
 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
SQL_ID  6xph9fhapys39, child number 0
-------------------------------------
 select /*+ ordered use_merge(t2)*/ * from t1,t2 where t1.id=t2.t1_id
Plan hash value: 412793182
--------------------------------------------------------------------------------
| Id  | Operation           | Name | Starts | E-Rows | A-Rows |   A-Time   | Buf
--------------------------------------------------------------------------------
|   1 |  MERGE JOIN         |      |      1 |    100 |    100 |00:00:00.07 |
|   2 |   SORT JOIN         |      |      1 |    100 |    100 |00:00:00.01 |
|   3 |    TABLE ACCESS FULL| T1   |      1 |    100 |    100 |00:00:00.01 |
|*  4 |   SORT JOIN         |      |    100 |    100K|    100 |00:00:00.07 |
|   5 |    TABLE ACCESS FULL| T2   |       1 |    100K|    100K|00:00:00.01 |
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   4 - access("T1"."ID"="T2"."T1_ID")
 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
       filter("T1"."ID"="T2"."T1_ID")
Note
-----
   - dynamic sampling used for this statement
 
26 rows selected

从上面的实验可以看出排序合并连接和HASH连接时一样的,T1和T2 表都只会被访问0次或者1次。

select /*+ ordered use_merge(t2)*/ * from t1,t2 where t1.id=t2.t1_id and 1=2;此语句T1和T2表就会是被访问0次。自己可以做试验测试下。

总结:排序合并连接根本就没有驱动和被驱动表的概念,而嵌套循环连接和哈希连接就要考虑驱动和被驱动表的情况!!

作者:waterxcfg304 发表于2014-5-15 14:23:54 原文链接
阅读:43 评论:0 查看评论

每个程序员都必读的10篇文章

$
0
0

作为一名Java程序员和软件开发人员,那些 每个程序员都应该知道的XXX的文章教会了我不少东西,它们提供了某个特定领域的一些实用的并且有深度的信息,这些东西通常很难找到。在我学习的过程中我读到过许多非常有用的文章,我把它们添加到了书签里,方便以后阅读或者引用。我个人认为所有开发人员都能从这些文章中受益,因此我也写了篇“ 每个程序员都应该了解的”文章,准备分享给你们。这是我的个人收藏。在这篇文章中,你会看到每个程序员都应该了解的一些经典文章,涵盖了内存,unicode,浮点数,网络,面向对象设计,时间,URL编码,字符串等话题。这个列表对初学者和新手来说非常重要,因为他们现在缺的正是实战的经验。而这些文章正好是实践相关的,他们可以从中学到很多东西。在职业生涯的初级,早点了解一些基础的知识有助于今后避免犯错,这些坑已经被其他的程序员和软件开发人员在他们学习的过程中踩过了。你可能还搞不明白浮点数的一些细节,或者被内存的细节弄得晕头转向,不过将这份列表保留在手边还是很有必要的,在适当的时候可以时不时的参考下。祝你好运,希望你能喜欢这些文章。顺便提一句,如果有任何的程序员必读系列的文章没在这个列表中,别忘了分享一下。

  1. 程序员必知之内存篇

这是篇非常经典的文章,它将会带领你走入内存的各个方面,有老的,也有新的,有知道的,也有不知道的。尽管内存十分常见,无处不在,但并不是每个程序员都足够了解它。如果你正在编写高性能的应用程序的话,了解现代系统中的内存尤为重要。硬件设计师们带来了更复杂的内存处理及加速的技术,比如说CPU缓存,但如果离开了程序员它们也无法发挥出最大的价值。我仍在阅读这篇文章,很难说清楚我到底从中学到了多少关于随机访问内存(RAM),CPU缓存,包括1级,2级缓存,不同类型的内存,直接内存访问,内存控制器设计及普通内存的知识。简而言之,它是各个层次的程序员都必读的文章。

  1. 每个计算机科学家都必知之浮点数运算

浮点数运算是一个非常有技术含量的话题,不太容易掌握。许多Java程序员都不清楚使用==操作符比较float/double类型的话到底出现什么问题。许多人在使用float/double进行货币计算的时候经常会犯错。这篇文章是这一系列中的精华,所有的软件开发人员都应该读一下。随着你经验的增长,你肯定想去深入了解一些常见的东西的细节,浮点数运算就是其中之一。作为一名Java高级开发人员,你必须了解如何进行货币运算,何时使用float,double或者BigDecimal,如何对浮点数进行舍入运算等等。就算你知道了浮点数运算的一些基础知识,读下这篇文章,你肯定还会学到一些新的东西。

  1. 每个程序员必知之Unicode篇

字符编码是另一个许多程序员痛苦挣扎的领域,” 每一个程序员都绝对绝对应该了解Unicode以及字符集(不许找任何借口!)“填补了这一空白。标注一下,是的,这就是这篇文章的标题。它是由stackoverflow.com的创始人之一,Joel Spolsky所写的。Joel10年前就在他的博客上发表了这篇文章,不过对于现在而言仍然适用。这篇文章会告诉你什么是Unicode,什么是字符编码,字符是如何通过字节来表示的等等。这篇文章最赞的一点就是它的语言及行文,尽管你根本不知道什么是Unicode,你也能够很容易地看懂。一句话,这又是一篇程序员,码农,软件工程师必读的文章。

  1. 每个程序员必知之时间篇

除了字符编码外,时间和日期又是另一个程序员经常栽倒的领域,包括我自己在内。甚至是高级开发人员也会被格林尼治标准时间(GMT),世界标准时间(UTC),夏令时,闰秒这些东西搞的死去活来。坦白地说,在处理时区这个问题上,很难不踩一些坑,更别说再加上夏令时什么的。如果你想要试错法的话则更糟糕,因为这么做永远也解决不了你的问题。这里有许多可能出错或者产生误解的地方。比方说,日期是否包括时区可能就会困扰到你,将UNIX时间转化成其它的时区可能会让你崩溃,你还是忘了时钟同步和延迟这些事吧。我希望读完这篇经典的文章后,你的许多关于时间的误解都能够消除,自己能够巩固一些关于日期的基础常识。

  1. 每个WEB开发人员必知之URL编码篇

这篇文章介绍了Uniform Resource Locator(URL)编码中的一些常见的误解,然后试图阐明什么是HTTP的URL编码,最后列举了一些常见的错误及解决方案。尽管这篇文章的内容并不特定于某种编程语言,但它是用Java来进行问题的描述,并修复URL编码中存在的问题。你会学习到URL的基础语法,HTTP及其它协议中通用的URL格式。这篇文章还介绍了URL中的一些常见错误,比如字符编码,URL不同部分的保留字符,以及URL编解码问题。如果你是一名Java开发人员,你会学习到如何在Java中正确地处理URL,如何构造URL,以及如何使用Apache Common Http client库。最后它还提供了一些最佳实践的建议,比如你应该在构建URL的时候进行编码,确保你的重写URL的过滤器正确地处理了URL,等等。这是任何WEB开发人员必读的文章 。

  1. 每个程序员必知之WEB开发

这是programmers.stackexchange.com上的一篇非常有趣的文章,它讲的是程序员在将网站对外发布之前需要实现的技术细节。这包括接口设计及用户体验,安全性,WEB标准,性能,搜索引擎优化(SEO),以及一些重要的资源。当今世界严重地依赖于互联网,很多程序员都有自己的网站,通常是一个博客。这篇文章中学到的东西可能对你的专业没有帮助,但它对你个人的事情肯定会有所帮助。你会了解到一些关键的技术,比如HTML,HTTP,XML,CSS,JavaScript,浏览器兼容性,减少网站加载时间的技巧,XML站点地图,W3C规范,以及许多其它的关键的细节。

  1. 每个程序员必知之SEO

这对WEB开发人员,程序员,博主而言又是一篇很重要的文章。由于很多程序员同时也是博主,你无法对SEO视而不见,学一个搜索引擎优化的基础知识还是非常重要的,这能帮助Google检索到你的内容并推荐给其它程序员。在今天这个网络互联的时代,没有任何公司可以脱离WEB而存在,SEO变得尤为重要。如果你有一家初创企业在卖一些产品,那么SEO就是你要关注的事情。所有程序员,尤其是WEB开发人员,都可以从这篇文章中受益良多。记住,SEO是一个很宽泛变化的题目,不同的搜索引擎,比如Google,Yahoo等,它们的SEO都各不相同。因此,要想掌握这项技能你得经常更新你的知识库。

  1. C程序必知的未定义行为

C语言有一个未定义行为的概念。未定义行为是一个很宽泛的主题,它有许多细微的差别,这就是为什么我喜欢Java的一个原因,没有这么多的未定义行为,没有这么多的困惑,更稳定也更消停。很多人看起来很自然的事情在C里其实是未定义的行为,这也是程序BUG的一个常见的来源。除此之外,C中的任何未定义行为都由具体实现来决定(编译器和运行时),它们生成的代码会格式化你硬盘,做一些意想不到的事情,甚至更糟。读下这篇文章,到未定义行为的海洋里遨游吧。

  1. 程序员必知之网络

这段话摘自这篇文章,”你是一个程序员。你有想过多玩家的游戏是如何实现的吗?从外面看起来它是:两个或多个玩家通过网络共享相同的经验,就像他们在同一个虚拟世界中一样。不过作为程序员,我们知道底下的真相和你看到的东西是有所区别的。事实上这都只是一个错觉“。这是篇关于网络的非常有趣的文章,它是为游戏开发人员而写的,不过我认为每个程序开发人员都能从中受益。

  1. Java程序员必知之String

这是我自己关于java.lang.String的一篇文章,我个人认为每个Java开发人员都应该了解一下。String在日常的Java开发中非常重要,这就是为什么每个Java程序员都应该对它非常了解。这篇文章涉及到了String的许多重要的领域,包括String池,字符串常量,使用==和equals比较字符串,将字节数组转化成String,为什么字符串是不可变的,如何正确拼接字符串,等等。高级程序员应该都知道这些东西了,不过回顾一下也是不错的。

  1. 程序员必知之安全

有一个计算机系的学生在StackOverFlow上问了这个问题。就像我们了解到的一些常见编程概念比如操作系统,算法,数据结构,计算机体系结构,以及其它东西一样,了解安全也同样重要。安全是一个很大的话题,包括加密解密,SSL,WEB安全,混淆,认证,授权,等等,它是每个程序员都应该了解的基础知识。刚进这行的时候,我个人对安全这块还不是很了解,这时候我就开始基于Servlet/JSP写一些的Java WEB程序,后来我才了解到EWB安全性以及一些安全威胁比如SQL注入,拒绝服务,XML注入,跨站脚本,等等。作为一名Java开发人员,我现在遵循fortify, PMP,以及其它一些静态代码分析器提供的Java安全编码规范进行编码。这篇文章是关于安全这个主题的一个很好的合集,不管你现在还写不写代码,这些资源对你来说都非常有用。

  1. 程序员必知之延迟时间

这篇文章是一份额外的福利,但也是每个程序员都应该读的。不管用的是什么语言,Java还是C++都好,要写出高性能的应用程序,你都得了解延迟时间的基础常识,比如从内存中读取一个变量需要多久,从一级缓存中读取又需要多久,二级缓存呢,SSD硬盘中随机读又需要多久,还有要是从磁盘中读呢?互斥锁的加锁解锁需要多长时间,从一个城市发送一个数据包到另一个城市需要多长时间,在同一个数据中心又需要多久?这些延迟的数字是独立于任何编程语言的,开发人员必须要想写高频低延迟的应用程序,它们是核心知识库中的一部分。这篇文章还有一个好消息就是,它会告诉你这些年以来这些延迟时间的变化。你可以看到2006年的延迟时间是多少,而现在又是多少。

这就是所有程序员必读文章的列表。看到这些文章的标题, 每个程序员都应该知道的XXX,你能了解到关于某个主题的一些比较有深度的知识。坦白说程序员有太多东西要学了,像学习Java语言这种只是冰山的一角,但并不是所有人都有热情去学习。写程序是一份很有挑战的工作,在你的职业生涯中,能帮忙到你的就是这些基础知识,比如,内存,Unicode,浮点数,时间,安全,这些对任何程序员来说都非常重要。有些文章是和语言相关的,比如我自己那篇关于String的文章,还有每个C程序员都应该了解的未定义行为,不过对于许多初学者来说学习一下也有好处。

译注:我觉得还有一个必读的,就是数数,这里一共是12篇了。。有几篇访问不了的,我也搬运到自己的博客上了。

原创文章转载请注明出处: 每个程序员都必读的10篇文章

英文原文链接

Viewing all 15843 articles
Browse latest View live


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