zoukankan      html  css  js  c++  java
  • golang 识别redis key在哪个codis的slot上

    golang从ES获取数据并计算存在那个codis的slot

    环境是已经将redis的bigkey存入ES

    1. 获取字符串存在那个slot

    1.1 官方命令

    SLOTSHASHKEY key1 [key2 …]
    命令说明:计算并返回给定 key 的 slot 序号
    命令参数:输入为 1 个或多个 key
    返回结果: 操作返回 array
      response := []int{slot1, slot2...}
      其中:
          INT slot : 表示对应 key 的 slot 序号,即 hash32(key) % NUM_OF_SLOTS
    例如:
    
      localhost:6379> slotshashkey a b c   # 计算 <a,b,c> 的 slot 序号
          1) (integer) 579
          2) (integer) 1017
          3) (integer) 879
    

    1.2 使用golang获取

    Codis 采用 Pre-sharding 的技术来实现数据的分片, 默认分成 1024 个 slots (0-1023), 对于每个key来说, 通过以下公式确定所属的 Slot Id : SlotId = crc32(key) % 1024。
    参考代码

    package slotcrc32
    
    import "hash/crc32"
    
    // GetIntvalKey 返回crc32算法的返回结果
    func GetIntvalKey(strKey string) uint32 {
    	table := crc32.MakeTable(crc32.IEEE)
    	ret := crc32.Checksum([]byte(strKey), table)
    	return ret % 1024
    }
    

    golang从elasticsearch获取数据,并调用函数计算keyName的slot位置

    package esgetkey
    
    import (
    	"context"
    	"encoding/json"
    	"fmt"
    	"local/dev/esgetkey/slotcrc32"
    	"log"
    	"os"
    	"sort"
    
    	"github.com/olivere/elastic/v7"
    )
    
    type Employee struct {
    	CodisName string `json:"codisName"`
    	Size      int64  `json:"size"`
    	KeyType   string `json:"keyType"`
    	RedisHost string `json:"redisHost"`
    	Database  int64  `json:"database"`
    	Ex        string `json:"过期时间"`
    	KeyName   string `json:"keyName"`
    }
    type MapSorter []slotInfo
    type slotInfo struct {
    	totalSize  int64
    	totalCount int64
    	slotNum    uint32
    }
    
    var (
    	slotInfoMap map[uint32]slotInfo = make(map[uint32]slotInfo, 1024)
    )
    
    // GetEsKey 从es中获取codis的key
    func GetEsKey(host string) {
    	var err error
    	var res *elastic.SearchResult
    	errorlog := log.New(os.Stdout, "APP", log.LstdFlags)
    
    	client, err := elastic.NewClient(elastic.SetErrorLog(errorlog), elastic.SetURL(host))
    	if err != nil {
    		panic(err)
    	}
    	info, code, err := client.Ping(host).Do(context.Background())
    	if err != nil {
    		panic(err)
    	}
    	fmt.Printf("Elasticsearch returned with code %d and version %s
    ", code, info.Version.Number)
    
    	esversion, err := client.ElasticsearchVersion(host)
    	if err != nil {
    		panic(err)
    	}
    	fmt.Printf("Elasticsearch version %s
    ", esversion)
    
    	// 查询
    	q := elastic.NewTermQuery("codisName", "THEIA_PUSH")
    	res, err = client.Search("codis-bigkey-2021-04-02*").Query(q).TrackTotalHits(true).Do(context.Background())
    	if err != nil {
    		panic(err)
    	}
    	fmt.Println(res.Hits.TotalHits.Value)
    	for i := 0; int64(i) < res.Hits.TotalHits.Value; i += 1000 {
    		res, err = client.Search("codis-bigkey-2021-04-02*").Query(q).From(i).Size(1000).TrackTotalHits(true).Do(context.Background())
    		if err != nil {
    			panic(err)
    		}
    		for _, data := range res.Hits.Hits {
    			var typ Employee
    			err = json.Unmarshal(data.Source, &typ)
    			if err != nil {
    				panic(err)
    			}
    			keySlotNum := slotcrc32.GetIntvalKey(typ.KeyName)
    			if typ.KeyName == "guess_item2vec_similar_popular_level_novel" {
    				fmt.Println("guess_item2vec_similar_popular_level_novel", typ)
    			}
    			value, ok := slotInfoMap[keySlotNum]
    			switch ok {
    			case true:
    				value.totalCount += 1
    				value.totalSize += typ.Size
    				// fmt.Println(keySlotNum, value)
    				slotInfoMap[keySlotNum] = value
    			case false:
    				slotInfoMap[keySlotNum] = slotInfo{totalSize: typ.Size, totalCount: 1}
    			}
    		}
    		// break
    	}
    	// fmt.Println(slotInfoMap)
    	ms := NewMapSorter(slotInfoMap)
    	sort.Sort(ms)
    	totalCount := 0
    	for _, item := range ms {
    		totalCount += int(item.totalCount)
    		fmt.Println(item)
    	}
    	fmt.Println(totalCount)
    }
    
    func (ms MapSorter) Len() int {
    	return len(ms)
    }
    
    func (ms MapSorter) Less(i, j int) bool {
    	return ms[i].totalSize < ms[j].totalSize // 按值排序
    	//return ms[i].Key < ms[j].Key // 按键排序
    }
    
    func (ms MapSorter) Swap(i, j int) {
    	ms[i], ms[j] = ms[j], ms[i]
    }
    
    func NewMapSorter(m map[uint32]slotInfo) MapSorter {
    	ms := make(MapSorter, 0, len(m))
    	for k, v := range m {
    		ms = append(ms, slotInfo{totalSize: v.totalSize, totalCount: v.totalCount, slotNum: k})
    	}
    	return ms
    }
    
  • 相关阅读:
    各操作系统各文件系统支持的最大文件的大小
    Java调用百度地图API
    Java面试宝典(3)Java基础部分
    Java7中的try-with-resources
    Spring学习笔记(6)——IoC的三种注入方式
    cmd中java的编译命令——java和javac、javap
    Spring学习笔记(14)——注解零配置
    java中多种方式解析xml
    双三次插值
    RCNN到faster RCNN 简介
  • 原文地址:https://www.cnblogs.com/-xuan/p/14619789.html
Copyright © 2011-2022 走看看