>백엔드 개발 >Golang >Golang의 Memcache를 간단하게 구현하는 방법

Golang의 Memcache를 간단하게 구현하는 방법

藏色散人
藏色散人앞으로
2021-02-10 09:31:472820검색

다음 golang 튜토리얼 칼럼에서는 Golang의 간단한 Memcache 구현 방법을 소개하겠습니다. 필요한 친구들에게 도움이 되길 바랍니다!

Golang의 Memcache를 간단하게 구현하는 방법

지난 이틀 동안 프로젝트 도중 전역 변수에 액세스하는 문제 시나리오에 직면했습니다. ID에 해당하는 토큰 값을 가져오는 메서드를 작성합니다. 토큰을 캐시해야 합니다(전역 변수 메모리 캐시). ) 획득한 경우 시간이 짧거나 토큰이 만료된 경우 다른 쪽 끝으로 http 요청을 보내 이를 가져오고 캐시한 다음 반환합니다.

code.go:

package person

import (
	"time"
)

var gAccId2Token map[int]interface{} = make(map[int]interface{})

func GetTokenByAccountId(accountId uint, acl string) (map[string]interface{}, error) {
	//get token from cache
	if token, ok := gAccId2Token[accountId]; ok {
		if token != nil {
			now := time.Now().Unix()
			if int(now) < int(token.(map[string]interface{})["expireDate"].(float64)) {
				return token.(map[string]interface{}), nil
			}
		}
	}

	token, err := getTokenByHttpUrl(apiUrl)
	if err != nil {
		return map[string]interface{}{}, err
	}

	gAccId2Token[accountId] = token

	return token.(map[string]interface{}), nil
}

그러면 이런 질문이 옵니다.

1. gAccId2Token 변수는 전역 변수이므로 읽기와 쓰기가 동시에 발생할 수 있으며, 읽기와 쓰기에 불일치가 있을 수 있습니다.

2. 이 예에서는 id=2인 토큰을 얻기 위해 캐시된 토큰이 만료된 후 이를 얻기 위해 http 요청을 보낸 다음 캐시 쓰기 시간을 가정하여 캐시를 작성합니다. 이 기간 동안 id=2인 토큰을 얻으려는 요청이 많이 발생하게 됩니다. 토큰이 만료되었기 때문에 요청이 많이 발생하는 문제가 발생합니다. http 서버는 캐시를 얻는 목적을 달성하지 못할 뿐만 아니라 동시에 백엔드에 대한 부담을 증가시킵니다. 동시에 여러 쓰기 캐시 작업이 있으며 Golang의 맵은 원자적이지 않아야 합니다. 많은 양의 메모리로 인해 충돌 문제가 발생할 수도 있습니다.

따라서 읽기 및 쓰기 작업을 잠가야 합니다.

memcache.go:

package person

import (
	"sync"
	"time"
)

type memoryCache struct {
	lock  *sync.RWMutex
	items map[interface{}]interface{}
}

func (mc *memoryCache) set(key interface{}, value interface{}) error {
	mc.lock.Lock()
	defer mc.lock.Unlock()
	mc.items[key] = value
	return nil
}

func (mc *memoryCache) get(key interface{}) interface{} {
	mc.lock.RLock()
	defer mc.lock.RUnlock()

	if val, ok := mc.items[key]; ok {
		return val
	}
	return nil
}

var gAccId2Token *memoryCache = &memoryCache{
		lock:  new(sync.RWMutex),
		items: make(map[interface{}]interface{}),
	}

func GetTokenByAccountId(accountId uint, acl string) (map[string]interface{}, error) {
	//get token from cache
	token := gAccId2Token.get(accountId)
	if token != nil {
		now := time.Now().Unix()
		if int(now) < int(token.(map[string]interface{})["expireDate"].(float64)) {
			return token.(map[string]interface{}), nil
		}
	}

	token, err := getTokenByHttpUrl(apiUrl)
	if err != nil {
		return map[string]interface{}{}, err
	}

	gAccId2Token.set(accountId, token)

	return token.(map[string]interface{}), nil
}

몇 가지 참고 사항:

1 Lock()이 실행되면 다른 잠금이 설정됩니다. 잠금은 잠금이 해제될 때까지 작동하지 않습니다. 즉, 쓰기 작업의 원자성이 보장됩니다.

2. 읽기 작업에 대해 읽기 잠금이 설정된 경우 여러 스레드가 해당 영역에 대한 잠금을 Rlock()하여 모든 읽기 잠금이 RUnlock()이 될 때까지 쓰기 잠금을 적용할 수 없습니다.

3. 맵의 키 및 값 유형을 인터페이스{} 유형으로 정의합니다. 인터페이스{}는 Java의 Object와 마찬가지로 모든 유형을 수신할 수 있습니다.

4.Interface{} 유형 변환 방법인 value.(type)은 값을 유형 유형(예: value.(int), value.(map[string]interface{}) 등)으로 변환하는 것입니다.

위 내용은 Golang의 Memcache를 간단하게 구현하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 csdn.net에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제