• 使用 shell 获取进程,并删除
1
2
3
4
5
6
7
8
9
10
11
12
13
#取得当前进程号
current_pid=$$
#获得特定进程号并重定向到一个临时文件中
ps -aux|grep "/usr/sbin/httpd" | grep -v "grep"| awk '{print $2}' >/tmp/${current_pid}.txt
#commands start
for pid in `cat /tmp/${current_pid}.txt`
do
{
echo "kill -9 $pid"
kill -9 $pid
}
done
rm -f /tmp/${current_pid}.txt
  • shell 的函数处理
1
2
3
4
5
6
7
8
9
func()
{
echo $a $b $c
echo $1 $2 $3
}
a="aaa"
b="bbb"
c="ccc"
func $a e f

函数传参是通过 funcname $para1 $para2 …,函数内部是使用$1,$2,$3
结果为:

1
2
aaa bbb ccc
aaa e f
  • 信号捕捉
    trap可以使你在脚本中捕捉信号,命令形式为trap name signal(s)
    其中,name是捕捉到信号以后所采取的一系列操作。实际中,name一般是一个专门用来处理所捕捉信号的函数。name需要用双引号(“”)引起来。signal是待捕捉的信号。
    最常见的行动包括: 清除临时文件 忽略该信号(如trap “” 23) 询问用户是否终止该脚本进程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
trap 'exitprocess' 2    #捕捉到信号2之后执行exitprocess function
LOOP=0
function exitprocess()
{
echo "You Just hit <CTRL-C>, at number $LOOP"
echo "I will now exit"
exit 1
}
while : # 循环直到捕捉到信号(注意中间的空格)
do
LOOP=$LOOP+1
echo $LOOP
sleep 1
done

给一个文本,获取其中2000 ~ 3000 行怎么破?

1
cat data.txt | tail -n +2000 | head -n 1000 > result.txt

查找文件是否存在

1
find /data -name hello.cpp 

以前在Amazon Web ServiceAWS 做过Hadoop 运算,处理业务逻辑,当时也曾在自己电脑做一个单一的节点模拟.在Tencent 有机会处理tencent 游戏的海量数据分析,这时候用到的是公司的TDW,也是基于Hadoop 的改造。大数据被炒的火热,特别是某些公司会把这些当作自我标榜更是让人恶心.本着折腾的信,把自己玩hadoop的过程写下来 :)

  • 创建hadoop用户组;
1
2
sudo addgroup hadoop
sudo adduser -ingroup hadoop hadoop

给hadoop用户添加权限,编辑/etc/sudoers文件; 在root ALL=(ALL:ALL) ALL下

1
hadoop  ALL=(ALL:ALL) ALL
  • 在Ubuntu下安装JDK
1
2
3
sudo apt-add-repository ppa:flexiondotorg/java
sudo apt-get update
sudo apt-get install sun-java6-jre sun-java6-jdk sun-java6-plugin

如果你在第二条命令遇到错误:

1
2
3
W: GPG 错误:http://ppa.launchpad.net precise Release: 由于没有公钥,无法验证下列签名: NO_PUBKEY 2EA8F35793D8809A
请执行
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 2EA8F35793D8809A

编辑 sudo vi /etc/environment
在其中添加如下两行:

1
2
JAVA_HOME=/usr/lib/jvm/java-6-sun
CLASSPATH=.:/usr/lib/jvm/java-6-sun/lib
  • 安装ssh 服务
1
sudo apt-get install ssh openssh-server

首先要转换成hadoop用户,执行以下命令:

1
su - hadoop

采用 rsa 方式 生成key

1
ssh-keygen -t rsa -P ""

进入~/.ssh/目录下,将id_rsa.pub追加到authorized_keys授权文件中,使其无密码登录本机

1
2
cd ~/.ssh
cat id_rsa.pub >> authorized_keys
1
sudo cp hadoop-0.20.203.0rc1.tar.gz /usr/local/

解压hadoop-0.20.203.tar.gz;

1
2
cd /usr/local
sudo tar -zxf hadoop-0.20.203.0rc1.tar.gz

将解压出的文件夹改名为hadoop;

1
sudo mv hadoop-0.20.203.0 hadoop

将该hadoop文件夹的属主用户设为hadoop,

1
sudo chown -R hadoop:hadoop hadoop

打开hadoop/conf/hadoop-env.sh文件;

1
sudo vi hadoop/conf/hadoop-env.sh

配置conf/hadoop-env.sh,配置本机jdk的路径;

1
2
3
export JAVA_HOME=/usr/lib/jvm/java-6-sun/
export HADOOP_HOME=/usr/local/hadoop
export PATH=$PATH:/usr/local/hadoop/bin

记得source hadoop-env.sh

编辑conf/core-site.xml文件;

1
2
3
4
5
6
7
8
9
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<!-- Put site-specific property overrides in this file. -->
<configuration>
<property>
<name>fs.default.name</name>
<value>hdfs://localhost:9000</value>
</property>
</configuration>

编辑conf/mapred-site.xml文件;

1
2
3
4
5
6
7
8
9
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<!-- Put site-specific property overrides in this file. -->
<configuration>
<property>
<name>mapred.job.tracker</name>
<value>localhost:9001</value>
</property>
</configuration>

编辑conf/hdfs-site.xml文件;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<configuration>
<property>
<name>dfs.name.dir</name>
<value>/usr/local/hadoop/datalog1,/usr/local/hadoop/datalog2</value>
</property>
<property>
<name>dfs.data.dir</name>
<value>/usr/local/hadoop/data1,/usr/local/hadoop/data2</value>
</property>
<property>
<name>dfs.replication</name>
<value>2</value>
</property>
</configuration>
  • 运行hadoop,并启动
1
2
3
cd /usr/local/hadoop/
bin/hadoop namenode -format // 进入hadoop目录下,格式化hdfs文件系统
bin/start-all.sh //启动脚本

检测hadoop是否启动成功

1
2
3
4
5
6
7
hadoop@hp:/usr/local/hadoop/bin$ sudo jps
11822 DataNode
12461 Jps
11581 NameNode
12157 JobTracker
12064 SecondaryNameNode
12377 TaskTracker

说明hadoop单机版环境配置好了
此时访问http://localhost:50030/,便可以看到管理界面

让我们来完成那篇著名论文的wordcounw吧

创建输入文件夹,并挂载hdfs

1
2
3
hadoop@hp:/usr/local/hadoop$ mkdir input //创建输入文件夹
hadoop@hp:/usr/local/hadoop$ cp conf/* input
hadoop@hp:/usr/local/hadoop$ bin/hadoop fs -put input/ input

执行wordcount程序,输入为input,输出数据目录为output。,

1
bin/hadoop jar hadoop-examples-0.20.203.0.jar wordcount input output

出现了运行情况如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
13/09/22 17:59:40 INFO input.FileInputFormat: Total input paths to process : 15
13/09/22 17:59:41 INFO mapred.JobClient: Running job: job_201309221738_0006
13/09/22 17:59:42 INFO mapred.JobClient: map 0% reduce 0%
13/09/22 17:59:58 INFO mapred.JobClient: map 13% reduce 0%
13/09/22 18:00:07 INFO mapred.JobClient: map 26% reduce 0%
13/09/22 18:00:16 INFO mapred.JobClient: map 40% reduce 8%
13/09/22 18:00:22 INFO mapred.JobClient: map 53% reduce 13%
13/09/22 18:00:28 INFO mapred.JobClient: map 66% reduce 13%
13/09/22 18:00:31 INFO mapred.JobClient: map 66% reduce 17%
13/09/22 18:00:34 INFO mapred.JobClient: map 80% reduce 17%
13/09/22 18:00:37 INFO mapred.JobClient: map 80% reduce 22%
13/09/22 18:00:40 INFO mapred.JobClient: map 93% reduce 22%
13/09/22 18:00:46 INFO mapred.JobClient: map 100% reduce 26%
13/09/22 18:00:55 INFO mapred.JobClient: map 100% reduce 100%
13/09/22 18:01:00 INFO mapred.JobClient: Job complete: job_201309221738_0006
13/09/22 18:01:00 INFO mapred.JobClient: Counters: 25
13/09/22 18:01:00 INFO mapred.JobClient: Job Counters

查看执行结果

1
hadoop@hp:/usr/local/hadoop$ bin/hadoop fs -cat output/*

截取部分结果现场

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
hadoop@hp:/usr/local/hadoop$ hadoop fs -cat output/*
"". 4
"*" 10
"alice,bob 10
"console" 1
"hadoop.root.logger". 1
"jks". 4
79
$HADOOP_BALANCER_OPTS" 1
$HADOOP_DATANODE_OPTS" 1
$HADOOP_HOME/conf/slaves 1
$HADOOP_HOME/logs 1
$HADOOP_JOBTRACKER_OPTS" 1
$HADOOP_NAMENODE_OPTS" 1
$HADOOP_SECONDARYNAMENODE_OPTS" 1

停止hadoop

1
hadoop@hp:/usr/local/hadoop$ ./stop-all.sh 

hadoop这只小象在单机可以这么玩

leveldb是一个google实现的非常高效的kv数据库,能够支持billion级别的数据量了。 在这个数量级别下还有着非常高的性能,主要归功于它的良好的设计。特别是LSM算法。 LevelDB 是单进程的服务,性能非常之高,在一台4个Q6600的CPU机器上,每秒钟写数据超过40w,而随机读的性能每秒钟超过10w。@ideawu的ssdb就是基于Leveldb引擎开发的,看起来很NB的样子

它只是一个本地存储引擎:

  • k/v db library,提供持久化
  • No Server
  • No cache
    于是它精巧。

talk is cheap ,Show me the Code

简单示范一下C++使用Leveldb ,要先下载leveldb源码编译code

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
#include<iostream>  
#include<string>
#include"leveldb/db.h"

using namespace std;
using namespace leveldb;

int main()
{
DB *db;
Options options;
options.create_if_missing = true;
Status s = DB::Open(options,"/data/leveldb/lvd.db",&db);
if(!s.ok()){
cerr << s.ToString() << endl;
}
string key = "name",val = "leveldb";
s = db->Put(WriteOptions(),key,val);
if(!s.ok()){
cerr << s.ToString() << endl;
}
s = db->Get(ReadOptions(),key,&val);
if(s.ok()){
cout << key << "=" << val << endl;
s = db->Put(leveldb::WriteOptions(),"key2",val);
if(s.ok()){
s = db->Delete(leveldb::WriteOptions(),key);
if(!s.ok()){
cerr << s.ToString() << endl;
}
}
}
}

编译方法

1
g++ testleveldb.cpp -o main -I./Include -l./ -lleveldb -lrt

执行./main 之后便可以看到,leveldb的存储文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
zj@hp:~/lvd.db$ tree
.
├── 000003.log
├── CURRENT
├── LOCK
├── LOG
├── MANIFEST-000002
├── sst_0
├── sst_1
├── sst_2
├── sst_3
├── sst_4
├── sst_5
└── sst_6

很多语言都给予了binding,那么python 也不例外了 :) py-leveldb
你需要先安装python-leveldb库

1
2
3
4
import leveldb
db = leveldb.LevelDB('./db')
db.Put('hello', 'world')
print db.Get('hello')

如果你也和我一样蛋疼,你会不会想会有Server可以调用呢,再看下一篇吧 :)

昨天搞了一整天js,遇到了各种我从没遇到的问题,真心觉得前端工程师是很厉害的。想不出为什么会有人说所谓的前端“无技术含量”的源论.前端要考虑的东西实在是多,也有其架构设计。特别是js. 我用的是phonegap + jqtouch做移动App

场景是:
客户端使用Ajax技术向服务器发送请求,然后拉取数据

Server端代码是php写的,

1
2
3
4
5
$arr = array(
'user'=>'123',
'friends' => 234
)
echo json_encode($arr);

js代码,使用jquery发起get 请求,文件路径E:/mytest/test.html

1
2
3
4
5
6
$(function(){
url = "http://127.0.0.1/test.php"
$.get(url,funtion(result) {
alert(result);
})
);

看过jquery文档之后,我以为这样会返回我要的数据,真是图样图森破,chrome的控制台返回:不是同一个源,不允许跨域发请求。

#####什么是跨域请求
简单来说:a.com 域名下的js无法操作b.com或是c.a.com域名下的对象,上述场景中,http://127.0.0.1/test.php 和 E:/mytest/test.html本身就不属于同一个域下,因此不能访问。浏览器本身有同源策略,当初设计是出于安全考虑,百度给出了解释是:

 同源策略,它是由Netscape提出的一个著名的安全策略。现在所有支持JavaScript 的浏览器都会使用这个策略。所谓同源是指,域名,协议,端口相同。当一个浏览器的两个tab页中分别打开来 百度和谷歌的页面当一个百度浏览器执行一个脚本的时候会检查这个脚本是属于哪个页面的,即检查是否同源,只有和百度同源的脚本才会被执行。

我最后是通过查阅资料,采用jsonp的方式解决

#####什么是jsonp

 JSONP是JSON with Padding的略称。它是一个非官方的协议,它允许在服务器端集成Script tags返回至客户端,通过javascript callback的形式实现跨域访问(这仅仅是JSONP简单的实现形式) - 百度

因此最后的Server端代码是php写的

1
2
3
4
5
6
$arr = array(
'user'=>'123',
'friends' => 234
)
$callback = $_GET['callback']; //新加
echo $callback.json_encode($arr);

js代码,请求的时候,加入一个参数callback,通过javascripte callback形式调用服务器的scrpt tags的返回值

1
2
3
4
5
$(function(){
url = "http://127.0.0.1/test.php?callback=?"
$.get(url,funtion(result) {
alert(result);
}));

调用成功
这个东西纠结我大半天。但是有收获的 :)

最近和小伙伴们在做一个游戏。有机会单挑服务端了。被信任是有压力也有动力 :),可以尝试各种好玩的技术的感觉是很爽。Jerry 和Cat 所主导的客户端,Mzt的美术都很给力。作为云风的忠实粉,可以独立设计游戏服务器后台,我对这样的挑战期待已久。

逻辑架构图

主要由三大逻辑层组成:

  • 连接(接入)服务器模块: ConnServer
  • 游戏服务器模块 : GameServer
  • 缓存服务器模块: CacheServer
    (附:我们自己编写了静态资源的服务器功能,提供给用户下载Apk的功能)
  • 接入服务器模块
    服务器Socket建立,建立玩家通讯连接,为每一位连上服务器的玩家建立一个线程。
    服务器维护一个连接列表。采用map 的方式记录每一位玩家的连接信息。

  • 游戏服务器模块:
    这是处理游戏业务逻辑的主要模块。它包括了消息包解析器服务(Parser),游戏大厅服务(GameRoom),账户体系服务(Account),消息中心服务(MsgCenter),心跳服务(Heartbeat).日志功能模块(log)

  • 消息包解析器服务(Parser):主要实现了消息状态机。解析收到的客户端的数据包的协议号,然后将消息路由到不同功能模块去处理。
  • 账户体系服务(Account):提供用户注册和登陆管理的模块
  • 游戏大厅服务(GameRoom):采用Redis 内存数据库,构造消息队列。模拟游戏大厅,并对玩家进行配对筛选,构造set类型的匹配对完成1对1 的对战模式
  • 消息中心服务(MsgCenter):完成游戏过程中玩家信息的交互。
  • 心跳服务(Heartbeat):这是一个相对独立的进程,每7秒遍历用户信息,完成心跳检测,清理无效的过期数据,保持游戏数据的一致性.
  • 日志功能:打印程序中的日志。
  • 静态资源下载器(downloader):采用tornado拓展编写web服务,提供Apk静态资源下载的模块
  • 缓存服务器模块
    现阶段游戏对服务的要求不需要做到持久化的保存,于是服务器没有采用mysql之类的范式数据库。我们的数据收发一直处于频繁状态,于是我们采用了Redis这种分布式的内存数据库来实现我们的数据缓存模块,后续会介绍数据的键值设计

类图

  • cache数据库的设计:
    利用Redis的数据特性,新增一个用户保证用户ID的原子性。
  • counter: 对新用户的注册执行自增操作,从而保证账号Id 唯一
1
2
说明 key value
实例 counter 1
  • 用户账号:
    Key设计为 user:name:用户名’,Value用户ID,
    为保证用户可以同时通过id 查找名字 ,也设计了 ‘user:id:ID值’值为用户名
1
2
3
说明 key                    value
实例 User:name:zhengji 1
实例 User:id:1 zhengji
  • 玩家通讯缓存设计:
    Key值:user:用户名:msg: Value:‘分数,buff_id,时间戳’
1
2
说明 key              value
实例 user:zhengji:msg 100, 2, 1324256778.89
  • 玩家匹配对设计
    在游戏大厅的功能里,我们采用了redis的list模拟了玩家等待队列的功能 在真正匹配到玩家对的时候,使用table_xx 来记录玩家匹配信息,它是一个set的类型,在游戏退出的时候会被驱动去清除该表的信息
1
2
说明   key      value
实例 Table_1 ‘jerry,zhengji’
   

为标志每个玩家的table号,我们使用了另外一个键值对
Table:玩家名:tableindex.

1
2
说明   key       value
实例 Table:zhengji 1

Oracle初印象

曾经阿里的去O化搞得满城风雨,,随后很多企业也开始跟风去除Oracle,让Oracle这样的企业都为之咳嗽了一阵子。有兴趣的朋友可以看看王坚博士的文章。作为一个开源软件热爱者,首先接触到的一定是Mysql, 随后才是MongoDB,Redis,LevelDb。无论如何是怎么也想不到会去接触Oracle,就像我再也没有机会也不会去使用3.5英寸软盘的样子,因为这样会让我感觉到世界在倒退。

先知言:”存在即合理”。也就为以后的遇见埋下伏笔。果然,由于历史原因,庞大的业务体系下,我终于还是遇见了它,带着对伟大数据库敬仰的心探索了一把。说实话,当你习惯了简单的Mysql之类的思维之后,接触Oracle就有点纠结了。我愿意称其为接触另一种新思维方式。没有比这更值得鼓舞人心的动力了 :)

我做的事情是在游戏数据操作中做一个抽象的操作类。涉及框架代码的改造,这过程有点DT。我从事的工作大部分是C++开发这过程着实feel到了“生命太短,远离C++” 涉及到多重继承,虚析构函数,同个父类冲突,属性可见性,抽象类可用。Debug 了两天。还好有GDB这种家伙。
Oracle查询流程

简单描述下普通的Oracle建立连接以及查询的顺序,使用的是OCCI (Oracle的C++接口):

1
2
3
4
5
6
7
8
9
10
11
12
13
//创建enviroment变量
Environment *env = Environment::createEnvironment( Environment::DEFAULT);
//创建连接
Connection *conn = env->createConnection( userName, password, connectString);
//创建 查询描述符
Statement *stmt = conn->createStatement( "SELECT blobcol FROM mytable");
//执行查询,返回结果集
ResultSet *rs = stmt->executeQuery();
//关闭查询,环境变量
stmt->closeResultSet(rs);
conn->terminateStatement(stmt);
env->terminateConnection(conn);
Environment::terminateEnvironment(env);

蛋蛋的疼

期间遇到了Oracle 好多奇形怪状的问题。尽管如此,我喜欢这样折腾自己 :) 是不是有点变态。

  • 创建环境变量类指明多线程使用。该任务需要多线程执行的,如果不特别声明多线程执行,如果不特别指明的话会奔溃,我纠结了一天就是因为没有指明这个常量。这在Mysql是没有见到的吧
  • 连接管理。Oracle的连接关闭很重要。查询任务完成后要及时关闭连接。如果不关闭连接和环境句柄,程序就会有很大的潜在bug,程序执行期间也会奔溃。这过程中自己写了连接管理模块。特别处理了多线程处理时的构造与析构。

以下是连接管理类的代码

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
52
53
54
55
56
57
58
59
60
61
62
#include<string.h>
using namespace oracle::occi;
class COraclconn
{
public :

COraclconn (const std::string & user, const std:: string& password,
const std:: string& dbname)
{
m_status = false;
env = NULL;
conn = NULL;
stmt = NULL;
env = Environment::createEnvironment( Environment::THREADED_MUTEXED);
if (! env)
{
env = NULL;
return;
}
conn = env-> createConnection(user, password, dbname);
if (! conn)
{
conn = NULL;
return;
}
m_status = true;
}

~COraclconn ()
{
if ( conn && stmt)
conn-> terminateStatement( stmt);
if ( env && conn)
env-> terminateConnection( conn);
if ( env)
Environment:: terminateEnvironment( env);
}
Statement * getstmt( const string& sql)
{
if (! m_status)
return NULL;
if ( stmt)
{
conn-> terminateStatement( stmt);
stmt = NULL;

}
stmt = conn-> createStatement(sql);
if (! stmt)
{
stmt = NULL;
m_status = false;
}
return stmt;

}
protected :
bool m_status;
Environment *env ;
Connection *conn ;
Statement *stmt ;
};

还好我做的是封装SQL,对于其诡异的语法可以不用涉及到。相信每个热爱技术的人儿碰到写相对非业务的代码会感到充实愉快的吧。

Happy Hacking :)

作为新入职的员工,参加了公司为期10天的封闭培训,此文记下这些日子的一些感悟。 因为 “思绪来地快,去地也快” by 云风。

遇到的人

因为缘分,我和其他6位同学组成了小组(肆无忌惮组),其中一位是武大的博士(windsunwang),一位是来广研微信的华工师兄(xiaochunguo),有趣的是我们曾在网易面试的时候相遇,一位广研邮箱的中大师姐(vinajiang),琳琅天上的美术设计师(Mzt,鬼斧神功的画技,我们称之为大师),还有QQ空间的南大愤青,(杰哥),华科运维女(hazel),大家一起完成每一天的任务,默契也在合作中慢慢养成。感受到了windsunwang的博学和严谨,xiaochunguo的冷静,Mzt的艺术家气息,vinajiang的细腻,hazel的积极。当然还少不了杰哥这个SB :) ,他说他封闭培训的收获就是大师学会画蜗牛,囧。在大伙身上感受到了久违的集体温暖

我的室友:litten是位小清新的SNG前端工程师,毕业于华中科大,litten有想法也有激情,人很文静,很好相处,因为有着很多共同话题,每天晚上因为聊得太晚而导致早上起床很累。这样的日子,想必我今后会怀念这位短暂的室友吧。

我们“班”里有很多个性鲜明的人,有的很主动高调,属于喜欢当领导的人,有的是很有实力的低调派,在需要的时候总是会一语惊人,腾讯的确是聚集了很多优秀的人才,大家的知识储备以及视野和专业度都很高。特别是两位产品经理。独特的视角和条理分明的逻辑,以及优秀的口才,让我钦佩。唯一有些遗憾的是,搞技术的人多少感觉不出。或许没有深入了解吧。

看到的事

封闭培训讲了不少所谓的职场课程,尽管我认为有些厚黑,但在职场的确需要适应,调整心态去接受吧少年。《体验式培训课》,以及《互联网行业发展》让我获益匪浅。“目标,计划,确认,执行”(Target Plan Chect Action)的指导方针应该是我们需要具备的思维方式。合作,沟通,领导在团队极其重要,特别是团队的规模到了一定的规模。主动的人总是应势站出来承担了责任,积极的热情,敬业的态度使得他们成为了耀眼的角色。培训过程中还是克服不少羞涩,拿起了话筒,在队友需要我的时候挺身而出,但总归还是不能像某些同学一样很老练地去表达。只要你细心观察,便能吸收到周围同学的正能量,比如博士跟我讲问卷设计的时候,深切感受到真正做过研究的人,他们严谨的逻辑思维让你觉得是如此的靠谱。

震撼的产品体验报告会

我们做的是QQ空间的产品体验报告,最终只是得到了阳光普照奖。这次活动我细心观摩了真正的产品经理,或者有用心的同学是如何做这个Presentation的,其中一组同学的体验报告包涵了竟品分析,用户调研,原型设计,同时也用了很炫的展示手法,毫无悬念的拿走了第一名。用心做事的人是应该值得尊敬的。

很多时候我们会感觉做产品其实只是耍耍花样,看到很多天花乱缀的文章为了一个小按钮而大书特书,有点没必要。如今看来,如果把握每一个需求,隐形要求你有丰富的知识储备,大量的用于调研(Custom Engagement).如果你想你的方案令他人信服,你需要组织资源,撰写有料的报告,甚至做一个小Demo,如果可能的话做自些小测试。这些同学让我看到了很赞的能力。

说到这里,我也看到了我们班有位微信的产品经理,在我与之交谈的过程中,由心的欣赏。除去淡定的临场发言的实力,更具闪光点的是其洞察力与组织能力,在谈及百度发展历程,以及产品发展定位,都能信手拈来,有理有据,中肯的道出个中要害,想必其阅读量很大。反思自己,虽然很多资料我也阅读过,但没有去总结形成自己的思想,只是在他人提及之后才恍然大悟。虽然我不是做产品的,“我只是了解了解就够了?”抱有这样的想法是可以么?如果程序员只是停留在代码中自娱自乐,没有思考产品,用户的东西,我想多半是没有灵魂的吧。以后要真的去沉淀才是。

感觉腾讯能发展成今天这样子,的确是有其伟大之处。至少是招到了不少优秀的同学,曾经有人说腾讯是一个消耗人才的地方,不可否认大公司因流程体制都有通病,但我感受到,只有用心,通过不同的方式,可以开阔视野,如果你用心并去努力,还是能收获到。学习的涵义也应该慢慢变得多元化(沟通,情绪,产品),而不仅仅只是单一的技术。

结尾想引用这次封陪之旅一位老师的话 “坚持是最好的美德” :) 。问题很多,耐心勇敢去做你能尽到的改变吧,别泄气哈。

今日在整理曾经的学习笔记,看到了ZeroMQ,号称史上最快消息内核。曾经在一创业公司用其开发过一些后端服务。当时用Go语言实现 源代码,使用的便是gozmq库.这个消息通信框架库的文章有很多,比较著名的当属一淘的,(技术文章这样写,的确是让读者舒服 :))还有官方文档

优点:

  • 高度封装。
    它处于会话层之上,应用层之下,你不需要自己写一行的socket函数调用就能完成复杂的网络通信工作。

  • 点对点的消息传输上。
    传统的消息队列都需要一个消息服务器来存储转发消息。而ZeroMQ则把侧重点放在了点对点的消息传输上。ZeroMQ能缓存消息,但是是在发送端缓存。ZeroMQ里有水位设置的相关接口来控制缓存量。当然,ZeroMQ也支持传统的消息队列(通过zmq_device来实现)。这样使得客户端在重启的时候可以重新发送上次未发送成功的消息

  • 灵活的收发模式。
    REQ-REP 请求响应模式,PUSH-PULL: 推拉模式, PUB-SUB: 发布订阅模式 等。 其中任何一方都可以作为服务端

  • 以统一接口支持多种底层通信方式
    支持线程间通信,进程间通信,跨主机通信,假如你想把本机多进程的软件放到跨主机的环境里去执行,通常要将IPC接口用套接字重写一遍。非常麻烦。而有了ZeroMQ就方便多了,只要把通信协议从”ipc:///xxx”改为”tcp://...:****”就可以了,其他代码通通不需要改,如果这个是从配置文件里读的话,那么程序就完全不要动了,直接复制到其他机器上就可以了。

  • 异步高效。
    ZeroMQ为了高性能的消息发送而服务的,它发送消息是异步模式,通过单独出一个IO线程来实现,要把资源释放函数交给ZeroMQ让ZeroMQ发完消息自己释放,所以消息发送调用之后不要立刻释放相关资源。

近日折腾Gearman.有兴趣可以参考阅读这个,这个,还有这个

官方说法:

Gearman provides a generic application framework to farm out work to other machines or processes that are better suited to do the work. It allows you to do work in parallel, to load balance processing, and to call functions between languages. It can be used in a variety of applications, from high-availability web sites to the transport of database replication events. In other words, it is the nervous system for how distributed processing communicates.

Gearman是一个提供机器与进程之间相互协作的通信框架。可以让你并行处理作业以及负载均衡,提供不同的语言接口使得不同语言可以互相协作。用处很广泛,从web站点到数据库Replication事件。换句话说,是一个分布式的通讯框架

特点

  • 开源:
    多语言支持:Gearman支持的语言种类非常丰富。让我们能够用一种语言来编写Worker程序,但是用另外一种语言编写Client程序。

  • 灵活:不必拘泥于固定的形式。您可以采用你希望的任何形式,例如 Map/Reduce。

  • 快速:Gearman的协议非常简单,并且有一个用C语言实现的,经过优化的服务器,保证应用的负载在非常低的水平。

  • 可植入:因为Gearman非常小巧、灵活置入到现有的任何系统中。

  • 无单点故障:Gearman可扩展系统,可以避免系统的失败。

场景

听上去很诱惑的样子了。试想下:
我们的服务器有IO读写密集型,存储密集型,CPU使用不频繁,内存使用不频繁。如果我们能根据业务充分调动起各个服务器的特点。实现服务器的最大价值。Gearman可以登上舞台 :)

图解工作流

Gearman 有三个角色

  • Job Server:中央调度,消息中心,负载均衡
  • Client:发起Job,可由任何语言编写
  • Worker:负责执行Job,执行业务流

实操安装Gearman(以ubuntu为例子),默认的端口4730

1
sudo apt-get install gearman

安装python-gearman

1
sudo apt-get install python-gearman

用python编写
worker代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#worker.py
import os
import gearman
import math

class CustomGearmanWorker(gearman.GearmanWorker):
def on_job_execute(self, current_job):
return super(CustomGearmanWorker, self).on_job_execute(current_job)
def task_callback(gearman_worker, job):
print job.data
return job.data + " has received"

new_worker = CustomGearmanWorker(['127.0.0.1:4730'])
new_worker.register_task("ping", task_callback)
new_worker.work()

client代码

1
2
3
4
5
6
7
8
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
# # file: client.py
from gearman import GearmanClient
new_client = GearmanClient(['127.0.0.1:4730'])
current_request = new_client.submit_job('ping', 'foo')
new_result = current_request.result
print new_resul

结果

1
foo has received

用Go测试下

1
2
#gearman的Go库,内有example
go get https://github.com/mikespook/gearman-go

Happy Hacking!

0%