Maison >développement back-end >Golang >Comment implémenter simplement le memcache de Golang

Comment implémenter simplement le memcache de Golang

藏色散人
藏色散人avant
2021-02-10 09:31:472825parcourir

La colonne tutorielle suivante de golang vous présentera la méthode simple d'implémentation de Memcache dans Golang. J'espère qu'elle sera utile aux amis qui en ont besoin !

Comment implémenter simplement le memcache de Golang

Au cours des deux derniers jours, j'ai rencontré un scénario problématique d'accès aux variables globales pendant le projet : écrire une méthode pour obtenir la valeur du jeton correspondant à l'identifiant, le jeton doit être mis en cache (cache de mémoire variable global), s'il ne peut pas être obtenu ou si le temps du jeton expire, envoyez une requête http à l'autre extrémité pour l'obtenir, mettez-le en cache, puis revenez, alors le code est comme suit :

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
}

Alors voici le problème :

1 Puisque la variable gAccId2Token est une variable globale, simultanée. la lecture et l’écriture peuvent survenir.

2. Dans cet exemple, si le jeton avec id=2 est obtenu et que le jeton mis en cache a expiré, une requête http sera envoyée pour l'obtenir, puis le cache sera écrit en supposant que le. le temps d'écriture du cache est très long, pendant cette période, il arrive qu'il y ait un grand nombre de requêtes pour obtenir le token avec id=2. Les tokens ayant expiré, il y aura un problème de grand nombre de requêtes vers le serveur http. Non seulement cela n'atteint pas l'objectif d'obtenir le cache, mais cela augmente également la taille du cache. Il y a une pression sur la fin et il y a plusieurs opérations d'écriture du cache en même temps. donc écrire une grande quantité de mémoire peut également provoquer des problèmes de crash.

Par conséquent, nous devons verrouiller les opérations de lecture et d'écriture :

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
}

Quelques notes :

1. Une fois qu'un verrou global est verrouillé, les autres verrous ne peuvent pas être verrouillés jusqu'à ce que Unlock() soit libéré, ce qui signifie que l'atomicité de l'opération d'écriture est garantie.

2. Si un verrou de lecture est défini pour l'opération de lecture, plusieurs threads peuvent Rlock() verrouiller une zone pour garantir que la zone est lisible jusqu'à ce que tous les verrous de lecture soient RUnlock().

3. Définissez les types de clé et de valeur de la carte comme type d'interface{} Interface{} peut recevoir n'importe quel type, tout comme Object en Java.

4.Interface{} méthode de conversion de type, value.(type), c'est-à-dire convertir la valeur en type type, par exemple : value.(int), value.(map[string]interface{}) , etc. .

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer