滕王阁序

发布在

时隔多年,又偶然看见了高中课堂上学过的《滕王阁序》,突然明白了当时语文老师为什么能那么充满激情的讲解,有些东西——没有一定的年龄和阅历是看不懂的。
以前只是觉得这是要求背诵的课文,真讨厌。但是现在读到

“嗟乎!时运不齐,命途多舛。冯唐易老,李广难封。屈贾谊于长沙,非无圣主;窜梁鸿于海曲,岂乏明时?所赖君子见机,达人知命。老当益壮,宁移白首之心?穷且益坚,不坠青云之志。酌贪泉而觉爽,处涸辙以犹欢。北海虽赊,扶摇可接;东隅已逝,桑榆非晚。孟尝高洁,空余报国之情;阮籍猖狂,岂效穷途之哭!”
心中却有了不可名状的触动。每个人都渴望做出名留青史的一番事业,但更多数的人却过完了普普通通的一生。或许是因为最近有些焦躁,觉得自己都这个年龄了却还一事无成才会有所触动吧。明知道这种事急不来,却依然恨不得明天就能做出一番轰轰烈烈的大事来。最近最明显的一个感觉就是,以前日子是一天一天过的,现在是一周一周过的,再过几年就是一个月一个月过的了吧。
突然想起丰子恺的一句话:孩子,我多么羡慕你们!羡慕你们的现在的生活!但是当你们明白我这句话的时候,你们已经不再令我羡慕了。就好像,长大了才知道《麦兜》不是给孩子看的,《幽游白书》的结局为什么那么平淡。

有人说,以前看《大话西游》看着看着就笑了,现在却是看着看着就哭了。虽然再次重温经典的时候我没有哭,却笑不出来了。以前一直觉得片尾夕阳武士对着悟空背影说的那句“他好像一条狗”十分突兀,不明所以。现在明白,电影中表明至尊宝最后顿悟了,带上头箍是为了保护唐僧取经,让大众脱离苦海,而非单单为了拯救紫霞。选择事业放弃爱情,却抹不掉心中的那个人影,这也就是最后悟空借夕阳武士之口对自己说“你好像一条狗”的原因吧。

你好像一条狗。

评论和分享

NodeJS学习记录1

发布在 Nodejs

本来学oc学的正爽,结果由于某些原因必须先学习NodeJS,所以oc的学习就先暂停一段时间吧。这几天恶补了相关基础知识,如果oc只是语法上让我不太习惯的话,那nodejs就是从编程思想上将原来所学的知识进行了颠覆。至于nodejs相关介绍、优缺点等这里就不多说了,如果想在学习过程中不“一头雾水”,就要理解几个概念:同步/异步、阻塞/非阻塞、闭包、回调、事件轮循。

本人以前并没有任何javascript语言的学习经验,这里仅仅记录我这几天学习的理解,如有什么偏颇,还望大家指正。

首先,nodejs是单线程的,同时只能进行一项任务。这点引起较大的批评就是无法利用多核CPU的能力,但同时在多个CPU运行程序也并不是完美的,因为想要多个CPU有效的拆分任务并执行,它们之间需要频繁的交换信息,比如当前执行状态、各自完成了哪些操作等。

关于上面的几个概念,网上答案五花八门都有,不过我更倾向于下面的答案,引用于知乎,原文链接

“阻塞”与”非阻塞”与”同步”与“异步”不能简单的从字面理解,提供一个从分布式系统角度的回答。

1.同步与异步

同步和异步关注的是消息通信机制 (synchronous communication/ asynchronous communication)

所谓同步,就是在发出一个调用时,在没有得到结果之前,该调用就不返回。但是一旦调用返回,就得到返回值了。

换句话说,就是由调用者主动等待这个调用的结果。

而异步则是相反,调用在发出之后,这个调用就直接返回了,所以没有返回结果。换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果。而是在调用发出后,被调用者通过状态、通知来通知调用者,或通过回调函数处理这个调用。

典型的异步编程模型比如Node.js

举个通俗的例子:

你打电话问书店老板有没有《分布式系统》这本书,如果是同步通信机制,书店老板会说,你稍等,”我查一下”,然后开始查啊查,等查好了(可能是5秒,也可能是一天)告诉你结果(返回结果)。

而异步通信机制,书店老板直接告诉你我查一下啊,查好了打电话给你,然后直接挂电话了(不返回结果)。然后查好了,他会主动打电话给你。在这里老板通过“回电”这种方式来回调。

2.阻塞与非阻塞

阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态.

阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。
非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。

还是上面的例子,

你打电话问书店老板有没有《分布式系统》这本书,你如果是阻塞式调用,你会一直把自己“挂起”,直到得到这本书有没有的结果,如果是非阻塞式调用,你不管老板有没有告诉你,你自己先一边去玩了, 当然你也要偶尔过几分钟check一下老板有没有返回结果。

在这里阻塞与非阻塞与是否同步异步无关。跟老板通过什么方式回答你结果无关。

这里补充一下,老板给你打电话回来,然后你去取书就是”回调“。上面网友回答也说道了要偶尔check一下返回结果,个人的理解这就是事件轮循。并不是说这个check这个动作,而是你要找老板这个事件。比如你先去一边玩去了,然后觉得饿了给老妈打电话问饭做好了没,老妈说还没好,你就又继续玩去了。那么事件列表中此时就有2个事件:给老板打电话(确认书到没到)和给老妈打电话(确认饭做没做好)。

再说闭包,什么是闭包(closure)呢?这里又不得不提起“作用域”这个东东了。类比c++、c#、java来说,javascrept中函数内(域内)的成员是不能在域外访问的,类似于”私有成员“。那么怎么得到内部数据呢?这时,闭包就华丽丽的出场了。英语好的小伙伴可以直接看这里,我在下面直接引用了其中比喻非常好的那个小公主的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function princess() {
var adventures = [];
function princeCharming() { / ... / }
var unicorn = { / ... / },
dragons = [ / ... / ],
squirrel = "Hello!";
adventures.push(unicorn, dragons, squirrel);
return {
story: function() {
return adventures[adventures.length - 1];
}
};
}
var littleGirl = princess();
x = littleGirl.story();
y = littleGirl.dragons;
console.log(x);
console.log(y);

执行后结果是

1
2
3
localhost :: ~/mynode/v55 » node test.js
Hello!
undefined

可以看到,闭包是个函数,它可以让你在作用域访问到作用域内部的变量。这里多说一句,虽然javascrept中并没有”类“这一结构,但上面的例子明显就是一个”类“的实现。关于孩子取垃圾袋的类比也不错,代码如下

1
2
3
4
5
6
7
8
9
10
11
12
function makeKitchen () {
var trashBags = ['A', 'B', 'C']; // only 3 at first
return {
getTrashBag: function() {
return trashBags.pop();
}
};
}
var kitchen = makeKitchen();
kitchen.getTrashBag(); // returns trash bag C
kitchen.getTrashBag(); // returns trash bag B
kitchen.getTrashBag(); // returns trash bag A

这个例子中看出,闭包不单可以取得值,还能改变它。这里不得不佩服歪国人那强大的类比能力,正如爱因斯坦说的:

If you can’t explain it to a six-year-old, you really don’t understand it yourself.

至于更底层的细节,比如inx和windows系统中实现异步的库并不一样啦、内存分配回收神码的,作为初学者的我也不懂,有兴趣的同学可以自行研究。

在fedora21中使用’yum install nodejs’安装即可,会自动把npm管理工具安装上,npm就是python的pip,负责三方模块的安装。当然也可以去官网下载源码或相应安装包进行安装。安装完毕后使用”node -v”可以查看版本,这里我安装的是0.10.36。接下来,直接使用node命令进入Node解释器,老规矩,先”hello world“一下:

1
2
3
$ node
> console.log("hello world!")
hello world!

至于上面说的“同一时刻只能执行一项操作”从下面的代码可以加深理解:

1
2
3
4
5
6
7
eve = require('events').EventEmitter;  
e = new eve();
die = false;
e.on('die',function(){die = true;});
setTimeout(function(){e.emit('die')},1000);
while(!die){}
console.log("done");

上面的代码永远不会输出done,虽然我们设定了1秒钟后通过事件回调将die设为true,但while循环在这里是永远执行不完的,回调事件永远没机会被触发。

评论和分享

mongodb的集群部署有3种方式,这里记录我在使用Replica Set(副本集)部署时的步骤。

首先这种方式至少需要3个节点——主、备、仲裁节点。主备节点存储数据,仲裁节点不存储数据,负责决定主节点挂掉之后哪个备节点升级为主节点。客户端同时连接主节点与备节点,不连接仲裁节点。

安装mongodb,CentOS下安装rpmfusion源后使用yum安装即可:yum install mongodb mongodb-server

安装完成后,修改/etc/mongodb.conf 这个配置文件。

1
2
3
4
5
6
7
8
9
10
11
bind_ip = 192.168.4.50
port = 27017
fork = true
pidfilepath = /var/run/mongodb/mongodb.pid
logpath = /var/log/mongodb/mongodb.log
dbpath =/var/lib/mongodb
journal = true
directoryperdb=true
logappend=true
replSet=testrs
noprealloc=true

其中注意修改bind_ip为各个节点的IP,下面的4行是我添加的:

  1. directoryperdb:为每一个数据库按照数据库名建立文件夹存放
  2. logappend:以追加的方式记录日志
  3. replSet:replica set的名字
  4. noprealloc:不预先分配存储

修改完成后,使用service mongod start即可启动服务。

随便链接一个节点后,进行配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
[root@pxc_bj63 ~]# service mongod start
Starting mongod: [ OK ]
[root@pxc_bj63 ~]# clear
[root@pxc_bj63 ~]# mongo 192.168.4.63:27017
MongoDB shell version: 2.4.12
connecting to: 192.168.4.63:27017/test
> use admin
switched to db admin
> conf = {_id:"testrs",members:[{_id:0,host:"192.168.4.63:27017",priority:2},{_id:1,host:"192.168.4.64:27017",priority:1},{_id:2,host:"192.168.4.50:27017",arbiterOnly:true}]};
{
"_id" : "testrs",
"members" : [
{
"_id" : 0,
"host" : "192.168.4.63:27017",
"priority" : 2
},
{
"_id" : 1,
"host" : "192.168.4.64:27017",
"priority" : 1
},
{
"_id" : 2,
"host" : "192.168.4.50:27017",
"arbiterOnly" : true
}
]
}

注意最初的_id的值就是我们配置文件中设定的replSet的值,arbiterOnly是大写的O,配置完成后进行初始化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
> rs.initiate(conf)
{
"info" : "Config now saved locally. Should come online in about a minute.",
"ok" : 1
}
> rs.status()
{
"set" : "testrs",
"date" : ISODate("2015-03-03T03:17:25Z"),
"myState" : 1,
"members" : [
{
"_id" : 0,
"name" : "192.168.4.63:27017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 460,
"optime" : Timestamp(1425352584, 1),
"optimeDate" : ISODate("2015-03-03T03:16:24Z"),
"self" : true
},
{
"_id" : 1,
"name" : "192.168.4.64:27017",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 60,
"optime" : Timestamp(1425352584, 1),
"optimeDate" : ISODate("2015-03-03T03:16:24Z"),
"lastHeartbeat" : ISODate("2015-03-03T03:17:25Z"),
"lastHeartbeatRecv" : ISODate("2015-03-03T03:17:25Z"),
"pingMs" : 0,
"syncingTo" : "192.168.4.63:27017"
},
{
"_id" : 2,
"name" : "192.168.4.50:27017",
"health" : 1,
"state" : 7,
"stateStr" : "ARBITER",
"uptime" : 58,
"lastHeartbeat" : ISODate("2015-03-03T03:17:25Z"),
"lastHeartbeatRecv" : ISODate("2015-03-03T03:17:24Z"),
"pingMs" : 1
}
],
"ok" : 1
}
testrs:PRIMARY>

插入一条数据试试:

1
2
3
testrs:PRIMARY> use test
switched to db test
testrs:PRIMARY> db.testdb.insert({"test1":"i'm master"})

目前,备节点是无法查询数据的:

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@pxc_bj_64 ~]# mongo 192.168.4.64
MongoDB shell version: 2.4.12
connecting to: 192.168.4.64/test
Welcome to the MongoDB shell.
For interactive help, type "help".
For more comprehensive documentation, see
http://docs.mongodb.org/
Questions? Try the support group
http://groups.google.com/group/mongodb-user
testrs:SECONDARY> use test;
switched to db test
testrs:SECONDARY> show tables;
Tue Mar 3 11:41:00.274 error: { "$err" : "not master and slaveOk=false", "code" : 13435 } at src/mongo/shell/query.js:128

需要进行配置:

1
2
3
testrs:SECONDARY> db.getMongo().setSlaveOk();
testrs:SECONDARY> db.testdb.find();
{ "_id" : ObjectId("54f52c9073b3842303717165"), "test1" : "i'm master" }

设定setSlaveOK后便可以进行数据查询了。

现在,停止主库的服务,再查看整个集群的状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
testrs:SECONDARY> rs.status();
{
"set" : "testrs",
"date" : ISODate("2015-03-03T03:48:40Z"),
"myState" : 1,
"members" : [
{
"_id" : 0,
"name" : "192.168.4.63:27017",
"health" : 0,
"state" : 8,
"stateStr" : "(not reachable/healthy)",
"uptime" : 0,
"optime" : Timestamp(1425353872, 1),
"optimeDate" : ISODate("2015-03-03T03:37:52Z"),
"lastHeartbeat" : ISODate("2015-03-03T03:48:39Z"),
"lastHeartbeatRecv" : ISODate("2015-03-03T03:47:39Z"),
"pingMs" : 0
},
{
"_id" : 1,
"name" : "192.168.4.64:27017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 2317,
"optime" : Timestamp(1425353872, 1),
"optimeDate" : ISODate("2015-03-03T03:37:52Z"),
"self" : true
},
{
"_id" : 2,
"name" : "192.168.4.50:27017",
"health" : 1,
"state" : 7,
"stateStr" : "ARBITER",
"uptime" : 1905,
"lastHeartbeat" : ISODate("2015-03-03T03:48:39Z"),
"lastHeartbeatRecv" : ISODate("2015-03-03T03:48:40Z"),
"pingMs" : 1
}
],
"ok" : 1
}

此时原来的备节点变成了主节点,此时我们新插入一条数据:

1
2
3
4
testrs:PRIMARY> db.testdb.insert({"test2":"i'm new master"})
testrs:PRIMARY> db.testdb.find();
{ "_id" : ObjectId("54f52c9073b3842303717165"), "test1" : "i'm master" }
{ "_id" : ObjectId("54f52f70abb951d25573981e"), "test2" : "i'm new master" }

重启原来的主节点并查看状态:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
[root@pxc_bj63 ~]# mongo 192.168.4.63
MongoDB shell version: 2.4.12
connecting to: 192.168.4.63/test
testrs:PRIMARY> rs.status()
{
"set" : "testrs",
"date" : ISODate("2015-03-03T03:50:57Z"),
"myState" : 1,
"members" : [
{
"_id" : 0,
"name" : "192.168.4.63:27017",
"health" : 1,
"state" : 1,
"stateStr" : "PRIMARY",
"uptime" : 59,
"optime" : Timestamp(1425354608, 1),
"optimeDate" : ISODate("2015-03-03T03:50:08Z"),
"self" : true
},
{
"_id" : 1,
"name" : "192.168.4.64:27017",
"health" : 1,
"state" : 2,
"stateStr" : "SECONDARY",
"uptime" : 59,
"optime" : Timestamp(1425354608, 1),
"optimeDate" : ISODate("2015-03-03T03:50:08Z"),
"lastHeartbeat" : ISODate("2015-03-03T03:50:56Z"),
"lastHeartbeatRecv" : ISODate("2015-03-03T03:50:57Z"),
"pingMs" : 0,
"lastHeartbeatMessage" : "syncing to: 192.168.4.63:27017",
"syncingTo" : "192.168.4.63:27017"
},
{
"_id" : 2,
"name" : "192.168.4.50:27017",
"health" : 1,
"state" : 7,
"stateStr" : "ARBITER",
"uptime" : 57,
"lastHeartbeat" : ISODate("2015-03-03T03:50:56Z"),
"lastHeartbeatRecv" : ISODate("2015-03-03T03:50:56Z"),
"pingMs" : 0
}
],
"ok" : 1
}

查询数据也同步过来了:

1
2
3
4
5
6
7
8
9
10
11
12
testrs:PRIMARY> db.testdb.find();
{ "_id" : ObjectId("54f52c9073b3842303717165"), "test1" : "i'm master" }
{ "_id" : ObjectId("54f52f70abb951d25573981e"), "test2" : "i'm new master" }

当主节点恢复后,备节点查询数据时会提示:

testrs:PRIMARY> db.testdb.find();
Tue Mar 3 11:53:00.354 DBClientCursor::init call() failed
Error: error doing query: failed
Tue Mar 3 11:53:00.355 trying reconnect to 192.168.4.64:27017
Tue Mar 3 11:53:00.356 reconnect 192.168.4.64:27017 ok
testrs:SECONDARY>

如果要向集群中新增节点,则进行如下操作:

1
2
3
cfg = rs.conf()
cfg.members[3] = {_id:3,host:"192.168.4.42:27017",priority:0.5}
rs.reconfig(cfg)

新的备份节点配置之前是无法读数据的,记得设定setSlaveOK,不过虽然可读但备份节点还是不可写的。如果想修改配置也同理,首先得到当前配置信息,以修改优先级为例:

1
2
3
4
5
cfg = rs.conf()
cfg.members[0].priority = 0.5
cfg.members[1].priority = 2
cfg.members[2].priority = 2
rs.reconfig(cfg)

一定记得reconfig后新配置才会生效。

评论和分享

  • 第 1 页 共 1 页
作者的图片

Roy

微信公众号:hi-roy


野生程序猿


China