En este artículo describiré el uso del kit Go, un conjunto de herramientas y bibliotecas para crear microservicios en Go. Este artículo es una introducción al kit Go. La primera parte de mi blog, el código fuente de los ejemplos está disponible aquí .
Go es cada vez más elegido para el desarrollo de sistemas distribuidos modernos. Cuando desarrolle un sistema distribuido basado en la nube, es posible que deba admitir varias funciones específicas en sus servicios, tales como: varios protocolos de transporte ( etc.transl. HTTP, gRPC, etc. ) y formatos de codificación de mensajes para ellos, confiabilidad RPC, registro , seguimiento, métricas y perfiles, interrupción de solicitudes, limitación del número de solicitudes, integración en la infraestructura e incluso descripción de la arquitectura. Go es un lenguaje popular debido a su simplicidad y enfoques "sin magia", por lo tanto, los paquetes de Go, por ejemplo, una biblioteca estándar, ya son más adecuados para desarrollar sistemas distribuidos que usar un marco completo con mucha "magia bajo el capó". Personalmente, yo [ aprox. trans. Shiju Varghese ] No apoyo el uso de frameworks completos, prefiero usar bibliotecas que den más libertad al desarrollador. El kit Go llenó el vacío en el ecosistema Go, haciendo posible el uso de un conjunto de bibliotecas y paquetes al crear microservicios, que a su vez permiten el uso de buenos principios para diseñar servicios individuales en sistemas distribuidos.

Introducción al kit Go
El kit Go es un conjunto de paquetes Go que facilitan la creación de microservicios confiables y compatibles. Go Kit proporciona bibliotecas para implementar varios componentes de una arquitectura de aplicación transparente y confiable, utilizando capas como: registro, métricas, rastreo, limitación e interrupción de solicitudes que son necesarias para ejecutar microservicios en el producto. Go kit es bueno porque tiene herramientas bien implementadas para interactuar con varias infraestructuras, formatos de codificación de mensajes y varias capas de transporte.
Además del conjunto de bibliotecas para servicios mundiales en desarrollo, proporciona y fomenta el uso de buenos principios para diseñar la arquitectura de sus servicios. El kit Go lo ayuda a adherirse a los principios SÓLIDOS, el enfoque orientado a temas (DDD) y la arquitectura hexagonal propuesta por Alistair Cockburn o cualquier otro enfoque de arquitectura conocido como " arquitectura de cebolla " por Jeffrey Palermo y " arquitectura limpia " por Robert C. Martin . Aunque el kit Go fue diseñado como un conjunto de paquetes para desarrollar microservicios, también es adecuado para desarrollar monolitos elegantes.
Kit de arquitectura Go
Los tres niveles principales en la arquitectura de las aplicaciones desarrolladas con el kit Go son:
- nivel de transporte
- nivel de punto final
- nivel de servicio
Nivel de transporte
Cuando escribe microservicios para sistemas distribuidos, los servicios en ellos a menudo tienen que comunicarse entre sí mediante varios protocolos de transporte, como: HTTP o gRPC, o utilizar sistemas pub / sub, como NATS. La capa de transporte en el kit Go está vinculada a un protocolo de transporte específico (en adelante, transporte). El kit Go admite varios transportes para su servicio, tales como: HTTP, gRPC, NATS, AMQP y Thirft ( aprox. También puede desarrollar su propio transporte para su protocolo ). Por lo tanto, los servicios escritos utilizando el kit Go a menudo se centran en la implementación de una lógica comercial específica que no sabe nada sobre el transporte utilizado, usted es libre de utilizar diferentes transportes para el mismo servicio. Como ejemplo, un servicio escrito en el kit Go puede proporcionarle acceso simultáneamente a través de HTTP y gRPC.
Puntos finales
Un punto final o punto final es el bloque de construcción fundamental para los servicios y los clientes. En el kit Go, el patrón de comunicación principal es RPC. El punto final se presenta como un método RPC separado. Cada método de servicio en el kit Go se convierte en un punto final, lo que le permite comunicarse entre el servidor y el cliente en el estilo RCP. Cada punto final expone un método de servicio utilizando la capa de transporte, que a su vez utiliza varios protocolos de transporte, como HTTP o gRPC. Un punto final separado se puede exponer fuera del servicio simultáneamente usando varios transportes ( aprox. Por HTTP y gRPC en diferentes puertos ).
Servicios
La lógica empresarial se implementa en la capa de servicio. Los servicios escritos con el kit Go están diseñados como interfaces. La lógica empresarial en la capa de servicio contiene el núcleo principal de la lógica empresarial, que no necesita saber nada sobre los puntos finales utilizados o un protocolo de transporte específico, como HTTP o gRPC, o sobre la codificación o decodificación de solicitudes y respuestas de varios tipos de mensajes. Esto le permitirá adherirse a una arquitectura limpia en los servicios escritos con el kit Go. Cada método de servicio se convierte en punto final mediante un adaptador y se expone al exterior mediante un transporte específico. Mediante el uso de una arquitectura limpia, se puede establecer un único método utilizando múltiples transportes al mismo tiempo.
Ejemplos
Y ahora veamos las capas descritas anteriormente usando un ejemplo de una aplicación simple.
Lógica empresarial en el servicio.
La lógica de negocios en el servicio está diseñada usando interfaces. Veremos un ejemplo de un pedido en el comercio electrónico:
La interfaz del servicio de pedidos funciona con la entidad de dominio de pedidos:
Aquí implementamos la interfaz del servicio de pedidos:
package implementation import ( "context" "database/sql" "time" "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" "github.com/gofrs/uuid" ordersvc "github.com/shijuvar/gokit-examples/services/order" )
Solicitudes y respuestas para puntos finales RPC
Los métodos de servicio están expuestos como puntos finales RPC. Por lo tanto, debemos determinar los tipos de mensajes ( aprox. Por DTO - objeto de transferencia de datos ) que se utilizarán para enviar y recibir mensajes a través de puntos finales RPC. Ahora definamos estructuras para los tipos de solicitud y respuesta para puntos finales RPC en el servicio de pedidos:
Ir a los puntos finales del kit para métodos de servicio como puntos finales RPC
El núcleo de nuestra lógica de negocios se separa del resto del código y se coloca en la capa de servicio, que se expone usando puntos finales RPC, que usan la abstracción del kit Go llamada Endpoint
.
Así es como se ve el punto final del kit Go:
type Endpoint func(ctx context.Context, request interface{}) (response interface{}, err error)
Como dijimos anteriormente, el punto final representa un método RPC separado. Cada método de servicio se convierte en endpoint.Endpoint
. Punto endpoint.Endpoint
mediante adaptadores. Hagamos los puntos finales del kit Go para los métodos de servicio de pedidos:
import ( "context" "github.com/go-kit/kit/endpoint" "github.com/shijuvar/gokit-examples/services/order" )
El adaptador de punto final acepta la interfaz como un parámetro para la entrada y la convierte en una abstracción del endpoint.Enpoint
kit Go. endpoint.Enpoint
convierte cada método de servicio individual en un punto final. Esta función de adaptador realiza conversiones de comparación y tipo para solicitudes, llama a un método de servicio y devuelve un mensaje de respuesta.
func makeCreateEndpoint(s order.Service) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(CreateRequest) id, err := s.Create(ctx, req.Order) return CreateResponse{ID: id, Err: err}, nil } }
Exponer un servicio usando HTTP
Creamos nuestro servicio y describimos los puntos finales RPC para exponer nuestros métodos de servicio. Ahora necesitamos publicar nuestro servicio en el exterior para que otros servicios puedan llamar a los puntos finales RCP. Para exponer nuestro servicio, necesitamos determinar el protocolo de transporte para nuestro servicio, según el cual aceptará solicitudes. El kit Go admite varios transportes, como HTTP, gRPC, NATS, AMQP y Thrift listos para usar.
Por ejemplo, utilizamos el transporte HTTP para nuestro servicio. El paquete go kit github.com/go-kit/kit/transport/http proporciona la capacidad de atender solicitudes HTTP. Y la función NewServer
del paquete transport/http
creará un nuevo servidor http que implementará http.Handler
y envolverá los puntos finales proporcionados.
A continuación se muestra el código que convierte los puntos finales del kit Go en un transporte HTTP que atiende solicitudes HTTP:
package http import ( "context" "encoding/json" "errors" "github.com/shijuvar/gokit-examples/services/order" "net/http" "github.com/go-kit/kit/log" kithttp "github.com/go-kit/kit/transport/http" "github.com/gorilla/mux" "github.com/shijuvar/gokit-examples/services/order/transport" ) var ( ErrBadRouting = errors.New("bad routing") )
Creamos http.Handler
utilizando la función NewServer
del NewServer
de transport/http
, que proporciona puntos finales y funciones de decodificación de solicitud (devuelve el valor del type DecodeRequestFunc func
) y la codificación de respuesta (por ejemplo, type EncodeReponseFunc func
).
Los siguientes son ejemplos de DecodeRequestFunc
y EncodeResponseFunc
:
Iniciando el servidor HTTP
Finalmente, podemos ejecutar nuestro servidor HTTP para procesar solicitudes. La función NewService
descrita anteriormente implementa la interfaz http.Handler
que nos permite ejecutarla como un servidor HTTP:
func main() { var ( httpAddr = flag.String("http.addr", ":8080", "HTTP listen address") ) flag.Parse() var logger log.Logger { logger = log.NewLogfmtLogger(os.Stderr) logger = log.NewSyncLogger(logger) logger = level.NewFilter(logger, level.AllowDebug()) logger = log.With(logger, "svc", "order", "ts", log.DefaultTimestampUTC, "caller", log.DefaultCaller, ) } level.Info(logger).Log("msg", "service started") defer level.Info(logger).Log("msg", "service ended") var db *sql.DB { var err error
Ahora se lanza nuestro servicio y utiliza el protocolo HTTP a nivel de transporte. El mismo servicio se puede iniciar usando otro transporte, por ejemplo, un servicio se puede exponer usando gRPC o Apache Thrift.
Para el artículo introductorio, ya hemos utilizado las primitivas del kit Go, pero también proporciona más funcionalidad para crear sistemas de patrones transparentes y confiables, descubrimiento de servicios, equilibrio de carga, etc. Discutiremos estas y otras cosas en el kit Go en los siguientes artículos.
Código fuente
El código fuente completo de los ejemplos se puede ver en GitHub aquí.
Middlewares en el kit Go
Go kit predispone al uso de buenos principios de diseño de sistemas, como la estratificación. El aislamiento de los componentes de servicio y puntos finales es posible utilizando Middlewares ( patrón de mediador de carril aprox. ). El kit Middlewares in the Go proporciona un poderoso mecanismo mediante el cual puede ajustar servicios y puntos finales y agregar funcionalidades (componentes aislados), como el registro, la interrupción de solicitudes, la limitación del número de solicitudes, el equilibrio de carga o el seguimiento distribuido.
A continuación se muestra una imagen del sitio web del kit Go , que se representa como una "arquitectura de cebolla" típica usando Middlewares en el kit Go:

Cuidado con el síndrome de microservicios de arranque de primavera
Al igual que el kit Go, Spring Boot es un kit de herramientas de microservicio en el mundo de Java. Pero, a diferencia del kit Go, Spring Boot es un marco muy maduro. Además, muchos desarrolladores de Java usan Spring Boot para crear servicios mundiales utilizando la pila de Java con comentarios positivos del uso, algunos de ellos creen que los microservicios solo se tratan de usar Spring Boot. Veo muchos equipos de desarrollo que malinterpretan el uso de microservicios, que solo se pueden desarrollar usando Spring Boot y OSS Netflix y no perciben los microservicios como un patrón cuando se desarrollan sistemas distribuidos.
Tenga en cuenta que con un conjunto de herramientas, como un kit Go o algún tipo de marco, dirige su desarrollo hacia microseurises, como un patrón de diseño. Aunque los microservicios resuelven muchos problemas de escalado tanto de comandos como de sistemas, también crea muchos problemas porque los datos en los sistemas de microservicios están dispersos en varias bases de datos, lo que a veces crea muchos problemas al crear consultas transaccionales o de datos. Todo depende del problema del área temática y del contexto de su sistema. Lo bueno es que el kit Go, diseñado como una herramienta para crear microservicios, también fue adecuado para crear monolitos elegantes que se crean con un buen diseño de arquitectura para sus sistemas.
Y algunas características del kit Go, como interrumpir y restringir solicitudes, también están disponibles en plataformas de malla de servicio, como Istio. Entonces, si usa algo como Istio para lanzar sus microseurises, es posible que no necesite algunas cosas del kit Go, pero no todos tendrán suficiente ancho de canal para usar la malla de servicio para crear comunicación entre servicios, ya que esto agrega más Un nivel y complejidad extra.
PS
El autor de la traducción puede no compartir la opinión del autor del texto original , este artículo ha sido traducido con fines educativos solo para la comunidad de idioma ruso Go.
UPD
Este es también el primer artículo en la sección de traducción y agradecería cualquier comentario sobre la traducción.