오늘은 Node-cache 에 대해 알아보도록 하겠습니다.
목표는 데이터를 캐싱해 API의 Response 속도를 개선하는 것 입니다.
node-cache
Simple and fast NodeJS internal caching. Node internal in memory cache like memcached.. Latest version: 5.1.2, last published: 4 years ago. Start using node-cache in your project by running `npm i node-cache`. There are 2522 other projects in the npm regis
www.npmjs.com
먼저 Node-Cache 에 대해 알아보겠습니다.
공식 문서에서 설명하는 Node-cache는 위 내용과 같습니다. 내용을 번역해보면
간단하고 빠른 Node.js 내부 캐싱. memcached와 비슷하게 작동하는 set, get 및 delete 메서드를 갖춘 간단한 캐싱 모듈입니다. 키에는 만료 시간 (ttl)을 설정할 수 있으며, 만료되면 캐시에서 삭제됩니다. 모든 키는 단일 객체에 저장되므로 실제 제한은 약 1백만 개의 키 정도입니다.
간단하고 빠른 Node.js 내부 캐싱 모듈 정도로 이해할 수 있습니다.
어떻게 데이터를 캐싱하는지 코드를 좀 더 자세히 살펴보았습니다.
coffescript 로 개발된 오픈소스로 내용은 아래와 같습니다.
node-cache/_src/lib/node_cache.coffee at master · node-cache/node-cache (github.com)
일부를 살펴보면
//node_cache.coffee
clone = require( "clone" )
EventEmitter = require('events').EventEmitter
# generate superclass
module.exports = class NodeCache extends EventEmitter
constructor: ( @options = {} )->
super()
@_initErrors()
# container for cached data
@data = {}
# module options
@options = Object.assign(
# convert all elements to string
forceString: false
# used standard size for calculating value size
objectValueSize: 80
promiseValueSize: 80
arrayValueSize: 40
# standard time to live in seconds. 0 = infinity;
stdTTL: 0
# time in seconds to check all data and delete expired keys
checkperiod: 600
# en/disable cloning of variables. If `true` you'll get a copy of the cached variable. If `false` you'll save and get just the reference
useClones: true
# whether values should be deleted automatically at expiration
deleteOnExpire: true
# enable legacy callbacks
enableLegacyCallbacks: false
# max amount of keys that are being stored
maxKeys: -1
, @options )
# generate functions with callbacks (legacy)
if (@options.enableLegacyCallbacks)
console.warn("WARNING! node-cache legacy callback support will drop in v6.x")
[
"get",
"mget",
"set",
"del",
"ttl",
"getTtl",
"keys",
"has"
].forEach((methodKey) =>
# reference real function
oldMethod = @[methodKey]
@[methodKey] = (args..., cb) ->
# return a callback if cb is defined and a function
if (typeof cb is "function")
try
res = oldMethod(args...)
cb(null, res)
catch err
cb(err)
else
return oldMethod(args..., cb)
return
return
)
# statistics container
@stats =
hits: 0
misses: 0
keys: 0
ksize: 0
vsize: 0
# pre allocate valid keytypes array
@validKeyTypes = ["string", "number"]
# initalize checking period
@_checkData()
return
# ## get
#
# get a cached key and change the stats
#
# **Parameters:**
#
# * `key` ( String | Number ): cache key
#
# **Example:**
#
# myCache.get "myKey", ( err, val )
#
get: ( key )=>
# handle invalid key types
if (err = @_isInvalidKey( key ))?
throw err
# get data and increment stats
if @data[ key ]? and @_check( key, @data[ key ] )
@stats.hits++
_ret = @_unwrap( @data[ key ] )
# return data
return _ret
else
# if not found return undefined
@stats.misses++
return undefined
좀 더 보기 편하게 자바스크립트 코드로 변경해보면
const EventEmitter = require('events').EventEmitter;
const clone = require("clone");
module.exports = class NodeCache extends EventEmitter {
constructor(options = {}) {
super();
this._initErrors();
// container for cached data
this.data = {};
// module options
this.options = Object.assign({
// convert all elements to string
forceString: false,
// used standard size for calculating value size
objectValueSize: 80,
promiseValueSize: 80,
arrayValueSize: 40,
// standard time to live in seconds. 0 = infinity;
stdTTL: 0,
// time in seconds to check all data and delete expired keys
checkperiod: 600,
// en/disable cloning of variables. If `true` you'll get a copy of the cached variable. If `false` you'll save and get just the reference
useClones: true,
// whether values should be deleted automatically at expiration
deleteOnExpire: true,
// enable legacy callbacks
enableLegacyCallbacks: false,
// max amount of keys that are being stored
maxKeys: -1
}, options);
// generate functions with callbacks (legacy)
if (this.options.enableLegacyCallbacks) {
console.warn("WARNING! node-cache legacy callback support will drop in v6.x");
["get", "mget", "set", "del", "ttl", "getTtl", "keys", "has"].forEach(methodKey => {
// reference real function
const oldMethod = this[methodKey];
this[methodKey] = (...args) => {
// return a callback if cb is defined and a function
const cb = args[args.length - 1];
if (typeof cb === "function") {
try {
const res = oldMethod(...args);
cb(null, res);
} catch (err) {
cb(err);
}
} else {
return oldMethod(...args);
}
};
});
}
// statistics container
this.stats = {
hits: 0,
misses: 0,
keys: 0,
ksize: 0,
vsize: 0
};
// pre allocate valid keytypes array
this.validKeyTypes = ["string", "number"];
// initalize checking period
this._checkData();
}
// get
// get a cached key and change the stats
//
// Parameters:
//
// * `key` ( String | Number ): cache key
//
// Example:
//
// myCache.get("myKey", (err, val) => { ... });
//
get(key) {
// handle invalid key types
const err = this._isInvalidKey(key);
if (err) {
throw err;
}
// get data and increment stats
if (this.data[key] && this._check(key, this.data[key])) {
this.stats.hits++;
const _ret = this._unwrap(this.data[key]);
// return data
return _ret;
} else {
// if not found return undefined
this.stats.misses++;
return undefined;
}
}
}
// ChatGPT가 변경해주었습니다. ChatGPT 짱짱
코드를 살펴보면
- NodeCache Class 는 Node.js EventEmitter 을 상속 받는 것을 알 수 있습니다.
- get 메소드의 경우 key 를 받아 this._unwrap 메서드로 data 에서 키를 가져옵니다.
- data 는 {} 로 선언되어 있고, _unwrap의 로직은 github에서 확인
- Emit을 통해 이벤트 발생
그렇다면 Events Module에 대해서도 알아야 할 것 같습니다.
Events Module
은 이벤트 기반 프로그래밍을 지원하는 핵심 모듈 중 하나입니다.
Events 모듈은 EvnetsEmitter 클래스를 통해 이벤트 처리를 구현합니다.
// Events 모듈을 가져옵니다
const EventEmitter = require('events');
// 이벤트 발생자 객체를 생성
const myEmitter = new EventEmitter();
// 이벤트 리스너를 등록
myEmitter.on('event', () => {
console.log('이벤트가 발생했습니다!');
});
// 이벤트를 발생
myEmitter.emit('event');
//이벤트가 발생하여 등록되어 있던 콜백함수가 실행
//이벤트가 발생했습니다!
Events 모듈을 사용하면 비동기적으로 발생하는 이벤트를 강력하게 관리하고 처리할 수 있습니다.
Node-Cache를 활용해 데이터 캐싱처리를 진행해 보려고 했지만 소스코드를 살펴보다가 글이 길어졌네요. 다음 글에서 Node-Cache를 활용해 데이터 캐싱을 해보겠습니다. :)
'Node.js' 카테고리의 다른 글
[Error] Cannot install on Intel processor in ARM default prefix (/opt/homebrew)! (0) | 2024.08.26 |
---|---|
[NestJS] NestJS 공통 라이브러리 분리 및 테스트 코드 작성 환경 개선 (0) | 2024.05.23 |
NestJS Boilerplate (0) | 2024.03.26 |