Directorio de artículos
- prefacio
- - agregación de datos
- Dos autocompletado
- Sincronización de tres datos
-
- 3.1 Análisis del pensamiento
- 3.2 Solución 1: llamada síncrona
- 3.3 Solución 2: notificación asíncrona
- 3.4 Supervisar binlog
- 3.5 Comparación y resumen de tres esquemas
- 3.6 Resumen de casos de sincronización de datos
- 3.7 Caso de prueba de sincronización de datos
- 3.8 Suplemento: Instalación del complemento vue Devtools
- 3.9 Explicación de la herramienta vue devtools
- Cuatro clústeres de búsqueda elástica
-
- 4.1 **Conceptos relacionados con el clúster ES**
- 4.2 Crear un clúster ES
- 4.4 Supervisión del estado del clúster
-
- 4.4.1 Win instalación cerebro [no recomendado]
- 4.4.2 Problema de retroceso [sin resolver]
- 4.4.3 instalar cerebo en linux
- 4.4.5 Crear una biblioteca de índices
- 4.4.6 Uso de DevTools de Kibana para crear una biblioteca de índices [operación no práctica]
- 4.4.7 Uso de cerebro para crear una biblioteca de índices [operación práctica]
- 4.4.8 Ver efecto de fragmentación
- 4.9 Problema de cerebro dividido en racimo
- 4.10 Almacenamiento distribuido en clúster
prefacio
- Este artículo se aprende de un caballo oscuro, y después de un estudio cuidadoso, se clasifica y se resume, ¡no se copia! !
- Con respecto a la parte de la operación real, se recomienda que los alumnos hagan más prácticas y analicen con cuidado. ! !
- Esta parte tiene requisitos ligeramente más altos en la computadora, ¡preste atención para actualizar la configuración de la computadora! ! !
- agregación de datos
- Las agregaciones pueden realizar las estadísticas, el análisis y la operación de los datos del documento.
- Hay tres tipos comunes de agregación:
- Agregación de cubos: se utiliza para agrupar documentos
- TermAggregation: agrupar por valor de campo de documento
- Histograma de fechas: agrupar por escala de fechas, por ejemplo, una semana como grupo o un mes como grupo
- Agregación de cubos: se utiliza para agrupar documentos
- Agregación de métricas: se utiliza para calcular algunos valores, como: valor máximo, valor mínimo, valor promedio, etc.
- Promedio: Promedio
- Max: encontrar el valor máximo
- Min: encontrar el valor mínimo
- Estadísticas: busque simultáneamente máximo, mínimo, promedio, suma, etc.
- Pipeline (pipeline) agregación: agregación basada en los resultados de otras agregaciones
- **Nota:** Los campos que participan en la agregación deben ser palabra clave, fecha, valor y valor booleano.
1.1 DSL realiza la agregación
1.1.1 Sintaxis de agregación de cubos
GET /hotel/_search
{
"size": 0, // 设置size为0,结果中不包含文档,只包含聚合结果
"aggs": {
// 定义聚合
"brandAgg": {
//给聚合起个名字
"terms": {
// 聚合的类型,按照品牌值聚合,所以选择term
"field": "brand", // 参与聚合的字段
"size": 20 // 希望获取的聚合结果数量
}
}
}
}
- Ejemplo:
#桶排序 GET /hotel/_search { "size": 0, "aggs": { "brandAgg": { "terms": { "field": "brand", "size": 20 } } } }
- resultado:
1.1.2 Clasificación de resultados de agregación
- De forma predeterminada, la agregación del depósito contará el número de documentos en el depósito, lo registrará como _count y ordenará en orden descendente de _count.
- Especifique el atributo de orden para personalizar el método de clasificación de agregación
- Manifestación:
#自定义聚合的排序方式 # 按照_count升序排列 GET /hotel/_search { "size": 0, "aggs": { "brandAgg": { "terms": { "field": "brand", "order": { "_count": "asc" }, "size": 20 } } } }
- resultado:
- resultado:
1.1.3 Limitar el alcance de la agregación
- De forma predeterminada, la agregación de depósitos agrega todos los documentos en la biblioteca de índices, pero en escenarios reales, los usuarios ingresarán las condiciones de búsqueda, por lo que la agregación debe ser la agregación de los resultados de la búsqueda. Entonces la agregación tiene que ser calificada.
- Para limitar el rango de documentos que se agregarán, simplemente agregue condiciones de consulta:
- Manifestación:
# 限定聚合范围 # 只对200元以下的文档聚合 GET /hotel/_search { "query": { "range": { "price": { "lte": 200 } } }, "size": 0, "aggs": { "brandAgg": { "terms": { "field": "brand", "size": 20 } } } }
- resultado:
1.2 Sintaxis de agregación de métricas
- Agregación de métricas: se utiliza para calcular algunos valores, como: valor máximo, valor mínimo, valor promedio, etc.
- Promedio: Promedio
- Max: encontrar el valor máximo
- Min: encontrar el valor mínimo
- Estadísticas: busque simultáneamente máximo, mínimo, promedio, suma, etc.
- Manifestación:
GET /hotel/_search
{
"size": 0,
"aggs": {
"brandAgg": {
"terms": {
"field": "brand",
"size": 20
},
"aggs": {
// 是brands聚合的子聚合,也就是分组后对每组分别计算
"score_stats": {
// 聚合名称
"stats": {
// 聚合类型,这里stats可以计算min、max、avg等
"field": "score" // 聚合字段,这里是score
}
}
}
}
}
}
- resultado:
1.3 Resumen
-
aggs significa agregación, que está al mismo nivel que consulta ¿Cuál es la función de consulta en este momento?
- Alcance de los documentos agregados
-
Los tres elementos necesarios para la agregación:
- nombre agregado
- tipo de agregación
- campo agregado
-
Las propiedades configurables agregadas son:
- tamaño: especifique el número de resultados de agregación
- order: especifique el método de clasificación de los resultados de agregación
- campo: especifique el campo de agregación
1.4 RestAPI realiza la agregación
1.5 Sintaxis de la API
- Las condiciones de agregación están al mismo nivel que las condiciones de consulta, por lo que se debe usar request.source() para especificar las condiciones de agregación.
- Sintaxis para condiciones agregadas:
- El resultado de la agregación también es diferente del resultado de la consulta y la API también es especial. Sin embargo, JSON también se analiza capa por capa:
1,7 caso
- Requisito: la marca, la ciudad y otra información de la página de búsqueda no deben codificarse en la página, sino obtenerse mediante datos agregados del hotel en la base de datos del índice:
- analizar:
- Use la función de agregación y la agregación de cubos para agrupar los documentos en los resultados de búsqueda según la marca y la ciudad, y conozca las marcas y ciudades incluidas.
- Debido a que es una agregación de resultados de búsqueda, la agregación es una agregación de rango limitado , es decir, las condiciones limitantes de la agregación son consistentes con las condiciones del documento de búsqueda.
- El tipo de valor de retorno es el resultado final que se mostrará en la página:
- El resultado es una estructura Map:
- la clave es una cadena, ciudad, estrella, marca, precio
- el valor es una colección, como los nombres de varias ciudades
-
Código lógico importante implementado
-
Agregue un método en
Controller
los siguientes requisitos:- Método de solicitud:
POST
- Solicitud de ruta:
/hotel/filters
- Parámetros de la solicitud:
RequestParams
, consistentes con los parámetros del documento de búsqueda - Tipo de valor de retorno:
Map<String, List<String>>
@PostMapping("filters") public Map<String, List<String>> getFilters(@RequestBody RequestParams params){ return hotelService.filters(params); }
- Método de solicitud:
-
Service
Defina el nuevo método en :Map<String, List<String>> filters(RequestParams params);
-
Implemente este método en
HotelService
la clase de implementación de@Override public Map<String, List<String>> filters(RequestParams params) { try { // 1.准备Request SearchRequest request = new SearchRequest("hotel"); // 2.准备DSL // 2.1.query buildBasicQuery(params, request); // 2.2.设置size request.source().size(0); // 2.3.聚合 buildAggregation(request); // 3.发出请求 SearchResponse response = client.search(request, RequestOptions.DEFAULT); // 4.解析结果 Map<String, List<String>> result = new HashMap<>(); Aggregations aggregations = response.getAggregations(); // 4.1.根据品牌名称,获取品牌结果 List<String> brandList = getAggByName(aggregations, "brandAgg"); result.put("品牌", brandList); // 4.2.根据品牌名称,获取品牌结果 List<String> cityList = getAggByName(aggregations, "cityAgg"); result.put("城市", cityList); // 4.3.根据品牌名称,获取品牌结果 List<String> starList = getAggByName(aggregations, "starAgg"); result.put("星级", starList); return result; } catch (IOException e) { throw new RuntimeException(e); } } private void buildAggregation(SearchRequest request) { request.source().aggregation(AggregationBuilders .terms("brandAgg") .field("brand") .size(100) ); request.source().aggregation(AggregationBuilders .terms("cityAgg") .field("city") .size(100) ); request.source().aggregation(AggregationBuilders .terms("starAgg") .field("starName") .size(100) ); } private List<String> getAggByName(Aggregations aggregations, String aggName) { // 4.1.根据聚合名称获取聚合结果 Terms brandTerms = aggregations.get(aggName); // 4.2.获取buckets List<? extends Terms.Bucket> buckets = brandTerms.getBuckets(); // 4.3.遍历 List<String> brandList = new ArrayList<>(); for (Terms.Bucket bucket : buckets) { // 4.4.获取key String key = bucket.getKeyAsString(); brandList.add(key); } return brandList; }
-
Aviso:
- En la parte del caso, el código no necesariamente debe personalizarse manualmente uno por uno, ¡pero debe operarlo usted mismo para verificar el resultado final! ! !
- ¡Al mismo tiempo, trabaje duro para lidiar con los problemas que encuentre! ! !
Dos autocompletado
- El efecto es como se muestra en la figura:
- De acuerdo con las letras ingresadas por el usuario, la función de solicitar entradas completas es la finalización automática
- Debido a que debe inferirse en función de las letras pinyin, se utiliza la función de segmentación de palabras pinyin
2.1 Instalación del separador de palabras Pinyin
- Para lograr la finalización basada en letras, es necesario segmentar el documento según pinyin. Resulta que hay un complemento de segmentación de palabras pinyin para elasticsearch en GitHub. DIRECCIÓN
-
descargar y descomprimir
-
Subir a la máquina virtual, el directorio de complementos de elasticsearch
- Para instalar el complemento, debe conocer la ubicación del directorio de complementos de elasticsearch, y usamos el montaje de volumen de datos, por lo que debemos ver el directorio de volumen de datos de elasticsearch y verificarlo con el siguiente comando:
docker volume inspect es-plugins
- Luego cargue el archivo descomprimido a este directorio,
py
como el separador de palabras pinyin después de la descompresión y el cambio de nombre
-
reiniciar búsqueda elástica
docker restart es
-
prueba
POST /_analyze { "text": "如家酒店还不错", "analyzer": "pinyin" }
2.2 Tokenizador personalizado
-
El separador de palabras pinyin predeterminado divide cada carácter chino en pinyin, pero queremos que cada entrada forme un conjunto de pinyin, por lo que debemos personalizar el separador de palabras pinyin para formar un separador de palabras personalizado.
-
La composición del analizador en elasticsearch consta de tres partes:
- filtros de caracteres : procesa el texto antes del tokenizador. por ejemplo, eliminar caracteres, reemplazar caracteres
- tokenizer : Cortar el texto en términos de acuerdo con ciertas reglas. Por ejemplo, palabra clave no es participio; también existe ik_smart
- Filtro tokenizador : procesa aún más las entradas generadas por el tokenizador. Por ejemplo, conversión de casos, procesamiento de sinónimos, procesamiento de pinyin, etc.
-
Cuando la segmentación de palabras del documento, el documento será procesado por estas tres partes a su vez:
-
manifestación
#拼音分词器
DELETE /test
PUT /test
{
"settings": {
"analysis": {
"analyzer": {
"my_analyzer": {
"tokenizer": "ik_max_word",
"filter": "py"
}
},
"filter": {
"py": {
"type": "pinyin",
"keep_full_pinyin": false,
"keep_joined_full_pinyin": true,
"keep_original": true,
"limit_first_letter_length": 16,
"remove_duplicated_term": true,
"none_chinese_pinyin_tokenize": false
}
}
}
},
"mappings": {
"properties": {
"name": {
"type": "text",
"analyzer": "my_analyzer",
"search_analyzer": "ik_smart"
}
}
}
}
POST /test/_analyze
{
"text": ["如家酒店还不错"],
"analyzer": "my_analyzer"
}
- resultado:
- Precauciones para el separador de palabras pinyin
- Para evitar buscar homófonos, no utilice el separador de palabras pinyin cuando busque
2.3 Consulta de autocompletar
-
Elasticsearch proporciona una consulta Sugerente de finalización para lograr la finalización automática. Esta consulta hará coincidir los términos que comienzan con la entrada del usuario y los devolverá. Para mejorar la eficiencia de la consulta de finalización, existen algunas restricciones en los tipos de campos en el documento:
- Los campos que participan en la consulta de cumplimentación deben ser de tipo cumplimentación.
- El contenido del campo es generalmente una matriz formada por múltiples entradas para completar.
-
Manifestación:
# 自动补全查询
DELETE /test02
## 创建索引库
PUT /test02
{
"mappings": {
"properties": {
"title": {
"type": "completion"
}
}
}
}
## 示例数据
POST test02/_doc
{
"title": ["Sony", "WH-1000XM3"]
}
POST test02/_doc
{
"title": ["SK-II", "PITERA"]
}
POST test02/_doc
{
"title": ["Nintendo", "switch"]
}
## 自动补全查询
GET /test02/_search
{
"suggest": {
"title_suggest": {
"text": "s", # 关键字
"completion": {
"field": "title", #补全查询的字段
"skip_duplicates": true, #跳过重复的
"size": 10 #获取前10条结果
}
}
}
}
2.4 API de Java para consultas de finalización automática
- Primero mire la API construida por el parámetro de solicitud:
- Veamos el análisis de resultados:
- Código importante:
@Override public List<String> getSuggestions(String prefix) { try { // 1.准备Request SearchRequest request = new SearchRequest("hotel"); // 2.准备DSL request.source().suggest(new SuggestBuilder().addSuggestion( "suggestions", SuggestBuilders.completionSuggestion("suggestion") .prefix(prefix) .skipDuplicates(true) .size(10) )); // 3.发起请求 SearchResponse response = client.search(request, RequestOptions.DEFAULT); // 4.解析结果 Suggest suggest = response.getSuggest(); // 4.1.根据补全查询名称,获取补全结果 CompletionSuggestion suggestions = suggest.getSuggestion("suggestions"); // 4.2.获取options List<CompletionSuggestion.Entry.Option> options = suggestions.getOptions(); // 4.3.遍历 List<String> list = new ArrayList<>(options.size()); for (CompletionSuggestion.Entry.Option option : options) { String text = option.getText().toString(); list.add(text); } return list; } catch (IOException e) { throw new RuntimeException(e); } }
Sincronización de tres datos
- Introducir:
3.1 Análisis del pensamiento
- Hay tres esquemas comunes de sincronización de datos:
- Solución 1: llamada síncrona
- Solución 2: notificación asíncrona
- Solución 3: monitorear binlog
3.2 Solución 1: llamada síncrona
- Los pasos básicos son los siguientes:
- hotel-demo proporciona una interfaz para modificar los datos en elasticsearch
- Una vez que el servicio de administración del hotel completa la operación de la base de datos, llama directamente a la interfaz proporcionada por hotel-demo
3.3 Solución 2: notificación asíncrona
- El proceso es el siguiente:
- El administrador del hotel envía un mensaje MQ después de agregar, eliminar y modificar los datos de la base de datos mysql
- Hotel-demo escucha MQ y completa la modificación de datos de elasticsearch después de recibir el mensaje
3.4 Supervisar binlog
- El proceso es el siguiente:
- Habilite la función binlog para mysql
- Las operaciones de adición, eliminación y modificación de mysql quedarán registradas en el binlog
- Hotel-demo monitorea los cambios de binlog según el canal y actualiza el contenido en elasticsearch en tiempo real
3.5 Comparación y resumen de tres esquemas
plan | llamada síncrona | llamada asíncrona | registro de binlog del monitor |
---|---|---|---|
ventaja | Darse cuenta simple, crudo | Acoplamiento bajo, generalmente difícil de implementar | Desacoplamiento completo entre servicios |
defecto | Alto grado de acoplamiento empresarial | Confíe en la fiabilidad de mq | Habilitar binlog aumenta la carga de la base de datos y hace que la implementación sea más compleja |
3.6 Resumen de casos de sincronización de datos
-
Cuando se agregan, eliminan o modifican los datos del hotel, se requiere la misma operación para los datos en elasticsearch.
-
paso:
- Importe el proyecto hotel-admin proporcionado por los datos, inicie y pruebe el CRUD de los datos del hotel
- Complete el envío de mensajes en agregar, eliminar y cambiar negocios en hotel-admin
- Use anotaciones para declarar intercambio, cola y RoutingKey en hotel-demo, monitoreo completo de mensajes y actualización de datos en elasticsearch
- Iniciar y probar la función de sincronización de datos
-
La estructura MQ se muestra en la figura:
-
confiar:
<!--amqp--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency>
-
Declarar el nombre de intercambio de la cola
public class MqConstants { /** * 交换机 */ public final static String HOTEL_EXCHANGE = "hotel.topic"; /** * 监听新增和修改的队列 */ public final static String HOTEL_INSERT_QUEUE = "hotel.insert.queue"; /** * 监听删除的队列 */ public final static String HOTEL_DELETE_QUEUE = "hotel.delete.queue"; /** * 新增或修改的RoutingKey */ public final static String HOTEL_INSERT_KEY = "hotel.insert"; /** * 删除的RoutingKey */ public final static String HOTEL_DELETE_KEY = "hotel.delete"; }
-
Enviar mensaje MQ
@PostMapping public void saveHotel(@RequestBody Hotel hotel){ hotelService.save(hotel); rabbitTemplate.convertAndSend(MqConstants.HOTEL_EXCHANGE,MqConstants.HOTEL_INSERT_KEY,hotel.getId()); } @PutMapping() public void updateById(@RequestBody Hotel hotel){ if (hotel.getId() == null) { throw new InvalidParameterException("id不能为空"); } hotelService.updateById(hotel); rabbitTemplate.convertAndSend(MqConstants.HOTEL_EXCHANGE,MqConstants.HOTEL_INSERT_KEY,hotel.getId()); } @DeleteMapping("/{id}") public void deleteById(@PathVariable("id") Long id) { hotelService.removeById(id); rabbitTemplate.convertAndSend(MqConstants.HOTEL_EXCHANGE,MqConstants.HOTEL_DELETE_KEY,id); }
-
Recibir mensaje MQ
- Las cosas que hacer cuando hotel-demo recibe mensajes MQ incluyen:
- Nuevo mensaje: consulte la información del hotel de acuerdo con la identificación del hotel pasada y luego agregue un dato a la biblioteca de índice
- Eliminar mensaje: elimine una parte de los datos en la biblioteca de índice de acuerdo con la identificación del hotel pasada
service
Definir servicios nuevos y eliminados en
void deleteById(Long id); void insertById(Long id);
- En su clase de implementación, implementa el negocio
@Override public void deleteById(Long id) { try { // 1.准备Request DeleteRequest request = new DeleteRequest("hotel", id.toString()); // 2.发送请求 client.delete(request, RequestOptions.DEFAULT); } catch (IOException e) { throw new RuntimeException(e); } } @Override public void insertById(Long id) { try { // 0.根据id查询酒店数据 Hotel hotel = getById(id); // 转换为文档类型 HotelDoc hotelDoc = new HotelDoc(hotel); // 1.准备Request对象 IndexRequest request = new IndexRequest("hotel").id(hotel.getId().toString()); // 2.准备Json文档 request.source(JSON.toJSONString(hotelDoc), XContentType.JSON); // 3.发送请求 client.index(request, RequestOptions.DEFAULT); } catch (IOException e) { throw new RuntimeException(e); } }
- Las cosas que hacer cuando hotel-demo recibe mensajes MQ incluyen:
-
Escribe un oyente
import cn.itcast.hotel.constants.MqConstants; import cn.itcast.hotel.service.IHotelService; import org.springframework.amqp.core.ExchangeTypes; import org.springframework.amqp.rabbit.annotation.Exchange; import org.springframework.amqp.rabbit.annotation.Queue; import org.springframework.amqp.rabbit.annotation.QueueBinding; import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class HotelListener { @Autowired private IHotelService hotelService; /** * 监听酒店新增或修改的业务 * @param id 酒店id * queues = */ @RabbitListener(bindings = @QueueBinding(value = @Queue(name =MqConstants.HOTEL_INSERT_QUEUE), exchange = @Exchange(name = MqConstants.HOTEL_EXCHANGE,type = ExchangeTypes.TOPIC, autoDelete="false",durable = "true"), key = { MqConstants.HOTEL_INSERT_KEY} ) ) public void listenHotelInsertOrUpdate(Long id){ hotelService.insertById(id); } /** * 监听酒店删除的业务 * @param id 酒店id */ @RabbitListener(bindings = @QueueBinding(value = @Queue(name =MqConstants.HOTEL_DELETE_QUEUE), exchange = @Exchange(name = MqConstants.HOTEL_EXCHANGE,type = ExchangeTypes.TOPIC, autoDelete="false",durable = "true"), key = { MqConstants.HOTEL_DELETE_KEY} ) ) public void listenHotelDelete(Long id){ hotelService.deleteById(id); } }
3.7 Caso de prueba de sincronización de datos
- En rabbitMq, puede ver que el registro de la cola está completo
- Confirme el funcionamiento normal del proyecto a través del enlace del interruptor.
上海希尔顿酒店
precio revisado
- El ID del documento visto por
vue devtools
la herramienta de complemento上海希尔顿酒店
- Luego, edita su precio.
- Ver, el registro de mensajes de la cola
- consultar precios
3.8 Suplemento: Instalación del complemento vue Devtools
- ¡No recomiendo a todos, descargue el código fuente usted mismo, compílelo e instálelo manualmente! ! ! ¡Encontrarás muchos errores, y tus esfuerzos son ingratos! ! !
3.8.1 Método de instalación del navegador Edge
- En la tienda de extensiones de Edge, busque e instale
- La versión actual es la versión estable 6.5.0
- La versión actual es la versión estable 6.5.0
3.8.2 Cómo instalar el navegador Chrome
- Debido a que en China, Chrome no puede acceder a Chrome Store normalmente, por lo que debe usar un sitio web de complementos de terceros.La dirección de descarga de Vue Devtools del sitio web minimalista de complementos
- Descarga Vue Devtools y descomprímelo
- Active el modo desarrollador de Chrome: Configuración->Extensiones->Modo desarrollador
- Arrastre los archivos en la carpeta descomprimida
.crx
a la página del programa de extensión del navegador Chrome y haga clic en Agregar extensión.
3.9 Explicación de la herramienta vue devtools
- Pruebas posteriores a la instalación
- Esta herramienta, solo cuando la página frontal de vue se ejecuta localmente, la consola mostrará el complemento y no aparecerá en otras páginas web.
- Entonces: la forma correcta de verificar si la instalación fue exitosa es: inicie el proyecto local de vue, abra la consola para ver las herramientas de desarrollo de vue
- El valor en el archivo de configuración predeterminado del complemento
persistent
es:true
, por lo que no se requiere ninguna modificación.
Cuatro clústeres de búsqueda elástica
- La búsqueda elástica independiente para el almacenamiento de datos inevitablemente enfrentará dos problemas: el almacenamiento masivo de datos y el punto único de falla.
- Problema de almacenamiento masivo de datos: divida lógicamente la biblioteca de índices en N fragmentos (shards) y almacénelos en varios nodos
- Problema de punto único de falla: copia de seguridad de datos fragmentados en diferentes nodos (réplica)
4.1 Conceptos relacionados con el clúster ES
- Clúster (clúster): Un grupo de nodos con un nombre de clúster común.
- Nodo (nodo) : una instancia de Elasticearch en el clúster
- Fragmento : los índices se pueden dividir en diferentes partes para el almacenamiento, llamados fragmentos. En un entorno de clúster, diferentes fragmentos de un índice se pueden dividir en diferentes nodos
- Resuelva el problema: la cantidad de datos es demasiado grande y la capacidad de almacenamiento de un solo punto es limitada.
- Fragmento primario (Primary shard): relativo a la definición de fragmentos de réplica.
- Fragmento de réplica (fragmento de réplica) Cada fragmento principal puede tener una o más copias, y los datos son los mismos que los del fragmento principal.
- Para encontrar un equilibrio entre alta disponibilidad y costo, podemos hacer esto:
- Primero fragmente los datos y guárdelos en diferentes nodos
- Luego haga una copia de seguridad de cada fragmento y colóquelo en el otro nodo para completar la copia de seguridad mutua
- Ahora, cada fragmento tiene 1 copia de seguridad, almacenada en 3 nodos:
- node0: contiene fragmentos 0 y 1
- node1: contiene fragmentos 0 y 2
- nodo2: fragmentos guardados 1 y 2
4.2 Crear un clúster ES
- Usamos contenedores docker para ejecutar varias instancias de es en una sola máquina para simular clústeres de es. Sin embargo, en el entorno de producción, se recomienda que solo implemente una instancia de es en cada nodo de servicio.
4.3.1 Crear clúster es
- Primero escriba un archivo docker-compose.yml con el siguiente contenido:
version: '2.2' services: es01: image: elasticsearch:7.12.1 container_name: es01 environment: - node.name=es01 - cluster.name=es-docker-cluster - discovery.seed_hosts=es02,es03 - cluster.initial_master_nodes=es01,es02,es03 - "ES_JAVA_OPTS=-Xms512m -Xmx512m" volumes: - data01:/usr/share/elasticsearch/data ports: - 9200:9200 networks: - elastic es02: image: elasticsearch:7.12.1 container_name: es02 environment: - node.name=es02 - cluster.name=es-docker-cluster - discovery.seed_hosts=es01,es03 - cluster.initial_master_nodes=es01,es02,es03 - "ES_JAVA_OPTS=-Xms512m -Xmx512m" volumes: - data02:/usr/share/elasticsearch/data ports: - 9201:9200 networks: - elastic es03: image: elasticsearch:7.12.1 container_name: es03 environment: - node.name=es03 - cluster.name=es-docker-cluster - discovery.seed_hosts=es01,es02 - cluster.initial_master_nodes=es01,es02,es03 - "ES_JAVA_OPTS=-Xms512m -Xmx512m" volumes: - data03:/usr/share/elasticsearch/data networks: - elastic ports: - 9202:9200 volumes: data01: driver: local data02: driver: local data03: driver: local networks: elastic: driver: bridge
- la operación es necesita modificar algunos permisos del sistema linux, modificar
/etc/sysctl.conf
archivosvi /etc/sysctl.conf
- Luego ejecute el comando para que la configuración surta efecto:
sysctl -p
- Inicie el clúster a través de docker-compose
docker-compose up -d
[root@kongyue tmp]# docker-compose up -d Starting es01 ... done Creating es03 ... done Creating es02 ... done
4.4 Supervisión del estado del clúster
4.4.1 Win instalación cerebro [no recomendado]
-
Kibana puede monitorear clústeres de es, pero la nueva versión necesita confiar en la función x-pack de es, y la configuración es más complicada.
-
Se recomienda usar cerebro para monitorear el estado del clúster es. El directorio descomprimido del sitio web oficial es el siguiente:
-
Introduzca el directorio bin correspondiente:
-
Haga doble clic en el archivo cerebro.bat para iniciar el servicio.
4.4.2 Problema de retroceso [sin resolver]
Oops, cannot start the server.
com.google.common.util.concurrent.UncheckedExecutionException: java.lang.IllegalStateException: Unable to load cache item
at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2051)
at com.google.common.cache.LocalCache.get(LocalCache.java:3951)
at com.google.common.cache.LocalCache.getOrLoad(LocalCache.java:3974)
at com.google.common.cache.LocalCache$LocalLoadingCache.get(LocalCache.java:4958)
at com.google.common.cache.LocalCache$LocalLoadingCache.getUnchecked(LocalCache.java:4964)
at com.google.inject.internal.FailableCache.get(FailableCache.java:54)
at com.google.inject.internal.ConstructorInjectorStore.get(ConstructorInjectorStore.java:49)
at com.google.inject.internal.ConstructorBindingImpl.initialize(ConstructorBindingImpl.java:155)
at com.google.inject.internal.InjectorImpl.initializeBinding(InjectorImpl.java:592)
at com.google.inject.internal.AbstractBindingProcessor$Processor.initializeBinding(AbstractBindingProcessor.java:173)
at com.google.inject.internal.AbstractBindingProcessor$Processor.lambda$scheduleInitialization$0(AbstractBindingProcessor.java:160)
at com.google.inject.internal.ProcessedBindingData.initializeBindings(ProcessedBindingData.java:49)
at com.google.inject.internal.InternalInjectorCreator.initializeStatically(InternalInjectorCreator.java:124)
at com.google.inject.internal.InternalInjectorCreator.build(InternalInjectorCreator.java:108)
at com.google.inject.Guice.createInjector(Guice.java:87)
at com.google.inject.Guice.createInjector(Guice.java:78)
at play.api.inject.guice.GuiceBuilder.injector(GuiceInjectorBuilder.scala:200)
at play.api.inject.guice.GuiceApplicationBuilder.build(GuiceApplicationBuilder.scala:155)
at play.api.inject.guice.GuiceApplicationLoader.load(GuiceApplicationLoader.scala:21)
at play.core.server.ProdServerStart$.start(ProdServerStart.scala:54)
at play.core.server.ProdServerStart$.main(ProdServerStart.scala:30)
at play.core.server.ProdServerStart.main(ProdServerStart.scala)
Caused by: java.lang.IllegalStateException: Unable to load cache item
at com.google.inject.internal.cglib.core.internal.$LoadingCache.createEntry(LoadingCache.java:79)
at com.google.inject.internal.cglib.core.internal.$LoadingCache.get(LoadingCache.java:34)
at com.google.inject.internal.cglib.core.$AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:119)
at com.google.inject.internal.cglib.core.$AbstractClassGenerator.create(AbstractClassGenerator.java:294)
at com.google.inject.internal.cglib.reflect.$FastClass$Generator.create(FastClass.java:65)
at com.google.inject.internal.BytecodeGen.newFastClassForMember(BytecodeGen.java:258)
at com.google.inject.internal.BytecodeGen.newFastClassForMember(BytecodeGen.java:207)
at com.google.inject.internal.DefaultConstructionProxyFactory.create(DefaultConstructionProxyFactory.java:49)
at com.google.inject.internal.ProxyFactory.create(ProxyFactory.java:156)
at com.google.inject.internal.ConstructorInjectorStore.createConstructor(ConstructorInjectorStore.java:94)
at com.google.inject.internal.ConstructorInjectorStore.access$000(ConstructorInjectorStore.java:30)
at com.google.inject.internal.ConstructorInjectorStore$1.create(ConstructorInjectorStore.java:38)
at com.google.inject.internal.ConstructorInjectorStore$1.create(ConstructorInjectorStore.java:34)
at com.google.inject.internal.FailableCache$1.load(FailableCache.java:43)
at com.google.common.cache.LocalCache$LoadingValueReference.loadFuture(LocalCache.java:3529)
at com.google.common.cache.LocalCache$Segment.loadSync(LocalCache.java:2278)
at com.google.common.cache.LocalCache$Segment.lockedGetOrLoad(LocalCache.java:2155)
at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2045)
... 21 more
Caused by: java.lang.ExceptionInInitializerError
at com.google.inject.internal.cglib.core.$DuplicatesPredicate.evaluate(DuplicatesPredicate.java:104)
at com.google.inject.internal.cglib.core.$CollectionUtils.filter(CollectionUtils.java:52)
at com.google.inject.internal.cglib.reflect.$FastClassEmitter.<init>(FastClassEmitter.java:69)
at com.google.inject.internal.cglib.reflect.$FastClass$Generator.generateClass(FastClass.java:77)
at com.google.inject.internal.cglib.core.$DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
at com.google.inject.internal.cglib.core.$AbstractClassGenerator.generate(AbstractClassGenerator.java:332)
at com.google.inject.internal.cglib.core.$AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:96)
at com.google.inject.internal.cglib.core.$AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:94)
at com.google.inject.internal.cglib.core.internal.$LoadingCache$2.call(LoadingCache.java:54)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
at com.google.inject.internal.cglib.core.internal.$LoadingCache.createEntry(LoadingCache.java:61)
... 38 more
Caused by: com.google.inject.internal.cglib.core.$CodeGenerationException: java.lang.reflect.InaccessibleObjectException-->Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module @6a988392
at com.google.inject.internal.cglib.core.$ReflectUtils.defineClass(ReflectUtils.java:464)
at com.google.inject.internal.cglib.core.$AbstractClassGenerator.generate(AbstractClassGenerator.java:339)
at com.google.inject.internal.cglib.core.$AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:96)
at com.google.inject.internal.cglib.core.$AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:94)
at com.google.inject.internal.cglib.core.internal.$LoadingCache$2.call(LoadingCache.java:54)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
at com.google.inject.internal.cglib.core.internal.$LoadingCache.createEntry(LoadingCache.java:61)
at com.google.inject.internal.cglib.core.internal.$LoadingCache.get(LoadingCache.java:34)
at com.google.inject.internal.cglib.core.$AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:119)
at com.google.inject.internal.cglib.core.$AbstractClassGenerator.create(AbstractClassGenerator.java:294)
at com.google.inject.internal.cglib.core.$KeyFactory$Generator.create(KeyFactory.java:221)
at com.google.inject.internal.cglib.core.$KeyFactory.create(KeyFactory.java:174)
at com.google.inject.internal.cglib.core.$KeyFactory.create(KeyFactory.java:157)
at com.google.inject.internal.cglib.core.$KeyFactory.create(KeyFactory.java:149)
at com.google.inject.internal.cglib.core.$KeyFactory.create(KeyFactory.java:145)
at com.google.inject.internal.cglib.core.$MethodWrapper.<clinit>(MethodWrapper.java:23)
... 49 more
Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module @6a988392
at java.base/java.lang.reflect.AccessibleObject.throwInaccessibleObjectException(AccessibleObject.java:387)
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:363)
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:311)
at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:201)
at java.base/java.lang.reflect.Method.setAccessible(Method.java:195)
at com.google.inject.internal.cglib.core.$ReflectUtils$1.run(ReflectUtils.java:61)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:569)
at com.google.inject.internal.cglib.core.$ReflectUtils.<clinit>(ReflectUtils.java:52)
at com.google.inject.internal.cglib.reflect.$FastClassEmitter.<init>(FastClassEmitter.java:67)
... 46 more
- Debido a que la versión jdk es demasiado alta, no es compatible con cerebo. ¡Parece que no hay solución en este momento! ! !
- ¡Por supuesto, el nivel del autor es limitado! Si hay una solución, por favor hágamelo saber, muchas gracias
4.4.3 instalar cerebo en linux
- descargar cerebro
- Sugerencia: instale el complemento del acelerador github en el navegador [omita si tiene una escalera]
- Luego suba el paquete comprimido a Linux para su instalación
rpm -ivh cerebro-0.9.4-1.noarch.rpm
- Modificar el archivo de configuración
vim /usr/share/cerebro/conf/application.conf
- Comprobar y cerrar el estado de inicio de cerebro: [no recomendado]
- No se puede acceder a este método de arranque desde dispositivos externos
# 停止 systemctl stop cerebro # 开启 systemctl start cerebro # 查看状态 systemctl status cerebro
- Comando de inicio:
- Para facilitar la resolución de problemas, puede usar directamente el comando para iniciar cerebro
/usr/share/cerebro/bin/cerebro
- Iniciado por defecto:
[info] play.api.Play - Application started (Prod) (no global state) [info] p.c.s.AkkaHttpServer - Listening for HTTP on /0:0:0:0:0:0:0:0:9000
- visita
ip:9000
:
- Ingrese la dirección y el puerto de cualquier nodo de elasticsearch, haga clic en conectar
- Una barra verde significa que el clúster es verde (saludable)
4.4.5 Crear una biblioteca de índices
4.4.6 Uso de DevTools de Kibana para crear una biblioteca de índices [operación no práctica]
- Ingrese el comando en DevTools:
PUT /itcast { "settings": { "number_of_shards": 3, // 分片数量 "number_of_replicas": 1 // 副本数量 }, "mappings": { "properties": { // mapping映射定义 ... } } }
4.4.7 Uso de cerebro para crear una biblioteca de índices [operación práctica]
- También puede crear una biblioteca de índices con cerebro:
-
Complete la información de la biblioteca del índice:
-
Haga clic en el botón Crear en la esquina inferior derecha:
-
Haga clic en el botón Crear en la esquina inferior derecha:
4.4.8 Ver efecto de fragmentación
- Regrese a la página de inicio y podrá ver el efecto de fragmentación de la biblioteca de índices:
4.9 Problema de cerebro dividido en racimo
4.9.1 División de responsabilidades del clúster
- Los nodos de clúster en elasticsearch tienen diferentes responsabilidades:
- El clúster debe separar las responsabilidades del clúster:
- nodo maestro: altos requisitos de CPU, pero requisitos de memoria
- nodo de datos: altos requisitos de CPU y memoria
- Nodo de coordinación: altos requisitos de ancho de banda de red y CPU
- La separación de tareas puede asignar hardware diferente para la implementación de acuerdo con las necesidades de los diferentes nodos. Y evitar la interferencia mutua entre servicios.
- Cada rol de nodo en elasticsearch tiene sus propias responsabilidades diferentes, por lo que se recomienda que cada nodo tenga un rol independiente durante la implementación del clúster.
4.9.2 Problema del cerebro dividido
-
De forma predeterminada, cada nodo es un nodo principal elegible, por lo que una vez que el nodo principal deja de funcionar, otros nodos candidatos elegirán uno para convertirse en el nodo principal. Puede ocurrir un problema de cerebro dividido cuando falla la red entre el nodo maestro y otros nodos.
-
Después de que se elige el nodo 3, el clúster continúa brindando servicios externos. El nodo 2 y el nodo 3 forman un clúster por sí mismos, y el nodo 1 forma un clúster por sí mismos. Los datos de los dos clústeres no están sincronizados, lo que resulta en discrepancias de datos y situaciones de cerebro dividido.
-
Para evitar el cerebro dividido, es necesario exigir que los votos excedan (número de nodos elegibles + 1)/2 para ser elegido maestro, por lo que el número de nodos elegibles es preferiblemente un número impar.
-
El elemento de configuración correspondiente es discovery.zen.minimum_master_nodes, que se ha convertido en la configuración predeterminada después de es7.0, por lo que el problema del cerebro dividido generalmente no ocurre.
4.9.3 Resumen
-
El rol del nodo maestro elegible:
- Participar en la elección del grupo.
- El nodo maestro puede administrar el estado del clúster, administrar información de fragmentación y procesar solicitudes para crear y eliminar bibliotecas de índices.
-
El papel del nodo de datos:
- CRUD de datos
-
El papel del nodo coordinador:
- Enrutar solicitudes a otros nodos
- Combine los resultados de la consulta y devuélvalos al usuario
4.10 Almacenamiento distribuido en clúster
- Cuando se agregan nuevos documentos, deben guardarse en diferentes fragmentos para garantizar el equilibrio de los datos, entonces, ¿cómo determina el nodo coordinador en qué fragmento se deben almacenar los datos?
4.10.1 Prueba de almacenamiento de fragmentos
- La herramienta utilizada para la prueba
insomnia
, Insomnia, como cartero, es una aplicación de escritorio de prueba de interfaz multiplataforma gratuita. - Sitio web oficial de Insomnia , si desea descargar, se recomienda descargar desde otros sitios web, el sitio web oficial es demasiado lento
- Aquí el autor proporciona la última versión de "Insomnia.Core-2023.1.0.exe"
- Puede ver en la prueba que los tres datos están en fragmentos diferentes:
4.10.2 Principio de almacenamiento de fragmentos
- Elasticsearch utilizará el algoritmo hash para calcular en qué fragmento se debe almacenar el documento:
- ilustrar:
- _routing por defecto es el id del documento
- El algoritmo está relacionado con la cantidad de fragmentos, por lo que una vez que se crea la biblioteca de índice, la cantidad de fragmentos no se puede modificar.
- El proceso de agregar un nuevo documento es el siguiente
- Interpretación:
- 1) Agregar un documento con id=1
- 2) Realice una operación hash en la identificación, si el resultado es 2, debe almacenarse en shard-2
- 3) El fragmento principal del fragmento 2 está en el nodo 3 y los datos se enrutan al nodo 3.
- 4) Guardar el documento
- 5) Sincronizar con la réplica 2 del fragmento 2, en el nodo node2
- 6) Devolver el resultado al nodo del nodo de coordinación
4.10.3 Consulta distribuida de clúster
- La consulta de elasticsearch se divide en dos etapas:
- fase de dispersión: en la fase de dispersión, el nodo coordinador distribuirá la solicitud a cada fragmento
- fase de recopilación: la fase de recopilación, el nodo de coordinación resume los resultados de búsqueda del nodo de datos, lo procesa como el conjunto de resultados final y lo devuelve al usuario
4.10.4 Conmutación por error del clúster
- Conmutación por error: el nodo maestro del clúster monitoreará el estado de los nodos en el clúster.Si se encuentra que un nodo está inactivo, migrará inmediatamente los datos fragmentados del nodo inactivo a otros nodos para garantizar la seguridad de los datos.
- Por ejemplo, en la figura se muestra una estructura de clúster: el nodo 1 es el nodo maestro y los otros dos nodos son nodos esclavos.
- nodo1 ha fallado
- Lo primero después del tiempo de inactividad es volver a elegir el maestro, por ejemplo, seleccione el nodo2
- Después de que el nodo 2 se convierta en el nodo maestro, verificará el estado de monitoreo del clúster y encontrará que: el fragmento 1 y el fragmento 0 no tienen nodos de réplica. Por lo tanto, los datos del nodo 1 deben migrarse al nodo 2 y al nodo 3.
- Demostración de animación: