Este artículo se basa en el discurso "Financial Technology Go Microservices" pronunciado por Liu Yi, ingeniero senior de I+D del Founder Securities Financial Technology Engineering Institute, en el salón de tecnología CloudWeGo "Cloud Native✖️Arquitectura de microservicios y práctica técnica en la era de la IA". Evento de Beijing celebrado en Beijing el 30 de marzo de 2024. Compilado de "Construction Practice".
Descripción general: este artículo presentará en detalle la experiencia práctica del Founder Securities Financial Technology Engineering Institute en la construcción de microservicios nativos de la nube. El intercambio incluye tres aspectos:
- Trabajo de gobernanza de microservicios
- Trabajo de observabilidad de microservicios.
- Las capacidades anteriores de gestión de interfaces de microservicios están unificadas e integradas en la plataforma de desarrollo Quark de Founder.
Introducción a la práctica de la construcción de microservicios de Founder Securities.
A principios de 2023, lanzamos la construcción de un sistema de microservicio, en el que el centro de registro utiliza ZooKeeper , y los marcos de aplicaciones web y RPC utilizan Hertz y Kitex de CloudWeGo respectivamente .
En la actualidad, hemos entrado en el área profunda de la construcción de microservicios, que implica principalmente gobernanza de microservicios , capacidades de observabilidad , gestión de interfaces y otros trabajos relacionados. A continuación se presentarán los conceptos y principios de implementación en detalle.
Desarrollo de capacidades de gobernanza de microservicios
concepto
Bajo la arquitectura de microservicios, a medida que el volumen de negocios aumenta gradualmente, la cantidad de servicios también aumentará gradualmente. Con base en estos antecedentes, a medida que el negocio se desarrolle, será cada vez más difícil administrar y controlar los servicios. La función de la gobernanza del servicio es resolver una serie de problemas causados por la división del servicio para que los servicios puedan funcionar de manera más estable. proporciona registro y descubrimiento de servicios, equilibrio de carga, disyuntor de servicio, degradación del servicio, limitación de corriente del servicio, etc. Las funciones de tiempo de espera, reintento y limitación de corriente del lado del servidor proporcionadas por la plataforma Quark se basan en las capacidades relacionadas de Kitex . El centro de registro utilizado actualmente es ZooKeeper (abreviado como zk), por lo que la configuración dinámica relacionada también se implementa con la ayuda. de zk, escriba la configuración en zk para notificar al servidor y al cliente que completen la activación de las funciones relacionadas.
introducir
-
control de flujo
La granularidad del control de flujo es el nivel de servicio. Como se muestra en la figura siguiente, el servicio puede manejar hasta 1000 solicitudes por segundo y las solicitudes excesivas se cerrarán directamente:
-
Reintentar configuración
La granularidad de la configuración de reintento es el nivel de método, que se utiliza para configurar cómo reintentar cuando el servicio actual no puede realizar una solicitud a un método del servicio especificado:
-
Configuración de tiempo de espera
La granularidad de la configuración del tiempo de espera está a nivel de método, que se utiliza para configurar el tiempo máximo que tarda el servicio actual en solicitar un método del servicio especificado. Cuando se excede este valor, el servicio actual se desconectará: consulte la configuración. descripción de las funciones específicas de cada configuración.
Principios y detalles de implementación.
Tanto el lado del servidor como el del cliente completan la inyección dinámica de configuraciones relevantes ampliando la suite de Kitex .
lado del servidor
Configure el servidor Kitex a través del siguiente código:
server.WithSuite(zooKeeperServer.NewSuite("Kitex-server", zooKeeperClient))
Entre ellos, zooKeeperServer.NewSuite("Kitex-server", zooKeeperClient)
se devolverá una instancia de la suite y se incluirá la configuración del limitador inyectada en el servidor: Options
func (s *zooKeeperServerSuite) Options() []server.Option {
opts := make([]server.Option, 0, 2)
// WithLimiter实现中,在zk中注册了监听器,每当数据变化,动态更新Limiter的相关配置,以达到限流目的
opts = append(opts, WithLimiter(s.service, s.zooKeeperClient, s.opts))
return opts
}
Según el contenido anterior, se puede encontrar que solo los limitadores están configurados de forma predeterminada en la suite del lado del servidor. El marco Kitex actualmente solo admite dos tipos de limitadores:
- Limitador de conexiones (limita el número máximo de conexiones)
- Limitador de Qps (limita los qps máximos)
Cuando se utiliza zk como centro de registro, ambos se pueden ajustar dinámicamente mediante la configuración. Después de los cambios, los valores de configuración se obtienen a través del oyente de zk:
// zk数据变化时的回调方法
onChangeCallback := func(restoreDefault bool, data string, parser zooKeeper.ConfigParser) {
lc := &limiter.LimiterConfig{}
if !restoreDefault && data != "" {
err := parser.Decode(data, lc)
if err != nil {
klog.Warnf("[zooKeeper] %s server zooKeeper config: unmarshal data %s failed: %s, skip...", dest, data, err)
return
}
}
// 将zk中的数据动态更新到配置中
opt.MaxConnections = int(lc.ConnectionLimit)
opt.MaxQPS = int(lc.QPSLimit)
u := updater.Load()
if u == nil {
klog.Warnf("[zooKeeper] %s server zooKeeper limiter config failed as the updater is empty", dest)
return
}
if !u.(limit.Updater).UpdateLimit(opt) {
klog.Warnf("[zooKeeper] %s server zooKeeper limiter config: data %s may do not take affect", dest, data)
}
}
// path,对于limiter,其值为:/KitexConfig/{ServiceName}/limit
zooKeeperClient.RegisterConfigCallback(context.Background(), path, uniqueID, onChangeCallback)
lado del cliente
Al igual que en el lado del servidor, el lado del cliente también tiene la misma configuración:
bizService.NewClient("Kitex-client",
client.WithSuite(zooKeeperclient.NewSuite("Kitex-server", "Kitex-client", zooKeeperClient)))
La suite del lado del cliente contiene las siguientes opciones:
func (s *zooKeeperClientSuite) Options() []client.Option {
opts := make([]client.Option, 0, 7)
opts = append(opts, WithRetryPolicy(s.service, s.client, s.zooKeeperClient, s.opts)...)
opts = append(opts, WithRPCTimeout(s.service, s.client, s.zooKeeperClient, s.opts)...)
opts = append(opts, WithCircuitBreaker(s.service, s.client, s.zooKeeperClient, s.opts)...)
return opts
}
Es decir, el cliente admite tres configuraciones dinámicas: reintento, tiempo de espera y disyuntor. El procesamiento relevante se realiza mediante el método de devolución de llamada del cliente zk para lograr el efecto de actualización dinámica.
Notas adicionales sobre la configuración del tiempo de espera
Para el tiempo de espera, la implementación específica de su método de configuración es la siguiente:
func WithRPCTimeout(dest, src string, zooKeeperClient zooKeeper.Client, opts utils.Options) []client.Option {
// ...
return []client.Option{
client.WithTimeoutProvider(initRPCTimeoutContainer(path, uid, dest, zooKeeperClient)),
client.WithCloseCallbacks(func() error {
// cancel the configuration listener when client is closed.
zooKeeperClient.DeregisterConfig(path, uid)
return nil
}),
}
}
client.WithTimeoutProvider
Finalmente, la configuración específica relacionada con el tiempo de espera se completa llamando al método proporcionado por Kitex . Para los tiempos de espera, existen los siguientes métodos de configuración diferentes:
func WithRPCTimeout(d time.Duration) Option {
// ...
}
func WithConnectTimeout(d time.Duration) Option {
// ...
}
func WithTimeoutProvider(p rpcinfo.TimeoutProvider) Option {
// ...
}
Entre ellos, WithTimeoutProvider
el tiempo de espera establecido se sobrescribirá WithRPCTimeout
con el valor establecido de , por lo que si WithConnectTimeout
se llama a WithRPCTimeout
o al crear el cliente Kitex, WithConnectTimeout
la configuración dinámica no tendrá efecto.
Instrucciones de configuración
se acabó el tiempo
Nodo zk correspondiente:/kitexConfig/{ClientName}/{ServiceName}/rpc_timeout
El formato de configuración escrito es el siguiente:
{
"*": {
"conn_timeout_ms": 100,
"rpc_timeout_ms": 800
},
"GetDemoInfo": {
"rpc_timeout_ms": 300
},
"GetDemoInfo3": {
"rpc_timeout_ms": 300
}
}
Significado del campo : el tiempo máximo de espera para establecer una nueva conexión: el tiempo máximo para una llamada rpc; conn_timeout_ms
rpc_timeout_ms
Rever
Nodo zk correspondiente:/kitexConfig/{ClientName}/{ServiceName}/retry
El formato de configuración escrito es el siguiente:
{
"GetDemoInfo": {
"enable": true,
"type": 0,
"failure_policy": {
"stop_policy": {
"max_retry_times": 2,
"max_duration_ms": 9000,
"cb_policy": {
"error_rate": 0.1
}
}
}
},
"GetDemoInfo5": {
"enable": true,
"type": 0,
"failure_policy": {
"stop_policy": {
"max_retry_times": 2,
"max_duration_ms": 9000,
"cb_policy": {
"error_rate": 0.1
}
}
}
}
}
Significado del campo
Elementos de configuración | valor por defecto | ilustrar | límite |
---|---|---|---|
max_retry_times | 2 | El número máximo de reintentos, excluyendo la primera solicitud. Si se configura en 0, significa dejar de reintentar. | Valores legales: [0-5] |
max_duration_ms | 0 | El tiempo máximo acumulado transcurrido, incluido el tiempo transcurrido para la primera solicitud fallida y la solicitud de reintento. Si el tiempo transcurrido alcanza el límite, se detendrán los reintentos posteriores. 0 significa sin límite. Nota: Si está configurado, este elemento de configuración debe ser mayor que el tiempo de espera de la solicitud. | |
Tasa de error | 10% | Reintentar el umbral de tasa de error del disyuntor; si la tasa de error de solicitud a nivel de método excede el umbral, se detendrán los reintentos. | Valores legales: (0-30%] |
Limitando
Esta configuración es una configuración global para el servicio, por lo que la ruta del nodo zk solo contiene el nombre del servicio:/kitexConfig/{ServiceName}/limit
El formato de configuración escrito es el siguiente:
{
"qps_limit": 100
}
Creación de capacidad de observabilidad de microservicios
concepto
La construcción de observabilidad del servicio se refiere al establecimiento y mejora de monitoreo, registro, seguimiento y otras herramientas y tecnologías en sistemas distribuidos para comprender de manera integral y oportuna el estado operativo y los indicadores de rendimiento del sistema.
Una herramienta de observación completa puede aportar muchos beneficios a los sistemas empresariales:
- Capacidad para detectar y resolver problemas de manera oportuna;
- Permitir que el equipo tenga una comprensión más clara del funcionamiento general y las interacciones internas del sistema;
- Puede comprender el estado de la carga, la utilización de recursos y los cambios de tendencias del sistema para respaldar la planificación de la capacidad y la optimización de los recursos;
- Al registrar los registros de operación del sistema y los seguimientos de solicitudes a través del sistema de registro y seguimiento, se pueden rastrear y analizar los comportamientos de operación del usuario, las solicitudes anormales y los eventos de seguridad para mejorar la seguridad y confiabilidad del sistema.
introducir
Los detalles del servicio se utilizan para mostrar el funcionamiento general del servicio en sí, incluidos los indicadores de monitoreo dorados (QPS, latencia y tasa de errores), SLO e información relacionada con el tiempo de ejecución, etc.:
El diagrama de topología se utiliza para mostrar las dependencias ascendentes y descendentes entre servicios:
Los datos de la cadena de llamadas contienen información detallada sobre cada llamada entre servicios:
Principios y detalles de implementación.
Actualmente, el cliente OpenTelemetry se ha integrado en el código de la plantilla y los servicios Hertz y Kitex generados tienen capacidades de generación de informes de datos observables (Métricas + Seguimiento) de forma predeterminada.
Para obtener información detallada, consulte: kitex-contrib/obs-opentelemetry y hertz-contrib/obs-opentelemetry
OpenTelemetry (OTel) es un marco de observabilidad de código abierto que permite a los equipos de desarrollo generar, procesar y transmitir datos de telemetría en un formato único y unificado. Fue desarrollado por Cloud Native Computing Foundation (CNCF) para proporcionar protocolos y herramientas estándar para recopilar y enviar métricas, registros y seguimientos a plataformas de monitoreo. OpenTelemetry proporciona SDK, API y herramientas independientes del proveedor. OpenTelemetry se está convirtiendo rápidamente en el estándar de datos de telemetría de observabilidad dominante para aplicaciones nativas de la nube. La adopción de OpenTelemetry es fundamental para las organizaciones que desean estar preparadas para satisfacer las necesidades futuras de datos sin estar atadas a un proveedor específico o limitadas por su tecnología heredada.
Rastro
El seguimiento proporciona una imagen completa de todo el ciclo de vida desde la recepción de la solicitud hasta su finalización.
Después de recibir la solicitud, el servicio habilita el seguimiento de enlaces desde metainformación (Kitex) o encabezado http (Hertz). Si no hay información de seguimiento en la metainformación o en el encabezado HTTP, el seguimiento de nuevos enlaces se habilitará automáticamente. La información del enlace se pasa dentro del proceso de servicio a través del contexto.
Método de acceso:
// for Hertz
tracer, cfg := hertztracing.NewServerTracer()
h := server.Default(tracer)
h.Use(hertztracing.ServerMiddleware(cfg))
// for Kitex
svr := echo.NewServer(new(DemoImpl),
server.WithSuite(tracing.NewServerSuite()),
server.WithServerBasicInfo(&rpcinfo.EndpointBasicInfo{ServiceName: serviceName}),)
La información de seguimiento se envía a OpenTelemetry Collector y luego se transmite de forma transparente a Jaeger. La información relacionada con el enlace se puede consultar en Jaeger.
Proporciona una impresora de registros unificada fzlog, que imprime información relacionada con el seguimiento de forma predeterminada.
{
"file": "get_repositories.go:33",
"func": "gitlab.fzzqft.com/ifte-quark/quark-api/biz/service.(*GetRepositoriesService).Run",
"level": "info",
"msg": "GetRepositoriesService Run req: page:1 limit:10 service_name:\"kitex\"",
"span_id": "aa26bab58cdf6806",
"time": "2024-04-23 15:59:40.609",
"trace_flags": "01",
"trace_id": "f714dbe2a96b1882dfc4b81909e55643"
}
Una vez recopilados y procesados los registros, la información de registro relevante de todo el enlace se puede consultar en la plataforma de registros . trace_id
Métrica
Las métricas son datos clave que miden el rendimiento y el comportamiento del sistema, como la tasa de solicitudes, el tiempo de respuesta, la tasa de errores, etc. Por lo general, las métricas se recopilan, agregan y visualizan para monitorear el estado del sistema y realizar análisis de tendencias.
Actualmente, cada servicio informa sus propios datos de métricas y los almacena de manera uniforme en Prometheus/VictoriaMetrics, y finalmente usa grafana para formar un panel de monitoreo.
A continuación se utilizan tres indicadores comunes de descripción de servicios: QPS, tiempo de solicitud y tasa de error para demostrar cómo utilizar los datos de métricas informados por el servicio.
-
QPS: según la definición de QPS, solo necesitamos obtener la cantidad de solicitudes en tiempo real para calcular QPS.
http_server_duration_count
El valor en los datos informados es consistente con la cantidad de solicitudes, por lo que esta métrica se puede usar para completar el cálculo de. QPS.sum(rate(http_server_duration_count{service_name="$service_name"}[$__rate_interval]))
CopiarEn el promQL anterior, la función de tasa se utiliza para calcular la tasa de crecimiento de una determinada métrica dentro de un período de tiempo específico, y el resultado final es el número promedio de solicitudes dentro del período de tiempo especificado.
-
Consumo de tiempo de solicitud: dado que son datos estadísticos, aquí elegimos utilizar el promedio para representar el consumo de tiempo de las solicitudes de servicio. El consumo de tiempo promedio se obtiene por el consumo de tiempo total de todas las solicitudes en el período de tiempo especificado ➗El número de. solicitudes en el período de tiempo especificado:
sum(rate(http_server_duration_sum{service_name="$service_name"}[$__rate_interval])) by (application) / sum(rate(http_server_duration_count{service_name="$service_name"}[$__rate_interval])) by (application)
Copiar -
Tasa de error: primero filtre la cantidad de solicitudes erróneas y divida por la cantidad total de solicitudes para obtener la tasa de error
round((1 - (sum(rate(http_server_duration_count{service_name="$service_name",http_status_code=~"^(2|3).*"} [$__interval]))/sum(rate(http_server_duration_count{service_name="$service_name"}[$__interval])))), 0.0001)
Copiar
Topología
Las dependencias generales entre servicios se muestran a través de los datos métricos mencionados en la agregación. Los datos informados contienen service_name
información , source
y la información ascendente y descendente del servicio se puede obtener target
a través del operador PromSQL .sum
Creación de capacidades de gestión de interfaces de microservicios
concepto
-
idl
El lenguaje de descripción de interfaz (IDL) es un lenguaje informático que se utiliza para describir la interfaz de los componentes de software. IDL describe interfaces de forma independiente del lenguaje de programación, lo que permite que los objetos que se ejecutan en diferentes plataformas y programas escritos en diferentes lenguajes se comuniquen entre sí.
-
Gestión de interfaz
Todos los servicios Kitex (RPC) se implementan en base a IDL. La plataforma de administración de interfaces proporciona principalmente una plataforma de interfaz para administrar los productos IDL de los servicios RPC, lo que facilita a los desarrolladores administrar y llamar a las interfaces RPC.
-
Pruebas de interfaz
No se puede acceder al servicio Kitex (RPC) para realizar pruebas. Los usuarios de la plataforma de prueba de interfaz resuelven este problema para facilitar las pruebas y el desarrollo iniciando solicitudes RPC a través de la plataforma para completar la depuración.
introducir
- Plataforma de gestión de interfaz (ver imagen para conocer el método de operación)
- Plataforma de prueba de interfaz (depuración de interfaz Kitex (RPC))
Principios y detalles de implementación.
-
Gestión de interfaz
Anteriormente, utilizamos un almacén independiente con gitlabci para administrar los productos IDL del servicio Kitex : durante el uso real, surgieron los siguientes puntos débiles:
- La persona que llama debe obtener la dirección, sucursal o número de versión del almacén de productos IDL a través de una pequeña ventana (chat privado)
- El método de prestación de servicios debe prestar atención tanto al almacén del proyecto de servicio como al almacén de producto correspondiente.
- Gitlabci depende en gran medida del corredor y el administrador debe configurar los nuevos grupos antes de que puedan usarse.
- No se puede vincular profundamente al proceso CICD existente
Para resolver los problemas y puntos débiles anteriores, se diseñó y desarrolló una plataforma de gestión de interfaz.
Cuando el servicio se crea y empaqueta, se activa el proceso de actualización del producto IDL. La plataforma detectará automáticamente el tipo de servicio, generará el producto IDL correspondiente y lo enviará al almacén independiente de gitlab. Los usuarios también pueden crear o actualizar manualmente productos IDL en la plataforma. La persona que llama solo necesita copiar y ejecutar el comando de ruta de importación para obtener la versión correspondiente de la dependencia del servicio.
-
La prueba de interfaz se implementa en base a la llamada de generalización de mapeo JSON de Kitex PB. El usuario selecciona el servicio y la interfaz correspondientes en la plataforma, y la plataforma analiza automáticamente el archivo IDL correspondiente y proporciona los parámetros de solicitud predeterminados (formato json). Después de enviar la solicitud, la plataforma inicia una solicitud RPC al servicio de destino mediante una llamada generalizada y devuelve el resultado.
resumen
El sistema de microservicio actual ya puede satisfacer la mayoría de las necesidades técnicas, pero planeamos ir más allá con el sistema nativo de la nube:
- La gobernanza del servicio se basa en capacidades de malla de servicios nativa de la nube (ServiceMesh) para gestionar el tráfico, al mismo tiempo que incorpora el tráfico de este a oeste desde otros marcos de aplicaciones.
- Observabilidad, OpenTelemetry es un conjunto de soluciones que son independientes del lenguaje y el marco de la aplicación. A través de una semántica unificada, planea incorporar los sistemas Java Web (Springboot) y RPC (Dubbo).
- Gestión de interfaces, en el futuro está previsto gestionar de forma unificada las interfaces RPC y HTTP y generar automáticamente casos de uso de interfaces.
actividades recientes
Los usuarios y desarrolladores empresariales están sinceramente invitados a participar en el Salón de Tecnología CloudWeGo . El evento se llevará a cabo en Shanghai el 25 de mayo de 2024 (sábado) , e invitará a colegas técnicos a discutir cómo las empresas pueden construir una arquitectura de microservicios nativa de la nube para respaldar la rápida iteración y el desarrollo de productos bajo la ola de xAI nativa de la nube . Escanea el código QR en la imagen para registrarte inmediatamente, ¡nos vemos allí!
Los recursos pirateados de "Celebrating More Than Years 2" se cargaron en npm, lo que provocó que npmmirror tuviera que suspender el servicio unpkg. El equipo de inteligencia artificial de Microsoft en China empacó colectivamente y se fue a los Estados Unidos, involucrando a cientos de personas. Biblioteca de visualización frontal y el conocido proyecto de código abierto ECharts de Baidu: "ir al mar" para respaldar a Fish. ¡ Los estafadores utilizaron TeamViewer para transferir 3,98 millones! ¿Qué deberían hacer los proveedores de escritorio remoto? Zhou Hongyi: No queda mucho tiempo para que Google recomiende que todos los productos sean de código abierto. Un ex empleado de una conocida empresa de código abierto dio la noticia: después de ser desafiado por sus subordinados, el líder técnico se enfureció. Despidió a la empleada embarazada. Google mostró cómo ejecutar ChromeOS en una máquina virtual de Android. Por favor, dame un consejo, ¿qué papel juega aquí time.sleep(6)? Microsoft responde a los rumores de que el equipo de IA de China está "haciendo las maletas para Estados Unidos" El People's Daily Online comenta sobre la carga tipo matrioska del software de oficina: Sólo resolviendo activamente los "conjuntos" podremos tener un futuro