花钱的年华

江南白衣,公众号:春天的旁边

陌生但默默一统江湖的MurmurHash

| Filed under 技术

看Jedis的主键分区哈希时,看到了名字很萌很陌陌的MurmurHash,谷歌一看才发现Redis,Memcached,Cassandra,HBase,Lucene都用它。

关于Hash,我之前只知道MD5,SHA1,SHA256还有Java自己的hashCode(),学校里怎么没教MurmurHash啊? 哦,原来这算法是2008年才被发明的,与MD5这些讲究安全性的摘要算法比,Redis们内部为主键做个Hash而已,就不需要安全性了,因此Google家的MurmurHash这种non-cryptographic的速度会快几十倍。详见Hash 函数概览(State of hash functions)

好了,以后要多用MurmurHash。在Java的实现,Guava的Hashing类里有,上面提到的JedisCassandra里都有Util类。

PS.有些人看到murmur就想到了陌陌就想到了别的,其实是 multiply and rotate的意思,因为算法的核心就是不断的"x *= m; x = rotate_left(x,r);"


 

Java的HashCode

那Java自己的String的hashCode()呢? 用的是Horner法则, s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]

实现上是循环原哈希值×31再加下一个Char的值,算法及其复杂度简单一目了然,连我都能看懂。

for (int i = 0; i < str.length(); i++) { hash = 31*hash + str.charAt[i]; }

注意,int会溢出成负数,再溢成正数,比如"abcde"是 92599395, abcdef"是 -1424385949, "abcdefgh" 是 1259673732

Eclipse的自动代码生成的hashCode()函数也是类似的,循环原哈希值×31,再加下一个属性的hashCode()值。

31有个很好的特性,就是用移位和减法来代替乘法,可以得到更好的性能:31*i==(i<<5)-i。现在的VM可以自动完成这种优化。 Java自己的HashMap,会在调用Key的hashCode()得到一个数值后,用以下算法再hash一次,免得Key自己实现的hashCode()质量太差。

static int hash(int h) {
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}

那为什么Cassandra们不选简单直白的Horner法则呢?

我猜原因之一是它的性能,有个评测用js来跑的,还是murmur好些。

再猜原因之二它的变化不够激烈,比如"abc"是96354, "abd"就比它多1。而用 murmur"abc"是1118836419,"abd"是413429783。像在Jedis里,它的几个Shard节点的名字就叫做shard-1,shard-2,shard-3而已,hash这几个字符串,murmur的结果还能均匀的落在一致性哈希环上,用Honer法则就不行了。

 
文章持续修订,转载请保留原链接:http://calvin1978.blogcn.com/articles/murmur.html

by calvin | tags : | 6

Redis、Memcached、Guava、Ehcache中的算法

| Filed under 技术

缓存那些事,一是内存爆了要用LRU(最近最少使用)、LFU(最少访问次数)、FIFO的算法清理一些;二是设置了超时时间的键过期便要删除,用主动或惰性的方法。

在看所有的细节之前,可以看一篇相当专业的《缓存算法》,世界真宽阔,算法真奇妙。

 

1. LRU

简单粗暴的Redis

今天看Redis3.0的发行通告里说,LRU算法大幅提升了,就翻开源码来八卦一下,结果哭笑不得,这旧版的"近似LRU"算法,实在太简单,太偷懒,太Redis了。

Github的Redis项目里搜索lru,找到代码在redis.c的freeMemoryIfNeeded()函数里。

先看2.6版的代码: 竟然就是随机找三条记录出来,比较哪条空闲时间最长就删哪条,然后再随机三条出来,一直删到内存足够放下新记录为止.......可怜我看配置文档后的想象,一直以为它会帮我在整个Redis里找空闲时间最长的,哪想到我有一百万条记录的时候,它随便找三条就开始删了。

好,收拾心情再看3.0版的改进:现在每次随机五条记录出来,插入到一个长度为十六的按空闲时间排序的队列里,然后把排头的那条删掉,然后再找五条出来,继续尝试插入队列.........嗯,好了一点点吧,起码每次随机多了两条,起码不只在一次随机的五条里面找最久那条,会连同之前的一起做比较......

中规中矩的Memcached

相比之下,Memcached实现的是再标准不过的LRU算法,专门使用了一个教科书式的双向链表来存储slab内的LRU关系,代码在item.c里,详见memcached源码分析-----LRU队列与item结构体,元素插入时把自己放到列头,删除时把自己的前后两个元素对接起来,更新时先做删除再做插入。

分配内存超限时,很自然就会从LRU的队尾开始清理。

同样中规中矩的Guava Cache

Guava Cache同样做了一个双向的Queue,见LocalCache中的AccessQueue类,也会在超限时从Queue的队尾清理,见evictEntries()函数

和Redis旧版一样的Ehcache/Hazelcast

文档,居然和Redis2.6一样,直接随机8条记录,找出最旧那条,刷到磁盘里,再看代码,Eviction类OnHeapStore的evict()函数

再看Hazelcast,几乎一样,随机取25条。 这种算法,切换到LFU也非常简单。

小结

不过后来再想想,也许Redis本来就不是主打做Cache的,这种内存爆了需要通过LRU删掉一些元素不是它的主要功能,默认设置都是noeviction——内存不够直接报错的,所以就懒得建个双向链表,而且每次访问时都要更新它了,看Google Group里长长的讨论,新版算法也是社区智慧的结晶。何况,Ehcache和Hazelcast也是和它的旧版一样的算法,Redis的新版还比这两者强了。

后来,根据@刘少壮同学的提示,JBoss的InfiniSpan里还实现了比LRU更高级的LIRS算法,可以避免一些冷数据因为某个原因被大量访问后,把热数据挤占掉。

 

2. 过期键删除

如果能为每一个设置了过期的元素启动一个Timer,一到时间就触发把它删掉,那无疑是能最快删除过期键最省空间的,在Java里用一条DeplayQueue存着,开条线程不断的读取就能做到。但因为该线程消耗CPU较多,在内存不紧张时有点浪费,似乎大家都不用这个方法。

所以有了惰性检查,就是每次元素被访问时,才去检查它是否已经超时了,这个各家都一样。但如果那个元素后来都没再被访问呢,会永远占着位子吗?所以各家都再提供了一个定期主动删除的方式。

Redis

代码在redis.c的activeExpireCycle()里,看过文档的人都知道,它会在主线程里,每100毫秒执行一次,每次随机抽20条Key检查,如果有1/4的键过期了,证明此时过期的键可能比较多,就不等100毫秒,立刻开始下一轮的检查。不过为免把CPU时间都占了,又限定每轮的总执行时间不超过1毫秒。

Memcached

Memcached里有个文不对题的LRU爬虫线程,利用了之前那条LRU的队列,可以设置多久跑一次(默认也是100毫秒),沿着列尾一直检查过去,每次检查LRU队列中的N条数据。虽然每条Key设置的过期时间可能不一样,但怎么说命中率也比Redis的随机选择N条数据好一点,但它没有Redis那种过期的多了立马展开下一轮检查的功能,所以每秒最多只能检查10N条数据,需要自己自己权衡N的设置。

Guava Cache

在Guava Cache里,同一个Cache里所有元素的过期时间是一样的,所以它比Memached更方便,顺着之前那条LRU的Queue检查超时,不限定个数,直到不超时为止。而且它这个检查的调用时机并不是100毫秒什么的,而是每次各种写入数据时的preWriteCleanup()方法中都会调用。

吐槽一句,Guava的Localcache类里面已经4872行了,一点都不轻量了。

Ehcache

Ehcache更乱,首先它的内存存储中只有惰性检查,没有主动检查过期的,只会在内存超限时不断用近似LRU算法(见上)把内存中的元素刷到磁盘中,在文件存储中才有超时检查的线程,FAQ里专门解释了原因。

然后磁盘存储那有一条8小时左右跑一次的线程,每次遍历所有元素.....见DiskStorageFactory里的DiskExpiryTask。 一圈看下来,Ehcache的实现最弱。

 
文章持续修改,转载时请保留原链接: http://calvin1978.blogcn.com/articles/lru.html

by calvin | tags : | 7

普通群众玩Docker

| Filed under 技术

现在有些开源软件很过分,直接就只发布Docker镜像,让人不得不学点Docker。

对于我这种平时用Windows的普通群众,Docker有一个Boot2Docker的选择,但风闻这个阉割版限制颇大,所以还是决定用VirtualBox + CoreOS。

为什么是CoreOS?因为又是风闻这是体积最小且与Docker最亲近(虽然最近分了家)的Linux版本。

网上已有的教程都需要从头装CoreOS,还要Vagrant什么的,在同事帮助下摸索了一个更简单的步骤如下:

1. 下载安装VirtualBox (~100M)

2. 下载CoreOS的VirtualBox镜像 (~100M)

http://stable.release.core-os.net/amd64-usr/current/下载coreos_production_virtualbox.ovf 与 coreos_production_virtualbox_image.vmdk.bz2 ,并用WinRar将bz2文件解压到与ovf文件同一目录下。

因为URL里很悲催的包含了某个敏感的数字,又被没文化的墙程序员给墙了,请自备梯子。

3. 在VirtualBox里import 那个ovf文件,启动镜像。

4. 设置用户密码

CoreOS并没有默认密码,一般像AWS EC2那样用SSH Key解决,但VirtualBox的镜像想再往里加个SSH Key不易,因此走另一条路,用autologin。

在登录过程中,在 GUN GRUB按键盘的上下箭头,选择Cor OS default,再按‘E’键修改启动参数, 在最后一行的末尾加上 `console=tty1 coreos.autologin=tty1` ,然后F10保存后启动。
无密码进入后,再sudo passwd core 修改默认用户core的密码。

5. 设置支持本地ssh登录

在虚拟机的Setting->Network->Port Forwarding里,增加一个 Host IP 127.0.0.1 Host Port 2222 Guest Port 22的映射,则本地可以用 ssh core@localhost -P 2222 登录

好了,可以开始Docker体验~~~如果手头没什么Docker的入门书,就直接看官网的User Guide,不过在HelloWorld的例子里,第一条指令sudo docker run ubuntu:14.04 /bin/echo 'Hello world'就要下载一个 200M左右的 Ubuntu镜像,又有一阵要等。

等的时候,可以看看《一个不是很短的Docker入门介绍》《Docker终极指南》 这两篇文章。

 
文章持续修订,转载请保留原链接:http://calvin1978.blogcn.com/articles/begintodocker.html

by calvin | tags : | 11

继续Redis

| Filed under 技术

Redis Cluster的八个月使用经验

大家都在冷眼观望的时候,有道的同学居然已经玩了Redis Cluster八个月了。不过有道好像主要把Redis用作可与Memcached互换的缓存,数据没有落地,也没有深度应用如Lua脚本,因此Codis似乎更适合他们。 《离职系列文章之redis cluster使用经验》

9.Huge Page

Huge Page这种听名字就很高贵,调优指南里屡屡出现的东西,在Redis里却是禁止的。Huge Page的科普文章。禁止的原因是Snapshot时fork出的子进程,使用Copy on Write的内存共享策略,期间主进程的Page被修改时必须另复制一份以保证子进程的Page不变,Page Huge了复制就Huge了。

不过拖慢的主要是期间访问的速度吧,至于容量,我们在规划时早就认命的只使用1/2内存,Redis也是最废内存的NOSQL方案了。

 

8. Scalable

沿着InfoQ的《高可用、开源的Redis缓存集群方案》,发现了豌豆荚的Codis和Netflix的Dynamo

两者都是使用Proxy-Based的思路,借鉴或直接在Twemproxy的基础上修改,摈弃了Redis自己的Redis Sentinel和Redis Cluster.

Codis主要解决动态增加Redis节点的问题,用Go开发,因为作者的设计思路比Redis Cluster简单,所以早早出来了。不过它的HA好像故意设计成Slave不能像Sentinel那样自动提升为Master了。

最近InfoQ又再发了一篇,《高效运维最佳实践(03):Redis集群技术及Codis实践》

Dynamo能解决跨机房复制,它的开发者叫Minh Do,我们研究了一下,胡志明也叫Minh,应该是个越南人。不过版本只有0.0.3。

在《程序员》杂志的最后一期上,还提到了小米的成倍扩容的方案。那寥寥几句话我是这样理解的:

客户端用取模分区而不是一致性哈希分区,假设原来有3台服务器(A,B,C),按3取模,那数据1,4就会落到A,2,5会落到B。现在成倍的扩容3台(D,E,F)——

Step1. 先让D,E,F充当A,B,C的Slave同步数据。
Step2. 告诉应用Redis集群已扩展, 则此时再按6取模,1会落到A而4就会落到D。
Step3. 最后将D,E,F改为Master状态接受写入。

Step2,3之间的数据可能写入失败,但也是必需的代价了,一分钱一分货。

 

7.3 Redis的一致性

Redis被人说在网络脑裂的时候一致性不行,Antirez悍然回应,有些东欧的同事也拿这个来说事,然后Flickr的力挺结束了争执。

InfoQ: Flickr选择使用Sentinel来保证Redis的高可用性

 

7.5 Hyberloglogs

Redis在整整一年多都在痛苦的实现Redis Cluster,最近终于憋不住了,做了个Hyberloglogs玩,作用是用恒定大小的空间,近似的估算Unique元素的个数。以前如果要算独立访问IP,就要将所有访问IP保存在一个Set里,这无疑会花很多空间。现在不用再存了,也能给出大概的数值。

其实Redis就应该多做点有趣的数据结构,实现各种算法,现在精力都花在Redis Cluster上,可惜了。
 

7. Redis的周报

关于Redis新闻八卦的两个周报: Redis WatchRedis Weekly 2014-12-28
 

6. 终于试了单机多实例

今天把集群里的六台Redis全移进一个虚拟机里。六个单线程的好孩子,不吵不闹也不争玩具,也就是不争网卡的磁盘了,亏那磁盘还是旧式的非SSD磁盘。2014-12-18
 

5. Red is the new black

@王四哥达家码 : CTO来看我救他的进度如何了,发现我带着耳机在听歌,怒道:你还有心听歌!我说:呃,我听的是Funeral for a Friend乐队的名曲。。。Redis the new black。。。他就悻悻得走了。。 2014-12-18

[看半天,原来是 "Red is the new black"]

 

4. Redis在VM里的调优神器

刚用chrt设置实时调度解决了Redis在KVM里,因为单线程抢不过隔壁几百条线程的Java程序导致性能减半的问题。chrt,让Redis 100%的占有那颗CPU。 

再回想一年前,曾经用numactl,将redis这个只会耍单线程的苦孩子绑死在一颗核上,性能赫然拔高了一截。但是……结果飘忽啊,为什么这颗CPU会快,那颗就慢呢。

那篇Running Redis in Production教人如何躲开有网卡流量的CPU,大约快10%  2014-05-27

 

3. RedisConf 2013

Antirez同志在RedisConf 2013上发表的重要讲话,很有Redis风格的幻灯片,第一句先自我表扬--Redis is made of pieces, most of them are modular,然后掰开来论尽每一块的职责,今年的变动和即将发生的演进。 2013-10-22

(Caption: Antirez在RedisConf 2013上发表的重要讲话)

 

2. 新浪的Redis集群

新浪的同学又一次掀开了他们Redis集群的一角:<Largest Redis Clusters Ever>,每天5500亿次的读写无愧世上最大的Redis集群之一。他们觉得,Redis的单线程架构其实更利于在单机上部署多个实例,如果磁盘撑得住多个AOF文件的IO,而且AOF重写也由程序调度而不是自动触发。 2013-10-10

(Caption: 新浪的同学又一次掀开了他们Redis集群的一角)

 

1. Redis Cluster 规范

Redis Cluster从来都是只闻楼梯响,正式版转眼又从Redis 2.8 跳票到3.0。不过R家的东西有个好处就是原理简单明了,你可以很容易推导出它在各场景下的行为,不会有别家那种黑盒的抓瞎感。《Redis Cluster Specification》,继续是@huangz1990 的翻译  2013-010-09

(Caption:只闻楼梯响不见人的Redis Cluster)

 

by calvin | tags : | 0

Storm笔记

| Filed under 技术

用了一段时间Storm后的笔记。发现可以记的东西不多,证明Storm挺简单的,你只要遵循一些简单的接口与原则,就能写出大规模实时消息处理的程序。

不断更新中,请尽量访问博客原文
 

为什么用Storm

没接触前把Storm想象得很强大,接触后觉得它就那样可有可无,再后来又觉得没有了全部自己做也麻烦。

集群管理:支持应用的部署,工作节点的管理(任务分配、HA、Scalable等),Metrics的收集。

数据流的传输与路由:支持多种数据在各处理节点间自由流动(是同类方案里DAG拓扑最灵活的),基于Netty的高效传输机制,支持轮询、广播、按值分组的路由。

数据高可靠性的保证:支持数据流动了多个节点后,在某个节点的处理失败,可以引发数据从源头开始重传

按Storm的官方说法,你也可以自己搭建许多消息队列和worker组成的网络来实现实时处理,但是:

乏味:你大部份开发时间花费在部署worker,部署中间队列,配置消息发送到哪里。你所关心的实时处理逻辑只占了你的代码很少的比例 。

脆弱:你要自己负责保持每个worker和队列正常工作。

伸缩时痛苦:当worker或队列的消息吞吐量太高时,你需要重新分区,重新配置其它worker,让它们发送消息到新位置。

缺点

核心代码是用Clojure写成,翻看代码非常不便。其实,它现在很多新的外部模块都用Java来写了,另外阿里同学翻写了一个JStorm

 

其他流处理方案

Spark-Streaming:总是有人问为什么不用Spark Stream,首先它是Micro-Batch风格的准实时方案,间隔一般设到500ms。另外,它的消息流拓扑好像没Storm那样可以随便乱入,有时候必须弄个DB或MQ来做中间传输。

Samza: Linkedin的产品,与Storm比,传输基于Apache Kafka,集群管理基于YARN,它只做处理的那块,但多了基于RocksDB的状态管理。但据《大数据日知录》说,受限于Kafka和YARN,它的拓扑也不够灵活。

 

自定义Spout

Storm对可靠消息传输的支持程度,很大程度上依赖于Spout的实现。

并不默认就支持高可靠性的,collector emit的时候要传输msgId,要自己处理ack(msgId)和fail(msgId)函数。而很多spout其实没有这样做,只有Kafka Spout做的比较正规。

默认的,如果三十秒,消息流经的所有下游节点没有都ack完毕,或者有一个节点报fail,则触发fail(msgId)函数。

因为ack/fail的参数只有msgId,这就要Spout想在ack/fail时对上有消息源如Kafka/JMS进行ack/fail,又或者fail时想重发消息,如果需要完整的消息体而不只是msgId才能完成时,要自己把msgId对应的消息存起来(会撑爆内存么,好在Kafka不需要)。

另外,因为每个Spout 是单线程的,会循环的调用nextTuple()的同时,调用ack()或fail()处理结果。所以nextTuple()如果没消息时不要长期阻塞,避免把ack()也阻塞了。同时,Storm自己有个机制在nextTuple总是没消息时Sleep一下避免空循环耗CPU,但参考storm-starter里的spout,还是直接内部等个50ms好了。在JStorm里,就改为了两条分开的线程。

另外,spout有时是每次被调用nextTuple()时主动去pull消息的,有时是被动接收push消息后存放在LinkedBlockingQueue里,netxtTuple()时从Queue里取消息的。Spout突然crash的话,存在Queue里的消息也会丢失,除非上游消息源有ack机制来保障。

Spout还有个Max Pending的配置,如果有太多消息没有ack,它就不会再调nextTuple()。但如果上游消息源是主动Push的,消息还是会源源不断的来,累积在queue里。

 

RichBolt vs BasicBolt

直接用BasicBolt,会在execute()后自动ack/fail Tuple,而RichBolt则需要自行调用ack/fail。

那什么时候使用RichBolt? Bolt不是在每次execute()时立刻产生新消息,需要异步的发送新消息(比如聚合一段时间的数据再发送)时,又或者想异步的ack/fail原消息时就需要。

BasicBolt的prepare()里并没有collector参数,只在每次execute()时传入collector。而RichBolt刚好相反,你可以在初始化时就把collector保存起来,用它在任意时候发送消息。

另外,如果用RichBolt的collector,还要考虑在发送消息时是否带上传入的Tuple,如果不带,则下游的处理节点出错也不会回溯到Spout重发。用BasicBolt则已默认带上。

 

Ack机制

作者是一拍脑袋想到了用20个字节来追踪每条Spout出来的消息被处理的情况,原理是XOR的时候,N XOR N=0,同一个值以任意次序XOR两次会归0,如A XOR B XOR B XOR C XOR A XOR C =0, 在发出Tuple时,就用随机产生的Tuple Id XOR一下。等接收的Bolt ack时,再XOR一下,就会归0。所以当消息以任意的顺序会流经很多节点,产生很多新Tuple,如果都被成功处理,即所有Tuple id都被以任意顺序执行了两次XOR,则这20个字节最后应该重新归0,就可判断全部ack完毕。

另外,重发是从最上游的Spout开始,如果某个bolt的操作是非幂等的,还要想想怎么自己去实现去重。
 

异常处理

如果希望上游的Spout重发消息,则在BasicBolt中抛出FailedException 或在RichBolt中直接fail掉Tuple。
其他情况下,execute()方法不应该抛出任何异常,或者你是故意抛出异常使得Topology停转。

 

状态管理

状态数据分两种,一种是本地历史数据,不如使用路由规则,使相同用户的数据总是路由到同一个Bolt。 一种是全局的数据。Storm完全不管数据的持久化(Trident那块没用到不算), 《Storm 并非完全适合所有实时应用》 就是吐槽Storm的状态数据管理的。

不像Linkedin的Samza,Bolt如果需要历史数据,一般自己在内存里管理数据(Crash掉或节点的变化导致路由变化就没了哈),或者在本地起一个Redis/Memcached(不能与Bolt一起管理,路由变化的数据迁移,性能也会削弱)

对于全局数据,同样需要Cassandra之类高可扩展的NOSQL来帮忙,但此时延时会更厉害,性能瓶颈也很可能压到了Cassandra上。

 

定时任务

定时聚合数据之类的需求,除了自己在bolt里开定时器,还可以用如下设置,所有Bolt都定时收到一条Tick消息:

conf.put(Config.TOPOLOGY_TICK_TUPLE_FREQ_SECS, 300);

如下函数用于判断是Tick还是正常业务消息:

protected static boolean isTickTuple(Tuple tuple) {
return tuple.getSourceComponent().equals(Constants.SYSTEM_COMPONENT_ID)
&& tuple.getSourceStreamId().equals(Constants.SYSTEM_TICK_STREAM_ID);
}

 

拓扑的定义

除了使用Java代码,还可以使用Yaml来动态定义拓扑,见 https://github.com/ptgoetz/flux

并发度的定义及基于命令行的动态扩容见官方文档,另对于worker进程数的建议是Use one worker per topology per machine。

 

序列化

Tuple除了传基本类型与数组,AraayList,HashMap外,也可以传一下Java对象的。Storm使用Kyro作为序列化框架,据测比Hessian什么的都要快和小。但一定注册这些额外的Java对象的类型,否则就会使用Java默认的序列化。

参看官方文档,有两种方式注册类型,一个是storm.yaml文件,一个是Config类的registerSerialization方法。如无特殊需求,直接注册需要序列化的类就可以了,不需要自己实现一个Serializer,Kryo默认的按fields序列化的Serializer已足够。

Spout和Bolt的构造函数只会在submit Topology时调一次,然后序列化起来,直接发给工作节点,工作节点里实例化时不会被调用里,所以复杂的成员变量记得都定义成transient,在open(),prepare()里初始化及连接数据库等资源。

另外,需要实现close()函数清理资源,但该函数不承诺在worker进程被杀时保证被调用。

 

fields grouping的算法

按名称提取fields的值,叠加其hash值,再按当前的可选Task数量取模。所以,动态扩展Task数量,或某Task失效被重建的话,都可能让原来的分配完全乱掉。

 

与其他开源技术的集成

比如External目录里的一堆,storm-contrib 里也有一堆,目前支持Jdbc,Redis,HBase,HDFS,Hive,甚至还有Esper,目标都是通过配置(比如SQL及Input/Output fields),而非代码,或尽量少的代码,实现交互。有时也可以不一定要直接用它们,当成Example Code来看就好了。

另外,与传统的Java应用思路相比,Bolt/Spout与资源连接时,比较难实现共享连接池的概念,连接池一般都是每个Bolt/Spout实例自用的,要正确处理其连接数量。

 

HA的实现

如果Worker进程失效,Supervisor进程会检查 Worker的心跳信息,重新创建。
Supervisor进程,需要用Daemon程序如monit来启动,失效时自动重新启动。
如果整个机器节点失效,Nimbus会在其他节点上重新创建。

Nimbus进程,需要用Daemon程序如monit来启动,失效时自动重新启动。
如果Nimbus进程所在的机器直接倒了,需要在其他机器上重新启动,Storm目前没有内建支持,需要自己写脚本实现。

因为Supervisor和Nimbus在进程内都不保存状态,状态都保存在本地文件和ZooKeeper,因此进程可以随便杀。
即使Nimbus进程不在了,也只是不能部署新任务,有节点失效时不能重新分配而已,不影响已有的线程。
同样,如果Supervisor进程失效,不影响已存在的Worker进程。

Zookeeper本身已经是按至少三台部署的HA架构了。

 

运维管理

Storm UI也是用Clojure写的,比较难改,好在它提供了Restful API,可以与其他系统集成,或基于API重写一个UI。

Metrics的采样率是1/20(topology.stats.sample.rate=0.05),即Storm随机从20个事件里取出一个事件来进行统计,命中的话,counter 直接+20。

在旧版本的Storm使用旧版的ZooKeeper要启动数据清理的脚本,在新版上只要修改ZooKeeper的配置文件zoo.cfg, 默认是24小时清理一次 autopurge.purgeInterval=24。

日志的配置在logback/cluster.xml文件里,Storm的日志,天然的需要Logstash + ElasticSearch的集中式日志方案。

storm.local.dir 要自己建,而且不支持~/ 代表用户根目录。

storm.yaml的默认值在 https://github.com/apache/storm/blob/master/conf/defaults.yaml

 

Tunning

1. 内部传输机制的各种配置,见文档

2. 屏蔽ack机制,当可靠传输并不是最重要时。可以把Acker数量设为0,可以让Spout不要发出msgId,或者bolt发送消息时不传之前的Tuple。

 

资料

文章持续修订,转载请保留原链接: http://calvin1978.blogcn.com/articles/stormnotes.html

Mac Talk《技术人物系列:白衣飘飘的江南》

| Filed under 技术

很荣幸做了@池建强 的新技术人物系列的开篇 (他是按见面次数最少来排序的.......)。 池大作家替人写故事的手艺一级好,大家快找他踊跃报名。

微信公众号版原文知乎专栏版原文

复制粘贴版:

科技媒体们总是喜欢捕捉热点人物,马云的一举一动,化腾的一词一句,雷军的一颦一笑,等。我不是媒体,我喜欢编程和写作,所以准备启动一个系列,写一写身边的技术人、产品经理和创业者们,这些人薄雾浓云愁永昼大都是70后和80后,在 IT 行业有超过十年的从业经验,他们大都在互联网发展的过程中参与了和建设了一些什么,他们可能星光闪烁,也可能低调无闻,但是每个人都有属于自己的一片天空,他们的故事,需要有人知道!

写他们当然是凭记忆和我对他们的了解去写,我可没时间去做访谈,所以设定几个简单的规则:

1、这些人肯定是我的朋友。
2、没见过面也可以是朋友,但没见过活物的,我就不胡说八道了吧。
3、见面越多,可能会写的越长。
4、愿意让我写写的,可以告诉我,不愿意的,也要告诉我。
5、无情的赞美多于温柔的杀戮,大致如此。

另外,说到记忆,这是一种最不可靠的物质,它就像一扇破败的窗户,落满灰尘,玻璃模糊不清,与窗框之间充满裂缝,腻子也掉了,如果你想看清楚窗户里是什么,只能用抹布沾拭清水去擦洗,擦之前还得用崭新的腻子填充裂缝。所以,我无法保证记忆里的东西都真实的发生过,我只能说,这些修补和擦洗的感情和态度是真实的。就当小说看吧。

今天的写作时间不多,我准备写写江南白衣——肖桦,谁让我和他只见过一次呢……

肖桦,网络 ID 「江南白衣」,70后资深程序员,「花钱的年华」博主,第一波互联网浪潮(泡沫)创业者,嗯,失败的那种,著名 Java 开源项目 SpringSide 的缔造者。目前在广州爱立信继续磨练编程技艺的 Coding Architect。

可以说,白衣同学就是老罗常常挂在嘴边的工匠,只不过白衣是在编程领域,并且,一生对文艺、Java 和 Spring 充满了暧昧之情。半生吧,谁知道以后他会有什么变化呢。

我知道白衣同学当然是通过 SpringSide 项目,因为我在很长一段时间里都是 Java 和 Spring 的重度使用者,那时候很多大公司还没有大规模开源自己的项目,比如淘宝们,还有很多公司在做自己的框架和平台,比如我们,可以说,SpringSide 在那个白衣飘飘的年代独树一帜,木秀于林,还没有风摧之!随着 Spring 的大规模普及,每个使用 Java 和 Spring 的开发者都或多或少的受益于 SpringSide,要么直接在 SpringSide 上构建项目和平台,要么阅读 SpringSide 的源代码和设计思想,我属于后者。

当时我在负责一个企业级的商业平台,阅读 SpringSide 的源代码之后发现这个项目的作者很多思路和我类似,其中精巧的设计给了我更多的启发。而且这个项目的作者显然是有代码洁癖的人,设计优雅,代码简洁,干净,不炫技,不乱用设计模式,用最少的代码实现最佳的功能,让人赞叹不已。怎么才能认识作者呢?

社交时代很快像奔腾的潮水一样汹涌而至,我在微博上找到了「江南白衣」这个名字,没想到他对我的名字也略有耳闻,于是我关注了他,他关注了我,我们开始了一段……未曾谋面的交流。偶尔转发,偶尔评论,偶尔私信聊聊技术和生活。与 SpringSide 初创时期相比,白衣变得沉默而低调。他常常在微博写下这样的句子:

最近这个月好沉默,因为在看物联网与大数据的东西,刚入门没什么可说的……想起唐诺的一段话:我们缺的不再是知识,过多过廉价的知识像大仓库般丧失了美感、珍罕感,再不复有魅惑力量。

我就知道,他的中年危机到了,因为我也会想起年轻时的理想,纵横四海,改造国家……这些梦想经常被线上的 bug 和无休止的 issue 打碎,什么是梦?什么是现实?到最后自己也无法分清楚。我没那么沉默,我开始写作了,后来出了一本书。读了和写了那么多代码的江南白衣,居然很喜欢我这本没什么技术含量碎碎念的作品,于是我觉得,也该见一见面了。

终于等到了一个假公济私的机会,我飞赴广州爱立信,去见江南。由于「江南白衣」这四个字对我的印象太深刻了,我想象中的白衣是这样的:

或者这样的:

结果从爱立信研发办公区走出了一个高高瘦瘦的男生,头发不算长,杂乱的散落在前额,着了一件白色的紧身T恤,就是那种八级台风也休想让这件白衣飘起来的款。他冲我咧嘴笑了一下,用柔软的南方普通话说:建强你好,我就是白衣。

我连忙把掉在地上的下巴捡起来按上,与之握手相庆,你就是白衣啊,衣服还真挺白的。然后我们假惺惺的互道仰慕之情,开始聊技术,聊生活,聊写作,诸如「这段代码是不是你写的」「孩子还好吧」「老婆都是原配的吧」「你喜欢诗、小说,还是杂文」「为什么要做 SpringSide」之类的话题。

为什么要做 SringSide 呢?那是十年前的一个晚上,白衣热的睡不着觉,他一直在思考「我是谁,从哪来,到哪去」这样的终极问题,最终也没有想清楚。好吧,那就让我们为这个世界留下一些什么吧。写一本书还是做一个开源项目?书印出来了就没法改了,对我这种货色还可以接受,但白衣是一个完美主义者……而开源项目,可以永远年轻,永远生长,永远重构……于是就有了 SringSide,这个项目还有一个好听的中文名称「春天的旁边」。

很多人说卖桃君是站在了科技与人文的十字路口,其实我差得很远,白衣同学基本上已经达到了「站在哪里,哪里就是十字路口」的境界,从他起的项目名字就可以看出这货有多么闷骚了。他的博客「花钱的年华」里有大量的非技术文章,他做了一件非常重要的工作「作现代诗重要的整理与最大的搬运」,在这篇博客里,他写到:

这世界绝不止眼前的苟且,还有诗与远方。远方有了,朋友圈里一天到晚都是旅游的照片。
但诗呢?除了黑色的眼镜,还有什么?……
忽然想,做一次重要的整理,最大的搬运,从图书馆里陆续搬回来几十本诗集,校对网上版本的错漏字,或自己手打那些无法谷歌的诗。按着自己的味道挑,最后超过了三百首——诗经以后所有诗集自觉的数字。

这篇博客的地址是:作现代诗重要的整理与最大的搬运

2014年年底,他写了当年最后一篇技术文章「我的2014技术流水帐」,文字如水,品之若酒,如果你是一个后端开发者,一定要读。

这篇博客的地址是:我的2014技术流水帐

思考之余,白衣还喜欢分享一些文艺女青年的照片,比如这样的


这样的

还有这样的

口味直追冯老师,只是文艺范更强悍一些。(当然,冯老师的故事我们以后有的说呢)

2014年逝去,2015不管不顾的来临,曾经白衣飘飘的江南少年已经不再年轻,但路上的风景依旧美妙,我们怀了年轻的心,奔走在苍老的路上。记住唐诺的话,一路向北!

我们缺的不再是知识,过多过廉价的知识像大仓库般丧失了美感、珍罕感,再不复有魅惑力量。

关于服务的一切

| Filed under 技术

6. 服务发现的选型Overview,除了ZooKeeper和etcd,还有其他。

 

5. 一切哲学都是对世界的一种自觉完满的解释,包括“白马非马”的名家,但也仅仅是其中一种解释,而不是世界的本源、真理。同样,面向对象也仅仅是代码的一种组织方式,因为与现实世界的常识相映射而容易理解,而已。在领域对象最火最魔怔的时候,也不觉得UserManager、AccountService有什么不对。 2-14-9-23

 
4. 现在更喜欢称呼自家的东西是JSON内容的HTTP API,而不是Restful Service。由那些R虫上脑,坚信一切皆是资源,死抱着Restful的大腿不肯放的学院派来设计协议,简直是灾难。

我遇到的死硬派:一个原子的操作,但认为涉及到两个"资源",生生拆成两个调用,万一第二个调用没收到我咋办呢,再额外做个超时回退的操作么。又如,通知接口明明可以把要通知的内容都送过去,被换成了一个资源的超链接...问题是,我发完通知就想删掉它呀,不会供着它让你哪天来访问...   2014-9-18

后来发现,其实不止我一个这样想,比如Heroku的那份设计指南,也叫做HTTP API Design Guide,这份指南集合了学院派与实战派中好的那一部分。
(Caption: 死抱着Restful的大腿)

 
3. 马丁花同志的长文:《Micro Services》

和那个被各大厂商用WS-* 和 ESB玩坏了的SOA比,从企业内多个应用之间的服务化,进化到了应用内的各个模块之间,也夹杂着这一个十年的Cloud、DevOps的诉求。

但后来,TW的技术雷达将Micro Services放到了谨慎的位置,毕竟分拆多了,运维的水平一定要跟上 2014-04-15

(Caption:一直想象不出一个叫花的男人是长什么样子的,后来才发现是fowler,不是flower)

 
2. InfoQ:《我们是否需要REST的替代品?》,又见反思,如 SDK vs API 那段。SoapUI作者的结论是,“在公用API领域REST依然是最好的,但有些场景的确需要一些替代方案,我并不反对这种多样性,相反我很乐于见到这一切。”

 

1. , 越来越多的基础组件, 在云里以服务的形式提供, 拍胸脯保证自己的运维与扩展性。也越来越多项目不再愿意自己花精力去运维一堆组件,哪怕是现成开源的, 而宁愿选择这些服务。 除了文中的例子,还有提供Metrics服务的Librato, Log管理的loggly等等。

by calvin | tags : | 0

《程序员必读之软件架构》读书笔记 I

| Filed under 技术

codingthearchitecture.com网站作者 Simon Brown的书。编码的架构师,一直是我的职业模板。
而当年我觉得RUP的基于4+1视图的机械架构文档模板不足以表达系统时,Simon Brown的模板给了很好的过渡范例。

 

架构师应该编码吗?

有些公司认为架构师太宝贵了,不该承担日常编码工作。
有人认为优秀的架构师的重要特征是抽象思维能力,也可以理解为不把时间耗在细节里。
还有一些大型项目通常意味着照看更大的“大局”,有可能你根本没时间写代码。

以上都对。

 

你不必放弃编码,也不要把大部分时间用于编码

你不应该因为“我是架构师”,就把自己排除在编码之外。
但也必须有足够的时间扮演技术架构师的角色。

1. 参与编写代码

要避免成为PPT架构师, 最好是参与实现与交付的过程,确保架构的交付,了解设计在实现上的问题,演进架构而不是画完框图就交给实现团队从此不管。
同时,缩短与团队的距离,保持对团队的影响力,帮助团队对架构的正确理解,分享自己软件开发的经验。

另外,作为开发团队的一份子,你不需要是开发代码最好的。

2. 构建原型、框架和基础

如果不能参与日常编码,至少尝试在设计时快速构建原型去验证你的概念。
还有为团队编写框架和基础,这也是最磨练与体现编码与设计能力的时刻。

3. 进行代码评审

如果完全没有时间编码,至少参与代码评审,了解发生了什么。

4. 实验并与时俱进

如果完全没有时间在工作时间里编码,在工作之外你往往有更多空间来维持编码技能,从贡献开源项目,到不断尝试最新的语言、框架。

一般来说,一个写代码的软件架构师会更有成效也更快乐。

文章持续修订,转载请保留原链接: http://calvin1978.blogcn.com/articles/software-architecture-for-developers.html

by calvin | tags : | 6

站在岸上看DEVOPS

| Filed under 工作 技术

今年项目要试水(X)AAS,尝试运维自己的产品,便离不开这几年最热的单词—DEVOPS。趁还在岸上,理解下DEVOPS对开发人员来说意味着什么。

因为没有实战,也就纸上谈兵一下,真正有经验的人, @连城404:为了分摊黑锅,运维发明了devops和full stack。

What is DEVOPS ?

十年前,敏捷出现,以反瀑布流程的方式模糊了需求、架构、开发、测试之间的界限,但对整个软件价值链的最后一环,交付与运维并没有太多的强调,造成一个有趣的现象是,产品以三周为迭代进行开发并交付给客户,但只充当与客户演示并收集反馈的媒介,而客户仍然会有自己独立的上线周期。

十年后,越来越多的互联网站与手机应用,需要频繁而持续的发布,每次发布需要部署到大量的机器集群上,需要不中断和破坏当前服务,在发布前能提供本次发布质量的证明,在发布后对系统有实时的监控,支持错误转移、服务降级,支持快速定位和修复故障。

显然,只靠传统运维人员的知识技能集(操作系统、网络、Shell脚本编写) 以及开发人员编写的的产品管理手册已不足以满足上述的需求了。好在,有敏捷的先例,解决方法是现成的——把开发拖下水吧:

1. 人员上,运维人员要更懂产品的架构与内在,而不只是那份管理员手册。开发人员要懂实际的运维,从实际部署、上线流程,到故障的定位与解决。当然,最重要是打通两个部门间的隔阂。

2. 产品特性上,运维所需的功能甚至运维的基础设施,成为了产品非功能性需求的重要一部分。

3. 流程上,产品交付与运维,接入整个软件生产周期构成一个完整的环。
 

What should developer do?

现在大家最关心的问题来了,DEVOPS的大旗下,开发人员到底要参与多少运维?

这幅图,又是零到一百之间的选择,各个组织根据自己的人员、技术,文化,找到自己最合适的那个平衡点。

理论上,开发人员在DEVOPS中可以有两种的参与:

一,为运维而开发。

比如,在代码中加入Metrics收集的代码,向Graphite吐出服务的调用次数与延时,通常是与运维协作的第一步——运维可以在CPU,内存占用与应用日志之外,不那么黑盒的看待应用了。

又比如,要和运维商量着,在代码端需要做些什么,才能实现监控,无中断升级,动态节点扩展,故障转移,服务降级,跨机房容灾。这些功能以前可能也是要的,但现在需求的采集更注重实效。甚至,运维的一些基础设施,也可以由开发代劳了。

又比如,环境与流程的统一,原来只在简版的集成测试环境上跑完功能测试就完事的开发闭环,现在需要考虑至少延伸到一台从服务器配置到数据库部署模型等都贴近生产环境的Staging服务器,又比如测试环境的安装部署,也会用和运维一样的基于Ansible 或 Saltstack。

二,开发直接参与运维。

也是最存在争议的地方,比如系统的上线升级,日常的运维操作,故障的即时修复。

开发人员参与运维,可以吃自己的狗粮,可以更深切的了解运维功能的需求,开发人员的故障修复更快,但是——

程序员是不是应该做更有创造性的事情?程序员做运维会不会感到厌烦?社会化分工还是不是一个无需争辩的现代社会真理?

其实类似的争论已发生过一次,在开发与测试的分工上。起码在我司,专门的测试人员仍然有不可动摇的作用,而开发人员,则承担了从持续的单元测试和功能测试,最后到手工的性能测试与稳定性测试,总体80%以上的测试工作量,很自然的合作。

所以,还是没有绝对,还是各个组织自己去通过不断的尝试,找到自己最合适的那个平衡点。

 

Reference

by calvin | tags : | 0

同事们关于FP语言的讨论与诗一首

| Filed under 工作 技术

缘起

 
达夫君:

利用 GitHub 统计分析编程语言发展趋势

 

第一轮讨论

 
梁君:

增加的Java的项目里,不知道有多少是与Android相关的呢?

Scala最热门都是在意大利城市(Milan, Rome, Florence, Naples,Turin),很奇怪,意大利软件业不发达。于是查了字典在意大利语里scala是scale(英语)的意思,应该跟编程语言无关。排除之后排首位的就是 San Francisco和San Jose,硅谷地区。

最近几天在看 Haskell,真是非常有趣的一门语言。
于是也在Google Trends上看一下,搜索Haskell最热的城市是 Gothenburg,第二是Utrecht (因为乌特勒支大学?)。

2014年热度,按国家排序,Haskell最热也是China! 考虑到中国已经屏蔽了Google,这个结果令人吃惊。在国内Scala, Haskell也不是那么热门吧?程序员人口基数大?

雄君:

Haskell应该是所有程序语言里面被神化的最厉害的吧。
有种说法,Haskell可以让你变成一个更好的程序员,即便你不用它,好像还有本书名就是这个。
感觉看几本Haskell书就能变成高手似的,快变成宗教了都。。。。

梁君:

Haskell应该是一种研究型/教学型语言吧。
据说是纯粹的FP,我现在看它是想试试强迫一下自己使用FP的思维模式。

那篇WhyWhyFP不错。 里面,看到一些话(虽然不算是那篇文字的主题):

The key is the word better. It is not the same as the phrase more powerful.
it is possible to make a language “better” by removing features that are considered harmful, if by doing so it makes programs in the language better programs.

关于 better 与 powerful 的思考,不是功能越多就越好。用在我们的产品上也是一样啊。

 

哥德堡的Haskell教授

 
赵君:

Gothenburg研究Haskell的那个人好像是Richard君的教授。感兴趣的可以问问Richard的感受。

范君:

Richard说的:

Mr Hughes is a very smart guy. And his homepage hasn’t changed since I had him as a professor : http://www.cse.chalmers.se/~rjmh/

国外大学很多都是用Haskell,大老板之前去大英帝国读研也是用它。

 

FP做题大赛

 
韶君:

我好奇看一下,“证明即程序、命题为类型”,这就是一门数学领域的领域语言,难怪学院派对它宠爱有加,一边证明一边编程,逼格高啊

有个网站号称趣味学Haskell, HASKELL 趣學指南

Step by step学了一下Haskell,居然停不下来,无论写还是读,都像在玩puzzle game,都想找回以前的数学课本来复习一下。我想不用也能让你成为更好的程序员此话不假,就是让你恶补一下已经还给老师的数学概念。给个零零漆的经典应用题大家思考一下:有一个农场,鸡的数目是鸭的四倍,但是鸭又比猪少九只,鸭和猪的数目是六十七只,请问农场所有动物的脚加起来共多少只?

雄君:

感觉这跟你的学习方式关系更大,跟语言关系不大的。你也可以用Scala去做SICP的习题,同样有这种感觉。

梁君:

不挑起具体语言之争
韶君的例子应该是说明FP给人带来耳目一新的感觉。

另外,我感觉那本书用来做FP入门真的很好,之前看过一些Scala的书都没有那么清晰的理解。

顺便做做那道题目:

Prelude> head [c*2+d*2+p*4 | d<-[0..], let c=d*4, let p=d+9, d+p==67]442

韶君:

我原来写的是:

head [a*2+b*2+c*4|a <-[1,2..], b <-[1,2..], c <- [1,2..], a=4*b, b=c-9, b+c=67]

结果不会结束,除非数组加上限,有空找你理解一下。

确实是FP带来的感觉,相信Scala也可以带来这个感觉,只不过如果我用Scala就不自觉地当Java来做了。

达夫君:

我原来也是将Scala当Java来写。但是当你将Java的语法忘了差不多了,Scala就入门了:)
其实只是个老问题,就是平常没机会看Scala的代码,没有好的example参考而已。看别人的代码多了,也就习惯了。

梁君:

Scala应该增加一种纯FP模式,当打开这个选项的时候,任何不符合FP的写法都报错(或者warning)。

米君:

沒電腦,裸寫一段 Python,不知道對不對:

print map(lambda x: ‎x*2 + x*4*2 + (x+9)*4, filter(lambda x: x+x+9 == 67, range(0,67)))[0]

‎看起來還是 Haskell 的最有數學味。

邊打邊爐邊研究,或者還可以這樣(不知道對不對,大意如此):

print (x*2 + x*4*2 + (x+9)*4 for x in range(0, 67) if x+x+9 == 67‎)[0]

據說這樣有 lazy evaluation,map 和 filter 不知道有沒有。有明白人指點一下嗎?

韶君:

FP的思路就是“是什么”,指令编程的思路是“做什么”,从这个角度看这个最优雅了,基本上把题目复述一遍而已

head [c*2+d*2+p*4 | d<-[0..], let c=d*4, let p=d+9, d+p==67]

雄君:

米君,你已经线下把三元方程转成一元了,这个是作弊吧,不算。
Haskell的lazy evaluation在这么小的程序里面也会搞出无限循环的bug,这是它没法商用的最大原因之一。

我发一个Clojure的,也符合数据的解方程思路。

(first (for [p (range 1 67)
      :let [d (- 67 p) c (* 4 d)]
      :when (= d (- p 9))]
  (+ (* p 4) (* d 2) (* c 2))))
442

梁君:

这个我忍不住要说说了,上限没有在原题中给出,需要推理才能得到的

Haskell的程序里是没有设上限的:a <-[1..], b <-[1..], c <- [1..]
你们写的其他程序都是有上限的:p (range 1 67),x in range(0, 67),(1 to 67)
用这个来说Haskell会搞出无限循环的bug是不是有点冤枉了?

p.s. FP的理论在那里,现代的语言都或多或少吸取进去了,只是用什么语法形式的问题,纯粹一些还是要跟原来的特性做妥协,大家也都相互借鉴。除了Java最不思上进。

看上去Clojure的语法最像Lisp。

米君:

不服上訴。哈哈。

這樣呢?算不算真三元?
(已經盡力了。除非改成一元,否則range 好像是繞不過的坎,如果改成無限列表也是一樣會死循環。)

print iter( c*2 + d*2 + p*4 for c in range(67*4) for d in range(67) for p in range(67) if c == d*4 and d == p-9 and d+p == 67).next()

Clojure的版本和Java看上去很像啊。唯一不同大概就是 lazy evaluation吧。
另外,雖然定義了三個變量,但其實只有一個是真正的“變”量,所以還是一元。

for ( int p = 1; p <=67; d++) {      int d = 67 - p;      int c = d * 4;      if ( d == p - 9 ) System.out.println( c*2 + d*2 + p*4 )  }

雄君:

其实完全不是那么一回事,Scala和Clojure里面的for不是循环的意思,达夫之前解释过。这是Java程序员转FP的第一重障碍。另外,Clojure这段代码绝对没有lazy evaluation,如果需要Lazy,Clojure必须要明确指定使用Lazy seq。

Python和Java的表达能力不可能赶上Lisp的,超过Lisp表达能力的语言还没有发明出来。

 

最后一轮讨论

 
雄君:

Clojure是一个Lisp变种,也是目前唯一的一个商业化的Lisp系语言。

Haskell是lazy evaluation by default的语言,全世界几乎独此一家了。这个特性导致程序运行时,时间和空间都是不可预期的,基本上没有企业敢用。

Haskell又为了程序在逻辑上的predictable,从语言成面回避side effect,结果连个随机数生成都搞不定,发明monad来解决这个问题。问题是monad这么复杂的东西,用Haskell开发竟然是必须掌握的技巧,这很恐怖啊,哪找程序员?

这语言真的是只能看的。

韶君:

Haskell我觉得商业上想取得成功确实不容易,但我不觉得作者想这样做,说商用,有哪种语言比Java更成功呢,指令语言也没那么容易出错,因为指令语言只有想不到,没有做不到,想取得商业成功就意味着妥协,从这个角度,我更看好Scala。

达夫君:

估计等大家要看Java8的时候就需要考虑是升级JDK到8呢还是换Scala了。

梁君:

Haskell 就是一门教学/研究型语言,开个学术会议,几个老家伙聚在一起,说不如我们设计个语言来显示一下FP多牛B吧。商业成功不是它设计的初衷 (后来其他人怎么想是另外一回事)

At the conference on Functional Programming Languages and Computer Architecture (FPCA '87) in Portland, Oregon, a meeting was held during which participants formed a strong consensus that a committee should be formed to define an open standard for such languages. The committee's purpose was to consolidate the existing functional languages into a common one that would serve as a basis for future research in functional-language design.

才发现BASIC不是我唯一的入门语言,我刚学电脑的时候还看过Logo语言,这么说我也是一开始就接触FP的啦。

对Java程序员和已经大量投资于Java的软件企业来说,应该是Scala最有价值。

雄君:

我是前几年被人忽悠后花了好几个月学习Haskell,还想用它做项目,现在已经弃坑了。

 

诗一首

《孤独时》

孤独时我不喜欢使用语言。
一头熊和一只鹦鹉坐在
跷跷板的两头
跷跷板朝一头翘起。很多东西
没办法称量,我是熊你们是鹦鹉。
我是这头熊我不使用
你们的语言。

-- 余怒,2003.7.20

by calvin | tags : | 2