100行代码左右实现一个高性能的Memcached Server原型
发布于 7 年前 作者 fxsjy 6259 次浏览 最后一次编辑是 3 年前

启动方式: node --nouse-idle-notification --expose-gc --max-old-space-size=8192 memcached.js 性能:用mc_benchmark测试可以达到4万qps.

memcached.js的源码:

var net = require('net');
var store = {}

function handle_header(header,crlf_len){
	var tup = header.split(" ")
	var expect_body_len = 0
	switch(tup[0]){
		case 'get':
		case 'delete':
			expect_body_len = 0
			break
		case 'set':
			expect_body_len = parseInt(tup[4]) + crlf_len
			break
		case 'gc':
			expect_body_len = 0
			gc()
			break;
	}
	return expect_body_len
}

function handle_body(socket,header,body,call_back){
	var response=""
	var tup = header.split(" ")
	switch(tup[0]){
		case 'get':
			var key = tup[1]
			var obj = store[key]
			if(obj){
				response = "VALUE "+ obj.key+" " + obj.flag+" "  + obj.data.length + "\r\n"
				response += obj.data + "\r\n"
				response += "END\r\n"
			}
			else
				response = "NOT_FOUND\r\n"
			break;
		case 'delete':
			var key = tup[1]
			delete store[key]
			response = "DELETED\r\n"
			break;
		case 'set':
			var obj = {key: tup[1], flag: tup[2], data: body}
			store[obj.key] = obj
			response = "STORED\r\n"
			break;
		case 'gc':
			response = "OK\r\n"
			break;
		default:
			response = "ERROR\r\n"
			break;
	}
	socket.write(response,"binary",call_back)
}

var server = net.createServer(function (socket) {
	console.log("client: ",socket.remoteAddress)
    var user_state = 'reading_header'
    var buf = ""
    var header =""
    var body = ""
    var expect_body_len = 0 
    var CRLF_LEN = 2
    socket.setEncoding("binary")
 	socket.on('data',function(data){
 		buf += data
 		socket.emit('user_event')
 	})
 	socket.on('user_event',function(){
 		switch(user_state){
 			case "reading_header":
 				var pos =-1
		 		if((pos=buf.indexOf('\r\n'))!=-1){
		 			header = buf.slice(0,pos)
		 			buf = buf.slice(pos+2)
		 			CRLF_LEN =2
		 		}
		 		else if((pos=buf.indexOf('\n'))!=-1){
		 			header = buf.slice(0,pos)
		 			buf = buf.slice(pos+1)
		 			CRLF_LEN =1
		 		}
		 		if(pos!=-1){
		 			user_state = 'reading_body'
		 			expect_body_len = handle_header(header,CRLF_LEN)
			 		socket.emit("user_event")
			 	}
 				break
 			case "reading_body":
 				if(expect_body_len <= buf.length){
 					body = buf.slice(0,expect_body_len-CRLF_LEN)
 					buf = buf.slice(expect_body_len)
 					user_state = 'reading_header'
 					handle_body(socket,header,body,
 						function(){		
 							if(buf.length>0)
 								socket.emit("user_event")
 						}
 					)
 					
 				}
 				break
 		}
 	})
});
var port = 11211
console.log("listening at "+ port)
server.listen(port, '0.0.0.0')
setInterval(function(){gc(); console.log(process.memoryUsage())},5000)
18 回复

收藏,做原型用。

哈啊,我也在写,参考下

目前还是只能算是memory store,还没有实现LRU Cache。

lru cache,node实现的有好多

@sumory 谢谢,我在github上搜索了一下,有好几个。 有推荐的么?

@fxsjy 都没试过,看看这个https://github.com/isaacs/node-lru-cache,isaacs的,还在更新。

不懂 memcache, 求指导… Google 说是缓存, 那代码是按什么原理来写呢?

@sumory 我刚实验了一下这个LRU模块: https://github.com/chriso/lru ,测试了一下发现性能没有明显下降,代码也挺简单的。

代码更新了。 加入了LRU算法,可以设置允许的最大内存占用。现在可以叫做cache了。

https://gist.github.com/3291755

https://github.com/3rd-Eden/node-memcached

Consistent hashing能够提高命中率。另外,使用楼主的代码怎么有,listen EADDRINUSE的报错呢。

因为你开着Memcached吧,端口11211被占用了。 3rd-Eden/node-memcached 这是Memcached的客户端,我贴的是server .

做个Redis吧~~~~

哈,只是一个实验。 redis,memcached都是以内存管理为卖点的,用node.js去实现,很难超越吧。 我倒是觉得用node.js实现一些智能的redis proxy, memcached proxy是不是更有用?

回到顶部