golang рефакторинг сервиса статистики блогов

Redis Go Nginx опрос Bower

Что касается внутренней разработки, то сегодня с появлением новых технологий, таких как docker, etcd, k8s, golang, герой, стоящий за ней, продолжает подниматься в рейтинге языков, поэтому арендодатель также открыл второй проект, используя разработанные основные функции. самим Голангом Принудительное путешествие.

Из весенней загрузки

Заинтересованные партнеры могут посмотреть предыдущую статью лендлорда, исходя из функций, реализованных Spring Boot, пожалуйста, переместитеВнедрить службу статистики блогов с помощью Spring Boot

Реализовать логику хранилища Redis

Причина выбора Redis вместо базы данных заключается в том, что Redis предоставляет богатые структуры данных и стратегии сохранения данных.Кроме того, Redis основан на памяти, которая более чем на порядок быстрее, чем базы данных. Сценарий подсчета количества прочтений все же имеет определенные требования к скорости обработки интерфейса, поэтому арендодатель выбрал redis в качестве БД для подсчета количества прочтений.
Ниже приведен базовый код работы Redis. Он относительно прост. Арендодатель опубликует код без дальнейшего уточнения.
Класс инструментов для операций Redis

func initRedisPool() {
	// 建立连接池
	RedisClient = &redis.Pool{
		// 从配置文件获取maxidle以及maxactive,取不到则用后面的默认值
		MaxIdle:     1,
		MaxActive:   10,
		IdleTimeout: 180 * time.Second,
		Dial: func() (redis.Conn, error) {
			c, err := redis.Dial("tcp", RedisAddress)
			if err != nil {
				return nil, err
			}
			// 选择db
			c.Do("SELECT", RedisDb)
			return c, nil
		},
	}
}

/**
 * 设置redis的对应key的value
 */
func redisSet(key string, value string) {
	c, err := RedisClient.Dial()
	if err != nil {
		fmt.Println("Connect to redis error", err)
		return
	}
	_, err = c.Do("SET", key, value)
	if err != nil {
		fmt.Println("redis set failed:", err)
	}
}

/**
 * 获取redis的对应key的value
 */
func redisGet(key string) (value string) {
	c, err := RedisClient.Dial()
	if err != nil {
		fmt.Println("Connect to redis error", err)
		return
	}
	val, err := redis.String(c.Do("GET", key))
	if err != nil {
		fmt.Println("redis get failed:", err)
		return ""
	} else {
		fmt.Printf("Got value is %v \n", val)
		return val
	}
}

/**
 * redis使得对应的key的值自增
 */
func redisIncr(key string) (value string) {
	c, err := RedisClient.Dial()
	_, err = c.Do("INCR", key)
	if err != nil {
		fmt.Println("incr error", err.Error())
	}

	incr, err := redis.String(c.Do("GET", key))
	if err == nil {
		fmt.Println("redis key after incr is : ", incr)
	}
	return incr
}

Реализация интерфейса статистики чтения блога

Базовая бизнес-логика статистики чтения блогов заключается в том, что blogId, соответствующий каждому блогу, используется в качестве ключа Redis, а количество посещений — это значение, соответствующее этому ключу.Каждый раз при доступе к интерфейсу соответствующий blogId будет увеличиваться. и будет возвращено соответствующее значение blogId. Структура данных redis, выбранная арендодателем, — это Stirng of redis. Ниже приведен основной код арендодателя для реализации логики:


package main

import (
	"encoding/json"
	"fmt"
	"github.com/garyburd/redigo/redis"
	"log"
	"net/http"
	"time"
	"strings"
)

const RedisAddress = "127.0.0.1:6379"
const RedisDb = 0

const AllowRequestUrlH = "*"
const  AllowRequestUrlW = "*"
const  IllegalCharacters = "?"
const  DefaultReadCount = "1"

var (
	// 定义常量
	RedisClient *redis.Pool
)

func main() {
	// 初始化redis连接池
	initRedisPool()

	// 启动web服务监听
	http.HandleFunc("/*-*/*/", blogReadCountIncr)       //设置访问的路由
	err := http.ListenAndServe(":9401", nil) //设置监听的端口
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}

func blogReadCountIncr(responseWriter http.ResponseWriter, request *http.Request) {

	// 解析参数,默认不解析
	request.ParseForm()

	blogId := request.Form.Get("blogId")

	log.Println(">>>>>> method blogReadCountIncr exec , request params is : ",blogId)

	// 判断请求参数是否为空
	if "" == blogId {
		result := ResultCode{
			Code: 200,
			Msg:  "success",
		}

		ret, _ := json.Marshal(result)
		fmt.Fprintf(responseWriter, string(ret)) //这个写入到w的是输出到客户端的
	}
	
	readCount := redisGet(blogId)
	if "" == readCount {
		// 不符合规则,直接返回
		flag := strings.Index(blogId, AllowRequestUrlH) != 0 ||strings.Index(blogId, AllowRequestUrlW) != 0||strings.Contains(blogId, IllegalCharacters)
		if  !flag {
			result := ResultCode{
				Code: 200,
				Msg:  "success",
			}

			ret, _ := json.Marshal(result)
			fmt.Fprintf(responseWriter, string(ret)) //这个写入到w的是输出到客户端的
		}

		redisSet(blogId, DefaultReadCount)
		readCount = DefaultReadCount
	} else {
		readCount = redisIncr(blogId)
	}
	log.Println(">>>>>> readCount is : ",readCount)
	result := ResultCode{
		Code: 200,
		Msg:  "success",
		Data: readCount,
	}
	ret, _ := json.Marshal(result)
	fmt.Fprintf(responseWriter, string(ret)) //这个写入到w的是输出到客户端的
}
// 结构体定义返回值
type ResultCode struct {
	Msg  string `json:"msg"`
	Code int    `json:"code"`
	Data string `json:"data"`
}

Яма, обнаруженная в процессе реализации

проблемы

При использовании собственного инструмента golang json для сериализации возникает проблема сбоя сериализации.Определение структуры, показанное ниже, на первый взгляд хорошо, но использование

ret, _ := json.Marshal(result)

При сериализации есть проблема, что нельзя сериализовать в json строку, и не сообщается об ошибке, от чего арендодателю головная боль.

type ResultCode struct {
	msg  string `json:"msg"`
	code int    `json:"code"`
	data string `json:"data"`
}

задача решена

В конце концов, арендодатель обнаружил, что существует проблема с определением структуры с помощью различных поз. При определении структуры первая буква должна быть заглавной для успешной сериализации. Эта функция очень очевидна в golang. вызываться в других файлах. Правильное определение структуры приведено ниже.

type ResultCode struct {
	Msg  string `json:"msg"`
	Code int    `json:"code"`
	Data string `json:"data"`
}

резюме

В настоящее время многие большие ребята написали учебники по сети golang. Если есть какие-либо сходства, пожалуйста, игнорируйте их. Эта статья завершена моим собственным реальным боем и ямой, на которую наступил домовладелец. Кроме того, эта статья основана на встроенныйnet/httpБиблиотека реализует веб-сервис.

Дополнительный

Арендодатель построил колесо. LIGHTCONF — это платформа управления конфигурацией, основанная на Netty. Ее основная цель — «предоставить унифицированную услугу управления конфигурацией для бизнеса», которую можно использовать «из коробки». Если вы заинтересованы, дайте звезду, чтобы поддержать это.

Автор: haifeiWu Исходная ссылка:Уууу. Пересаживайтесь на студию. Можете/статья/201…Заявление об авторских правах: Неспециальное заявление является оригинальной работой данного сайта.При перепечатке указывайте автора и оригинальную ссылку.