JSON键值对集合序

JSON作为数据交换协议应用已越来越广,其简易性和编程友好性使得程序员们几乎无不适之感,也因此全面盖过xml成为前后端数据交换的通用格式之一。我们的搜索API也将其作为基本数据交换格式提供接口服务。但前几天发生个有意思的事情,谨记之。

前几天和前端同事开发H5项目,前端同事提出个听上去挺合理的建议,
其使用的接口数据需要后端把json协议中的某个键值对集合按序组装,
这样前端可以按序取出,不需要额外判断。形如:
{
   1th:'abc',
   2nd:'cbd',
   3rd:'efg'
}

作为非nb程序员,我的第一反应是这样是不OK的,因为集合本身是无序的,但该同事用了js做了个简单的示范,证实js封装/解析json的集合节点时确实是按序封装/解析的。呃呃呃,我当时就给JS跪了,太人性了不是,为了更好地说服这位小哥,打算做个实验并辅以协议本身说明以证实我的观点。

Read More

不那么坏的宏

做学生时, 写个”Hello World”, 若是Linux, 用个g++ main.cpp就可以了. 但对多些的源码工程, 一行命令就难以搞定了. 这个时候, 大家熟悉的make命令就派上用场. 这个书上很少教说, 我在网上边搜边学后折腾了个简单的makefile, 应付简单的工程…

1
ifeq ($(dd),debug) 
export dd := debug
BIN_DIR=./debug
CPPLAGS=-g -pg -fPIC -Wall -D_FILE_OFFSET_BITS=64
BUILDS=$(DIRS) lib test
else  #release
export dd := release
BIN_DIR=./release
CPPLAGS=-O3 -fPIC -D_FILE_OFFSET_BITS=64
BUILDS=$(DIRS) lib
endif

TEST=
DIRS=$(BIN_DIR)

BASE_DIR=.
LIB_PATH=$(BASE_DIR)/lib
SHARE_PATH=$(LIB_PATH)
STATIC_PATH=$(LIB_PATH)

SHARE_LIBS=boost_thread
STATIC_LIBS=libboost_system.a libevent.a

INC_PATH=./
SRC_DIRS=./ ./bits ./algo ./ext
SRCS=$(foreach SRC_DIRS,$(SRC_DIRS),$(wildcard $(SRC_DIRS)/*.cxx))
OBJS=$(patsubst %.cxx,%.o,$(SRCS))
INC_SHARE=$(addprefix -L, SHARE_PATH/) $(addprefix -l, $(SHARE_LIBS)) 
INC_STATIC=$(addprefix $(STATIC_PATH)/, $(STATIC_LIBS))

.SECONDARY :%.o %(OBJS)

%.o:%.cxx
	@echo "Compile $@ ($<)."
	@g++ $(CPPLAGS) -I $(INC_PATH) -c $< -o $@ 

all: $(BUILDS)

$(DIRS):
	mkdir -p $@

lib: $(OBJS)
	@echo 'build static lib'
	@ar -rc libbang.a $(OBJS)
	mv $(OBJS) libbang.a $(BIN_DIR)

test:
	@echo 'build unit test'
	g++ -DUNIT_TEST -DTEST_$(TEST) $(CPPLAGS) -o $(TEST).exe $(SRCS) -I $(INC_PATH) $(INC_SHARE) $(INC_STATIC) -lcurl

install:
	@echo 'install lib'
	cp $(BIN_DIR)/libbang.a $(LIB_PATH)

clean:
	@echo 'clean up the generated files'
	rm ./debug/ -rf;
	rm ./release/ -rf;

.PHONY: all lib test install clean $(DIRS)

用这个Makefile文件, 即可编译链接了. make dd=debug进行debug方式的编译. 而make dd=release则进行release编译, 以适合生产环境的需要和性能优化. 那这种区别编译是怎么做到的呢? 我们如何在实际使用时干预已经写好的代码行为?答案就是本篇的主题, 宏.

Read More

域名和DNS

怎么找到一个网站?先找到他的IP:)

我们在浏览网站时,计算机和Internet是怎么知道我们想要找的是哪个网站呢?怎么知道我要找的是www.badibu.com而不是www.baidu.com呢?计算机又不识字…

计算机和网络虽然不识字,但是知道IP的,就是123.234.12.89这种东西。如果知道IP,通过复杂的IP协议,计算机(客户端)就可以把“我们需要浏览xxx网站的yyy网页”这种信息正确投递给响应的计算机(服务端),并返回响应结果。而在此之前,需要做的事情就是把www.badibu.com翻译成对应的IP地址11.22.33.44。这个过程就是DNS解析。

Read More

从SYN-Flood攻击到TCP/IP协议

这篇博客缘起一次服务故障,在写下事故报告的同时总结分析了这次故障原因及教训。

我们的新搜索后台2012年8月份上线,10月份偶发不稳定,具体症状是lvs探测发现某个后台频繁上下线,吞吐很低,基本不能正常 返回结果,11月份该情况加剧。当在线调试跟踪时,发现后台基本无动作,CPU利用率很低,负载也不高。

查看系统的网络连接状态,如下左(右是正常连接):
connect_error.png connect_normal.png

从表象上看,我们开始怀疑网络通信环节出现了问题,很多链接不能被正常接收处理,而这种情况类似常见的SYN-Flood攻击的特征,在通信环节存在握手等待和无应答的情况。我们的第一反应是有恶意攻击发生,但和运维同事确认后排除了这种可能。那么具体是怎么回事呢?

Read More

编写线程安全的代码

编写线程安全的代码
新近参与的一个搜索项目,上线前的压力测试时,会导致后台程序不稳定,偶尔程序会崩溃掉,在debug模式下却很难重现。现场一片狼藉,除了STL和pthread那些残迹,基本上很难得到有用信息。在经历一周多的排查后,终于发现了bug的藏身之处。下面代码即是浪费我们大量时力的bug源头,拿来做楔子吧:

++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
template<class T> 
inline void SplitToVecEx(char* pSrc, vector<T> &vec, const char* pchSplit) {
char* pchCurWord=strtok(pSrc,pchSplit);
while(pchCurWord)
{
#ifdef _WIN32
vec.push_back((T)_atoi64(pchCurWord));
#else
vec.push_back((T)atoll(pchCurWord));
#endif
pchCurWord = strtok(NULL, pchSplit);
}

}

这段代码通常来看不会有什么问题,而且能很好地完成任务。但当它放在多线程环境中时,大量请求会并发地调用该函数进行字符串的切分。这个时候,这个函数的问题就大条了,在高并发时会破坏内存,让程序内部直接爆掉。而原因是因疏忽调用了strtok——线程不安全的系统调用,使得该函数是线程不安全的。线程不安全的代码,会带来灾难,这也是我写这篇博客的原因。

Read More

编写干净的代码-Python篇

这篇blog整理下写python程序时应注意的问题。在写程序时,我们的代码的整洁和规范会直接影响到该代码的表达能力,从机器的指令清晰高效到人的理解消化。没有个性的代码没有活力,但没有规范的代码没有生命力。Python作为已经很通用的一门高级语言,这方面的语言层次的考虑已经有不少,但同时还是需要人们在使用时自我规范一下,以让代码更加地整洁。

参考一些比较权威的文档,本文从代码的通用规范,Python的语言准则,Python的风格进行评述,学习并简单分析摘要一下,聊以自用。

通用规范

- [MUST] 最小化代码的作用范围
- [MUST] 语义的明晰大于任何技巧和优化
- [MUST] 一致性大于个性
- [MUST] 尽可能地将代码纳入控制
- [SHOULD] 尊重传统和习惯
- [SHOULD] 拒绝语法糖

Read More