首页 > 其他分享 >公有云--web集群部署实战

公有云--web集群部署实战

时间:2024-06-18 09:01:18浏览次数:30  
标签:web 0001 -- 192.168 公有 etc root logstash es

公有云--web集群部署实战

今日目标:

-华为云网站部署实战

-华为云负载均衡ELB

-ELASTICSEARCH安装部署

Web集群架构图

Web集群规划:

-NFS共享存储

-web-0001、web-0002、web-0003、-ELB负载均衡

-跳板机(管理主机)

部署Web集群

1.购买云主机

主机名称 IP地址

nfs 192.168.1.10

web-0001 192.168.1.11

web-0002 192.168.1.12

web-0003 192.168.1.13

2.部署NFS服务

 # 拷贝网站页面到 NFS 云主机
 [root@ecs-proxy s4]# rsync -av public/website.tar.gz 192.168.1.10:/root/
 #----------------------------------------------------------------------#
 # 创建共享目录,并部署网站页面
 [root@nfs ~]# mkdir -p /var/webroot
 [root@nfs ~]# tar -zxf website.tar.gz -C /var/webroot/
 ​
 # 部署 NFS 服务
 [root@nfs ~]# dnf install -y nfs-utils
 [root@nfs ~]# vim /etc/exports
 /var/webroot    192.168.1.0/24(rw,no_root_squash)
 ​
 [root@nfs ~]# systemctl enable --now nfs-server.service

3.部署web服务(自动化部署web集群)

 [root@ecs-proxy ~]# mkdir website
 [root@ecs-proxy ~]# cd website
 [root@ecs-proxy website]# vim ansible.cfg
 [defaults]
 inventory         = hostlist
 host_key_checking = False
 [root@ecs-proxy website]# vim hostlist
 [web]
 192.168.1.[11:13]
 [root@ecs-proxy website]# vim web_install.yaml
 ---
 - name: web 集群安装
   hosts: web
   tasks:
   - name: 安装 apache 服务 
     dnf:
       name: httpd,php,nfs-utils
       state: latest
       update_cache: yes
   - name: 配置 httpd 服务 
     service:
       name: httpd
       state: started
       enabled: yes
   - name: 编辑 fstab 文件,添加 NFS 配置
     lineinfile:
       path: /etc/fstab
       regexp: '^192.168.1.10:/.*'
       line: '192.168.1.10:/var/webroot /var/www/html nfs defaults,_netdev,nolock 1 1'
       create: yes
   - name: 挂载 NFS
     shell:
       cmd: mount /var/www/html
 ​
 # 设置语言环境
 [root@ecs-proxy website]# locale
 [root@ecs-proxy website]# export LANG="en_US.UTF-8" LC_ALL="en_US.UTF-8"
 [root@ecs-proxy website]# echo 'export LANG="en_US.UTF-8"' >>/etc/profile.d/lang.sh
 # 执行 playbook 完成安装
 [root@ecs-proxy website]# ansible-playbook web_install.yaml

案例一:部署网站实战

-- 配置NFS服务并部署网页

-- 在跳板机上使用Playbook完成集群安装部署

什么是弹性负载均衡(ELB):是将访问流量根据转发策略分发到后端多台服务器的流量分发控制服务。弹性负载均衡可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。

负载均衡架构原理图

4.配置负载均衡(ELB)

(1)购买负载均衡ELB

(2)购买ELB

(3)配置监听器

(4)选择负载均衡算法

(5)添加服务主机

(6)验证ELB服务

 [root@ecs-proxy ~]# curl http://192.168.1.250/info.php
 <pre>
 Array
 (
     [REMOTE_ADDR] => 100.125.99.180
     [REQUEST_METHOD] => GET
     [HTTP_USER_AGENT] => curl/7.29.0
     [REQUEST_URI] => /info.php
 )
 php_host: web-0001
 1229

(7)弹性负载均衡---更多---绑定弹性公网IP

网站部署成功截图页面:

案例2:部署网站实战

ELK是什么

ELK是一套解决方案,有三个软件首字符缩写组成

-Elasticsearch:负责日志检索和存储

-logstash:负责日志的收集和分析、处理

-Kibana:负责日志的可视化,读出数据展示页面

Elasticsearch概述:一个基于Lucene的搜索服务器,它提供一个分布式多用户能力的全文搜索引擎,基于RESTful API的Web接口;一大优势是拥有集群协调子系统。集群协调子系统可以从只有几个节点的小集群无缝扩展到拥有数百个节点的大集群

主要特点:实时分析,分布式实时存储高可用,接口友好,是一种面向文档的数据库

Elasticsearch与关系数据库对比:

项目架构图

Elasticsearch 安装

添加软件包

 # 添加 ELK 软件包到自定义 Yum 仓库
 [root@ecs-proxy s4]# rsync -av elk/ /var/localrepo/elk/
 [root@ecs-proxy s4]# createrepo --update /var/localrepo

购买云主机

主机IP地址配置
es-0001192.168.1.21最低配置2核4G
es-0002192.168.1.22最低配置2核4G
es-0003192.168.1.23最低配置2核4G
es-0004192.168.1.24最低配置2核4G
es-0005192.168.1.25最低配置2核4G

集群安装

部署 es-0001
 [root@es-0001 ~]# vim /etc/hosts
 192.168.1.21    es-0001
 192.168.1.22    es-0002
 192.168.1.23    es-0003
 192.168.1.24    es-0004
 192.168.1.25    es-0005
 [root@es-0001 ~]# dnf install -y elasticsearch
 [root@es-0001 ~]# vim /etc/elasticsearch/elasticsearch.yml
 17:  cluster.name: my-es
 23:  node.name: es-0001
 56:  network.host: 0.0.0.0
 70:  discovery.seed_hosts: ["es-0001", "es-0002", "es-0003"]
 74:  cluster.initial_master_nodes: ["es-0001", "es-0002", "es-0003"]
 [root@es-0001 ~]# systemctl enable --now elasticsearch
 # 服务启动成功
 [root@es-0001 ~]# curl http://127.0.0.1:9200
 {
   "name" : "es-0001",
   "cluster_name" : "my-es",
   "cluster_uuid" : "_na_",
   "version" : {
     "number" : "7.17.8",
     "build_flavor" : "default",
     "build_type" : "rpm",
     "build_hash" : "120eabe1c8a0cb2ae87cffc109a5b65d213e9df1",
     "build_date" : "2022-12-02T17:33:09.727072865Z",
     "build_snapshot" : false,
     "lucene_version" : "8.11.1",
     "minimum_wire_compatibility_version" : "6.8.0",
     "minimum_index_compatibility_version" : "6.0.0-beta1"
   },
   "tagline" : "You Know, for Search"
 }
部署 es-0002
 # 验证集群状态失败
 [root@es-0002 ~]# curl http://es-0001:9200/_cat/nodes?pretty
 {
   "error" : {
     "root_cause" : [
       {
         "type" : "master_not_discovered_exception",
         "reason" : null
       }
     ],
     "type" : "master_not_discovered_exception",
     "reason" : null
   },
   "status" : 503
 }
 # 部署服务
 [root@es-0002 ~]# vim /etc/hosts
 192.168.1.21    es-0001
 192.168.1.22    es-0002
 192.168.1.23    es-0003
 192.168.1.24    es-0004
 192.168.1.25    es-0005
 [root@es-0002 ~]# dnf install -y elasticsearch
 [root@es-0002 ~]# vim /etc/elasticsearch/elasticsearch.yml
 17:  cluster.name: my-es
 23:  node.name: es-0002
 56:  network.host: 0.0.0.0
 70:  discovery.seed_hosts: ["es-0001", "es-0002", "es-0003"]
 74:  cluster.initial_master_nodes: ["es-0001", "es-0002", "es-0003"]
 [root@es-0002 ~]# systemctl enable --now elasticsearch
 # 验证集群状态
 [root@es-0002 ~]# curl http://es-0001:9200/_cat/nodes?pretty
 192.168.1.21 16 89  2 0.15 0.06 0.04 cdfhilmrstw * es-0001
 192.168.1.22  6 88 61 1.00 0.23 0.08 cdfhilmrstw - es-0002
集群扩容
  • 在所有 es 主机安装 Elasticsearch

 [root@ecs-proxy ~]# mkdir es
 [root@ecs-proxy ~]# cd es
 [root@ecs-proxy es]# vim ansible.cfg 
 [defaults]
 inventory         = hostlist
 host_key_checking = False
 [root@ecs-proxy es]# vim hostlist
 [es]
 192.168.1.[21:25]
 [root@ecs-proxy es]# rsync -av 192.168.1.21:/etc/elasticsearch/elasticsearch.yml elasticsearch.j2
 [root@ecs-proxy es]# vim elasticsearch.j2
 23:  node.name: {{ ansible_hostname }}
 [root@ecs-proxy es]# vim es_install.yaml 
 ---
 - name: Elasticsearch 集群安装
   hosts: es
   tasks:
   - name: 设置 /etc/hosts
     copy:
       dest: /etc/hosts
       owner: root
       group: root
       mode: '0644'
       content: |
         ::1     localhost localhost.localdomain localhost6 localhost6.localdomain6
         127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
         {% for i in groups.es %}
         {{ hostvars[i].ansible_eth0.ipv4.address }} {{ hostvars[i].ansible_hostname }}
         {% endfor %}
   - name: 安装 ES 服务
     dnf:
       name: elasticsearch
       state: latest
       update_cache: yes
   - name: 拷贝配置文件
     template:
       src: elasticsearch.j2
       dest: /etc/elasticsearch/elasticsearch.yml
       owner: root
       group: elasticsearch
       mode: '0660'
   - name: 配置 ES 服务 
     service:
       name: elasticsearch
       state: started
       enabled: yes
 ​
 [root@ecs-proxy es]# ansible-playbook es_install.yaml
 [root@ecs-proxy es]# curl http://192.168.1.21:9200/_cat/nodes?pretty
 192.168.1.21 32 88 0 0.04 0.01 0.00 cdfhilmrstw * es-0001
 192.168.1.22 16 87 0 0.13 0.04 0.01 cdfhilmrstw - es-0002
 192.168.1.23  6 86 1 0.64 0.21 0.07 cdfhilmrstw - es-0003
 192.168.1.24 18 86 0 0.44 0.13 0.05 cdfhilmrstw - es-0004
 192.168.1.25  6 86 1 0.67 0.21 0.07 cdfhilmrstw - es-0005

插件管理

Head插件图例

部署插件页面
 # 拷贝插件 public/head.tar.gz 到 es-0001 主机
 [root@ecs-proxy s4]# rsync -av public/head.tar.gz 192.168.1.21:./
 #-------------------------------------------------
 # 在 es-0001 上安装 web 服务,并部署插件
 [root@es-0001 ~]# dnf install -y nginx
 [root@es-0001 ~]# systemctl enable --now nginx
 [root@es-0001 ~]# tar zxf head.tar.gz -C /usr/share/nginx/html/

  • 通过 ELB 的 8080 端口,发布服务到互联网

认证和代理
 [root@es-0001 ~]# vim /etc/nginx/default.d/esproxy.conf 
 location ~* ^/es/(.*)$ {
     proxy_pass http://127.0.0.1:9200/$1;
     auth_basic "Elasticsearch admin";
     auth_basic_user_file /etc/nginx/auth-user; 
 }
 [root@es-0001 ~]# dnf install -y httpd-tools
 [root@es-0001 ~]# htpasswd -cm /etc/nginx/auth-user admin
 New password: 
 Re-type new password: 
 Adding password for user admin
 [root@es-0001 ~]# systemctl reload nginx
  • 通过 head 插件管理 elasticsearch 集群

API原语管理

Elasticsearch提供http协议的管理方式(API)

http请求由三部分组成:请求行,消息报头,请求正文

http请求方法:get,post,head

Elasticsearch使用的请求方法:增(put)删(delete)改(post)查(get)

1、linux中curl是一个利用URL规则在命令行下工作的文件传输工具,是一款很强大的http命令行工具。支持多种请求模式,自定义请求头等强大功能。

格式:curl -X "请求方法" -H“请求头” http://请求地址

2、_cat关键字用来查询集群状态、节点信息等

-显示详细信息(?v)

-显示帮助信息(?help)

-json使用易读的调试格式显示(?pretty)

集群状态查询
 # 查询支持的关键字
 [root@es-0001 ~]# curl -XGET http://127.0.0.1:9200/_cat/
 # 查具体的信息
 [root@es-0001 ~]# curl -XGET http://127.0.0.1:9200/_cat/master
 # 显示详细信息 ?v
 [root@es-0001 ~]# curl -XGET http://127.0.0.1:9200/_cat/master?v
 # 显示帮助信息 ?help
 [root@es-0001 ~]# curl -XGET http://127.0.0.1:9200/_cat/master?help
 # 显示易读格式 ?pretty
 [root@es-0001 ~]# curl -XGET http://127.0.0.1:9200/_cat/master?pretty
创建索引
  • 指定索引的名称,指定分片数量,指定副本数量

 # 设置默认分片副本数量
 [root@es-0001 ~]# curl -XPUT -H 'Content-Type: application/json' \
     http://127.0.0.1:9200/_template/index_defaults -d '{
       "template": "*",
       "settings": {
         "number_of_shards": 5,
         "number_of_replicas": 1
       }
     }'
 {"acknowledged":true}
 ​
 # 创建 tedu 索引
 [root@es-0001 ~]# curl -XPUT http://127.0.0.1:9200/tedu?pretty
 {
   "acknowledged" : true,
   "shards_acknowledged" : true,
   "index" : "tedu"
 }
增加数据
 [root@es-0001 ~]# curl -XPUT -H "Content-Type: application/json" \
     http://127.0.0.1:9200/tedu/teacher/1?pretty -d '{
         "职业": "诗人","名字": "李白","称号": "诗仙","年代": "唐"
     }' 
查询数据
 [root@es-0001 ~]# curl -XGET http://127.0.0.1:9200/tedu/teacher/_search?pretty
 [root@es-0001 ~]# curl -XGET http://127.0.0.1:9200/tedu/teacher/1?pretty
修改数据
 [root@es-0001 ~]# curl -XPOST -H "Content-Type: application/json" \
     http://127.0.0.1:9200/tedu/teacher/1/_update -d '{ 
       "doc": {"年代":"公元701"}
     }'
删除数据
 # 删除一条
 [root@es-0001 ~]# curl -XDELETE http://127.0.0.1:9200/tedu/teacher/1
 # 删除索引
 [root@es-0001 ~]# curl -XDELETE http://127.0.0.1:9200/tedu

logstash概述

logstash是一个数据采集、加工处理以及传输的工具

结构原理:

-input 负责收集数据

-filter 负责处理数据

-output 负责输出数据

logstash支持的数据类型:布尔、字节、字符串、数值、数组、键值对

logstash支持判断方法:==、!=、>、>=、<、<=、=~、!~

logstash支持的逻辑判断:in、notin、and、or、nand、xor

logstash安装在/usr/share/logstash目录下,配置文件/etc/logstash

Logstash 配置管理

安装 logstash

主机名称IP地址配置
logstash192.168.1.27最低配置4核8G

安装部署

 [root@logstash ~]# vim /etc/hosts
 192.168.1.21    es-0001
 192.168.1.22    es-0002
 192.168.1.23    es-0003
 192.168.1.24    es-0004
 192.168.1.25    es-0005
 192.168.1.27    logstash
 [root@logstash ~]# dnf install -y logstash
 [root@logstash ~]# ln -s /etc/logstash /usr/share/logstash/config

最简单的配置

 [root@logstash ~]# vim /etc/logstash/conf.d/my.conf
 input { 
   stdin {}
 }
 filter{ 
 }
 output{ 
   stdout{}
 }
 [root@logstash ~]# /usr/share/logstash/bin/logstash

插件管理命令 /usr/share/logstash/bin/logstash-plugin

-查看插件 list

-安装插件 install

-删除插件 uninstall

插件与调试格式

  • json格式字符串: {"a":"1", "b":"2", "c":"3"}

 [root@logstash ~]# vim /etc/logstash/conf.d/my.conf
 input { 
   stdin { codec => "json" }
 }
 ​
 filter{ 
 ​
 }
 ​
 output{ 
   stdout{ codec => "rubydebug" }
 }
 [root@logstash ~]# /usr/share/logstash/bin/logstash

input 模块

file 插件

file插件基本配置

 [root@logstash ~]# touch /tmp/{a,b}.log
 [root@logstash ~]# echo 'string 01' >>/tmp/a.log
 [root@logstash ~]# echo 'string 02' >>/tmp/a.log
 [root@logstash ~]# echo 'string 03' >>/tmp/a.log
 [root@logstash ~]# vim /etc/logstash/conf.d/my.conf
 input {
   file {
     path => ["/tmp/a.log", "/tmp/b.log"]
   }
 }
 # filter { 不做任何修改 }
 # output { 不做任何修改 }
 ​
 # 启动程序,等待数据输出
 [root@logstash ~]# /usr/share/logstash/bin/logstash
 ​
 #---------------------------------------------------
 # 在另一个终端模拟写入日志
 [root@logstash ~]# echo 'string 04' >>/tmp/b.log
 [root@logstash ~]# echo 'string 05' >>/tmp/a.log

file插件高级配置

 # 删除默认书签文件
 [root@logstash ~]# rm -rf /var/lib/logstash/plugins/inputs/file/.sincedb_*
 [root@logstash ~]# cat /tmp/{a.log,b.log} >/tmp/c.log
 [root@logstash ~]# vim /etc/logstash/conf.d/my.conf
 input {
   file {
     path => ["/tmp/c.log"]#要监控的文件路径
     start_position => "beginning"#第一次读取文件位置
     sincedb_path => "/var/lib/logstash/sincedb"#记录读取文件位置
   }
 }
 # filter { 不做任何修改 }
 # output { 不做任何修改 }
 ​
 [root@logstash ~]# /usr/share/logstash/bin/logstash

filter 模块

grok 插件

正则表达式分组匹配格式: (?<名字>正则表达式) 正则表达式宏调用格式: %{宏名称:名字} 宏文件路径 : /usr/share/logstash/vendor/bundle/jruby/2.5.0/gems/logstash-patterns-core-4.3.4/patterns

准备测试数据

 # 从 web 服务器查找一条日志写入到日志文件
 [root@logstash ~]# echo '60.26.217.109 - admin [13/Jan/2023:14:31:52 +0800] "GET /es/ HTTP/1.1" 200 148209 "http://127.70.79.1/es/" "curl/7.61.1"' >/tmp/c.log
 ​
 # 调试技巧:设置路径为 /dev/null 可以多次反复测试
 [root@logstash ~]# vim /etc/logstash/conf.d/my.conf
 input {
   file {
     path => ["/tmp/c.log"]
     start_position => "beginning"
     sincedb_path => "/dev/null"
   }
 }
 # filter { 不做任何修改 }
 # output { 不做任何修改 }
 ​
 [root@logstash ~]# /usr/share/logstash/bin/logstash

filter插件配置管理

正则表达式分组匹配格式,调用格式:(?<名字>正则表达式)

调用宏表达式的格式,调用格式:%{宏名称:名字}

grok自带的宏定义路径在:/usr/share/logstash/vendor/bundle/jruby/2.5.0/gems/logstash-patterns-core-4.3.4/patterns

匹配IP地址测试

 [root@logstash ~]# vim /etc/logstash/conf.d/my.conf
 # input { 不做任何修改 }
 ​
 filter {
   grok {
     match => { "message" => "(?<userIP>((25[0-5]|2[0-4]\d|1?\d?\d)\.){3}(25[0-5]|2[0-4]\d|1?\d?\d))" }
   }
   grok {
     match => { "message" => "%{IP:clientIP}" }
   }
 }
 ​
 # output { 不做任何修改 }
 ​
 [root@logstash ~]# /usr/share/logstash/bin/logstash

使用宏格式化日志

 [root@logstash ~]# vim /etc/logstash/conf.d/my.conf
 # input { 不做任何修改 }
 ​
 filter{ 
   grok {
     match => { "message" => "%{HTTPD_COMBINEDLOG}" }
     remove_field => ["message"]
   }
 }
 ​
 # output { 不做任何修改 }
 ​
 [root@logstash ~]# /usr/share/logstash/bin/logstash

output 模块

elasticsearch 插件
 [root@logstash ~]# vim /etc/logstash/conf.d/my.conf
 # input { 不做任何修改 }
 # filter { 不做任何修改 }
 ​
 output{ 
   stdout{ codec => "rubydebug" }
   elasticsearch {
     hosts => ["es-0002:9200","es-0003:9200"]
     index => "weblog-%{+YYYY.MM.dd}"
   }
 }
 ​
 [root@logstash ~]# /usr/share/logstash/bin/logstash
  • 访问页面,查看 Head 插件,验证数据写入 Elasticsearch 成功

标签:web,0001,--,192.168,公有,etc,root,logstash,es
From: https://blog.csdn.net/QueueTT/article/details/139752387

相关文章

  • JSON响应中提取特定的信息——6.14山大软院项目实训2
    在收到的JSON响应中提取特定的信息(如response字段中的文本)并进行输出,需要进行JSON解析。在Unity中,可以使用JsonUtility进行简单的解析,但由于JsonUtility对嵌套对象的支持有限,通常推荐使用第三方库如Newtonsoft.Json来处理复杂的JSON结构。首先,确保Unity项目中已经包含了Newton......
  • 大型语言模型的“不知道”:一种新的不确定性敏感训练方法
    大型语言模型(LLMs)在各种任务中展现出惊人的能力,但仍然面临着诸如幻觉等挑战。幻觉是指LLMs生成与事实不符或毫无意义的响应。造成幻觉的一个潜在原因是缺乏相关知识或上下文。因此,一个很有前景的解决方案是指示LLMs在问题超出其知识范围或提供的上下文时,回答“我不知道”。......
  • Unity中使用UI组件实现场景切换——6.18山大软院项目实训
    设置场景切换在Unity项目中,首先需要准备几个场景,并在项目的“BuildSettings”中添加这些场景,以确保SceneManager可以加载它们。本例中,我们假设已有几个场景编号依次为1到5。脚本概述我们创建了一个SwitchScene类,这个类包含了几个公共方法,允许通过不同方式切换场景:使用下拉......
  • 简单处理字符串——6.14山大软院项目实训1
    对于直接输出服务器返回的json到Debug,发现他还包含json的结构,但是不想调试json的返回结构,可以使用简单地处理字符串的方法,而不引入额外的库或复杂的JSON解析,但是这个解决方式是暂时的是投机取巧的,正确的做法我会在下一条博客里面写出来。可以考虑使用字符串操作方法直接从接收......
  • django学习入门系列之第三点《快速了解 CSS》
    文章目录CSS快速了解CSS应用方式在标签上在head标签中写到文件中问题:用Flask框架开发不方便往期回顾CSSCSS专门用来"美化"标签基础CSS,写简单的界面&能看懂&会改就行模块,调整和修改快速了解style这种就叫css样式<imgsrc"..."style="height:100px"/><d......
  • 从零开始学数据结构系列之第三章《先序线索二叉树查找及总代码》
    文章目录查找下一个节点总代码往期回顾查找下一个节点​  我们为啥没有像中序二叉树一样有第一个节点,因为我们一开始最大就是我们的根节点,所以无需遍历去寻找我们的第一个节点,我们的T就是我们的第一个节点​我们回过来看中序线索二叉树的节点应该是怎么写的/*......
  • 最简单直接的开动热气球方法——6.17山大软院项目实训
    我们思考一下开动热气球的逻辑,通过控制器(手柄)的移动来控制热气球的前进后退以及转向,这不是和人物的基础移动很像吗,那我们可以想到,只要对于热气的y轴移动没有什么要求,那么我们就可以使用一个热气球模型将他直接挂在maincamera的下面,然后通过手柄控制人物移动的方式控制热气球的......
  • ROS实验课(三)
    writeinadvance此次实验课给我的生活来了沉重的一击,不单单是因为没有做出来,还因为我卡在了插件缺失而无法解决。之前对待实验课,能在操作流程之外有暇思考具体的实现,此次只能记录简单的操作流程部分。老规矩,基于同样的《ROS机器人开发技术基础》教材。以下是实验内容,要......
  • 【C/C++】实现高性能日志轮转功能,已实测
    基本实现在C语言中实现日志文件轮转功能,你需要手动编写代码来处理文件的重命名、压缩和删除。下面是一个简单的C语言程序示例,它演示了如何实现基本的日志文件轮转功能。这个程序会检查日志文件的大小,如果超过预设的大小限制,则将当前日志文件重命名,并创建一个新的日志文件。......
  • 6.16 10
    importtkinterastkfromtkinterimportttk,messageboxfromPILimportImage,ImageTkimportmysql.connectorimportdb_connectiondefupdate_mistake(conn,mistake_id,question,error_info,answer_analysis,thoughts,source,reason,difficulty,......