redis.js 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. /**
  2. * example:
  3. var redis=require('../libs/redis.js');
  4. var uid=yield redis.redisCo.get('siss:user:token_'+tokenKey);
  5. redis.redisClient.expire('siss:user:token_'+tokenKey,C.session.ttl);
  6. */
  7. 'use strict';
  8. var fs = require('fs');
  9. var path = require('path');
  10. var redis = require('redis');
  11. var C = require('../config');
  12. var ready = require('ready');
  13. var F = require('../common/function');
  14. //require('redis-lua2').attachLua(redis);
  15. //runOnce(redis);
  16. var redisClient;
  17. var dbcacheCli; // 独立mysqlcache用
  18. var javaRedisClient; // 连接java服务器使用的 redis接口
  19. if (C.redis.unix_socket){
  20. redisClient = redis.createClient(C.redis.unix_socket,C.redis.options);
  21. dbcacheCli = redis.createClient(C.redis.unix_socket,C.redis.options);
  22. javaRedisClient = redis.createClient(C.javaredis.unix_socket,C.javaredis.options);
  23. }else{
  24. redisClient = redis.createClient(C.redis.port,C.redis.host,C.redis.options);
  25. dbcacheCli = redis.createClient(C.redis.port,C.redis.host,C.redis.options);
  26. javaRedisClient = redis.createClient(C.javaredis.port,C.javaredis.host,C.javaredis.options);
  27. }
  28. redisClient.select(C.redis.db,function(){
  29. console.log('redis select db is '+C.redis.db);
  30. });
  31. dbcacheCli.select(C.redis.db_cache,function(){
  32. console.log('dbcache redis select db is '+ parseInt(C.redis.db_cache));
  33. });
  34. javaRedisClient.select(C.javaredis.db,function(){
  35. console.log('java redis select db is '+ parseInt(C.javaredis.db));
  36. });
  37. var wrapper = require('co-redis');
  38. var redisCo = wrapper(redisClient);
  39. var dbcacheCo = wrapper(dbcacheCli);// 独立mysqlcache用
  40. var javaRedisCo = wrapper(javaRedisClient);//连接java服务器使用的 redis
  41. exports.redisCo=redisCo;
  42. exports.redisClient=redisClient;
  43. exports.dbcacheCo=dbcacheCo;// 独立mysqlcache用
  44. exports.dbcacheCli=dbcacheCli;// 独立mysqlcache用
  45. exports.javaRedisCo=javaRedisCo;// 连接java服务器使用的 redis 协程
  46. exports.javaRedisClient=javaRedisClient;// 连接java服务器使用的 redis 异步
  47. var hook_fun = function*(cmd,cmd_name,args){
  48. let start_time = new Date().getTime();
  49. let res = yield cmd.apply(redisCo,args)
  50. let end_time = new Date().getTime();
  51. //F.addDebugLogs(["##redis",cmd_name,args,(end_time-start_time)]);
  52. if (end_time - start_time > 30) F.addOtherLogs("slow/slow",["##redis",cmd_name,args,"utime",(end_time-start_time)]);
  53. return res;
  54. };
  55. var reg_hook = function(cmd_name) {
  56. let s = `redisCo.imraw${cmd_name} = redisCo.${cmd_name};redisCo.${cmd_name}=function*(){return yield hook_fun(redisCo.imraw${cmd_name},cmd_name,arguments);}`;
  57. eval(s);
  58. };
  59. reg_hook("hget");
  60. reg_hook("INCR");
  61. reg_hook("HINCRBY");
  62. reg_hook("expire");
  63. reg_hook("hmset");
  64. reg_hook("hmget");
  65. reg_hook("hkeys");
  66. reg_hook("hgetall");
  67. reg_hook("hdel");
  68. reg_hook("set");
  69. reg_hook("get");
  70. reg_hook("del");
  71. reg_hook("ZADD");
  72. reg_hook("zrangebyscore");
  73. reg_hook("zcount");
  74. reg_hook("zrem");
  75. reg_hook("zscore");
  76. reg_hook("zcard");
  77. reg_hook("zrange");
  78. reg_hook("ttl");
  79. reg_hook("sadd");
  80. reg_hook("smembers");
  81. reg_hook("sdiff");
  82. reg_hook("sinter");
  83. reg_hook("exists");
  84. reg_hook("ZRANK");
  85. reg_hook("lpush");
  86. reg_hook("lrem");
  87. reg_hook("llen");
  88. reg_hook("hset");
  89. reg_hook("ZSCORE");
  90. reg_hook("ZREVRANGE");
  91. reg_hook("ZCOUNT");
  92. reg_hook("zremrangebyscore");
  93. /*************以下包装redis lua 扩展函数**************/
  94. var tpl_wrap = function(fn) {
  95. var str = fn.toString();
  96. var tpl = str.substring(str.indexOf("*") + 1);
  97. return tpl.substring(0,tpl.length-3);
  98. };
  99. exports.sha_map = {};
  100. var mysinter_lua = tpl_wrap(function(){/*
  101. local nousekey = KEYS[1]
  102. local tablename = ARGV[1]
  103. local key = ARGV[2] -- set key array json
  104. local key2 = ARGV[3] -- sort set json array json {key:x,min:x,max:x}
  105. local sort_field = ARGV[4]
  106. local isdesc = ARGV[5]
  107. local limit_first = ARGV[6]
  108. local limit_second = ARGV[7]
  109. local argv_null_count = 0
  110. if sort_field == nil or sort_field == "" then
  111. sort_field = "auto_id"
  112. argv_null_count = argv_null_count + 1
  113. end
  114. if isdesc == nil or isdesc == "" then
  115. isdesc = "asc"
  116. argv_null_count = argv_null_count + 1
  117. end
  118. if limit_first == nil or limit_first == "" then
  119. limit_first = 0
  120. argv_null_count = argv_null_count + 1
  121. end
  122. if limit_second == nil or limit_second == "" then
  123. limit_second = 99999999
  124. argv_null_count = argv_null_count + 1
  125. end
  126. local final_res = {}
  127. local has_set_res = false --是否已经设置第一个结果集
  128. local set_keys = cjson.decode(key);
  129. local set_keys_len = #set_keys
  130. if set_keys_len > 0 then
  131. has_set_res = true
  132. local set_res = redis.call('sinter', unpack(set_keys));
  133. for i, val in pairs(set_res) do
  134. final_res[val] = 1
  135. end
  136. end
  137. local sset_keys = cjson.decode(key2)
  138. for i, val in pairs(sset_keys) do
  139. local ssetKey = val["key"]
  140. local min = val["min"]
  141. local max = val["max"]
  142. local sset_res = redis.call('zrangebyscore', ssetKey, min, max)
  143. if has_set_res == false then --no set_keys
  144. has_set_res = true
  145. for i2, val2 in pairs(sset_res) do
  146. final_res[val2] = 1
  147. end
  148. else
  149. local merge_res = {}
  150. for i2, val2 in pairs(sset_res) do
  151. if final_res[val2] then
  152. merge_res[val2] = 1
  153. end
  154. end
  155. final_res = merge_res
  156. end
  157. end
  158. local final_ids = {}
  159. if argv_null_count == 4 then
  160. for i, val in pairs(final_res) do
  161. table.insert(final_ids,i)
  162. end
  163. else
  164. local k = {}
  165. for i, val in pairs(final_res) do
  166. local score = redis.call('ZSCORE','{rk}_zset_'..tablename..'_'..sort_field,i);
  167. if score == nil then score = 0 end
  168. table.insert(k,{i,score})
  169. end
  170. if isdesc == "asc" then
  171. table.sort(k,function (x,y) return x[2]<y[2] end)
  172. else
  173. table.sort(k,function (x,y) return x[2]>y[2] end)
  174. end
  175. local c = 0
  176. for i, val in pairs(k) do
  177. if i >= limit_first+1 then
  178. table.insert(final_ids,val[1])
  179. c = c + 1
  180. end
  181. if c >= limit_second then break end
  182. end
  183. end
  184. return cjson.encode(final_ids)
  185. */});
  186. redisClient.script('load', mysinter_lua, function(err,sha){
  187. if (err) {
  188. console.log("load mysinter lua err:",err);
  189. } else {
  190. exports.sha_map.mysinter_sha = sha;
  191. }
  192. console.log("mysinter lua sha:",sha);
  193. });
  194. //zrangebyscorestore zrangebyscore并存到另外的set 返回set key
  195. var zrangebyscorestore_lua = tpl_wrap(function(){/*
  196. local key = KEYS[1]
  197. local key2 = KEYS[2]
  198. local min = ARGV[1]
  199. local max = ARGV[2]
  200. local res = redis.call('zrangebyscore', KEYS[1], min, max);
  201. for i, val in pairs(res) do
  202. redis.call('sadd', KEYS[2], val);
  203. end
  204. redis.call('expire', KEYS[2], 30);
  205. return key2
  206. */});
  207. redisClient.script('load', zrangebyscorestore_lua, function(err,sha){
  208. if (err) {
  209. console.log("load zrangebyscorestore lua err:",err);
  210. } else {
  211. exports.sha_map.zrangebyscorestore_sha = sha;
  212. }
  213. console.log("zrangebyscorestore lua sha:",sha);
  214. });
  215. // 封装setnx+expire函数
  216. var setnxex_lua = tpl_wrap(function(){/*
  217. local key = KEYS[1]
  218. local content = ARGV[1]
  219. local ttl = ARGV[2]
  220. local lockSet = redis.call('setnx', KEYS[1], content)
  221. if lockSet == 1 then
  222. redis.call('expire', KEYS[1], ttl)
  223. end
  224. return lockSet
  225. */});
  226. redisClient.script('load', setnxex_lua, function(err,sha) {
  227. if (err) {
  228. console.log("load setnxex lua err:",err);
  229. } else {
  230. exports.sha_map.setnxex_sha = sha;
  231. }
  232. console.log("setnxex lua sha:",sha);
  233. });
  234. // 封装lock函数
  235. var lock_lua = tpl_wrap(function(){/*
  236. local key = KEYS[1]
  237. local pid = KEYS[2]
  238. local json_str = ARGV[1]
  239. local ttl = ARGV[2]
  240. if key == nil or json_str == nil or ttl == nil then
  241. return 0
  242. end
  243. local ret,errmsg = pcall(cjson.decode,json_str)
  244. if ret == false then
  245. return 0
  246. end
  247. local js = cjson.decode(json_str)
  248. if js == nil or js["time"] == nil or js["pid"] == nil then
  249. return 0
  250. end
  251. local lockSet = redis.call('setnx', KEYS[1], json_str)
  252. if lockSet == 1 then
  253. redis.call('expire', KEYS[1], ttl)
  254. redis.call('zadd', KEYS[2], js["time"], key)
  255. end
  256. return lockSet
  257. */});
  258. redisClient.script('load', lock_lua, function(err,sha){
  259. if (err) {
  260. console.log("load lock lua err:",err);
  261. } else {
  262. exports.sha_map.lock_sha = sha;
  263. }
  264. console.log("lock lua sha:",sha);
  265. });
  266. // 封装unlock函数
  267. var unlock_lua = tpl_wrap(function(){/*
  268. local key = KEYS[1]
  269. local pid = KEYS[2]
  270. local json_str = ARGV[1]
  271. if key == nil or json_str == nil then
  272. return 0
  273. end
  274. local ret,errmsg = pcall(cjson.decode,json_str)
  275. if ret == false then
  276. return 0
  277. end
  278. local js = cjson.decode(json_str)
  279. if js == nil or js["time"] == nil or js["pid"] == nil then
  280. return 0
  281. end
  282. local redis_json_str = redis.call("get", KEYS[1])
  283. if redis_json_str == nil then
  284. redis.call("zrem", KEYS[2], key)
  285. return 0
  286. end
  287. local ret,errmsg = pcall(cjson.decode,redis_json_str)
  288. if ret == false then
  289. return 0
  290. end
  291. local redis_js = cjson.decode(redis_json_str)
  292. if js["time"] == redis_js["time"] and js["pid"] == redis_js["pid"] then
  293. redis.call("zrem", KEYS[2], key)
  294. return redis.call("del", KEYS[1])
  295. elseif redis_js["time"] == nil or redis_js["pid"] == nil then
  296. redis.call("zrem", KEYS[2], key)
  297. return redis.call("del", KEYS[1])
  298. elseif js["pid"] == redis_js["pid"] and js["svrRestartTime"] ~= nil and tonumber(redis_js["time"]) < tonumber(js["svrRestartTime"]) then
  299. -- same svr and set time before svr start, must del
  300. redis.call("zrem", KEYS[2], key)
  301. return redis.call("del", KEYS[1])
  302. else
  303. return 0
  304. end
  305. */});
  306. var ready = false;
  307. redisClient.script('load', unlock_lua, function(err,sha){
  308. if (err) {
  309. console.log("load unlock lua err:",err);
  310. } else {
  311. exports.sha_map.unlock_sha = sha;
  312. }
  313. console.log("unlock lua sha:",sha);
  314. ready = true;
  315. });
  316. var deasync = require('deasync');
  317. while (true) {
  318. if (ready) break;
  319. deasync.sleep(200);
  320. }