SpringCloud 使用与Nacos

目录

1. 什么是Spring Cloud?

    1.1 业务场景介绍 

    1.2 服务分析 

    1.3 流程调用

    1.4 Spring Cloud 

2. Spring Cloud 核心组件 

    2.1 Eureka

    2.2 Feign

    2.3 Ribbon 

    2.4 Hystrix 

    2.5 Zuul

3.springCloud关系 

   3.1 Spring Cloud Netflix 第一代 

   3.2 Spring Cloud Alibaba 第二代

3.2.1 「阿里开源组件」

3.2.2 「阿里商业化组件」

4. SpringCloud常用组件

5. 版本关系

    Spring Boot

    Spring Cloud

    Spring Cloud Dependencies

    Spring Cloud中文学习指南

    Spring Cloud Alibaba

6. 版本管理规范

7. Nacos 搭建

    Nacos官网

   7.1 配置Nacos数据库源 

   7.2 启动Nacos 并访问Nacos管理页面

8. 消费者和生成者编写

    8.1 新建一个maven项目为父工程  

    8.1.1 修改父工程pom文件并添加以下代码

8.2 新建一个springboot项目为子项目 (生产者构建 Provider)

    8.2.1 修改并添加子项目pom文件  

    8.2.2 修改并添加子项目application.yml文件

    8.2.3 修改并添加子项目启动类

8.3 新建一个springboot项目为子项目  (消费者构建 Consumer)

     8.3.1 修改并添加子项目pom文件

     8.3.2 修改并添加子项目application.yml文件

     8.3.3 修改并添加子项目启动类

9. 启动子项目Tomcat服务器前往Nacos管理页面查看服务

10. 调用方法

     10.1 新增子项目【生产者构建 Provider】Controller模块代码 

     10.2 修改并添加子项目【消费者构建 Consumer】pom 文件

     10.3 新增子项目【消费者构建 Consumer】Controller模块码 

     10.4 修改并添加子项目【消费者构建 Consumer】启动类

     10.5 启动子项目服务器调用并测试方法


1. 什么是Spring Cloud?

    1.1 业务场景介绍 

       开发一个电商网站,要实现支付订单的功能,流程如下: 

  •  创建一个订单之后,如果用户立刻支付了这个订单,我们需要将订单状态更新为“已支付”
  •  扣减相应的商品库存
  •  通知仓储中心,进行发货
  •  给用户的这次购物增加相应的积分

    1.2 服务分析 

         订单服务、库存服务、仓储服务、积分服务 

    1.3 流程调用

  • 用户针对一个订单完成支付之后,就会去找订单服务,更新订单状态
  • 订单服务调用库存服务,完成相应功能
  • 订单服务调用仓储服务,完成相应功能
  • 订单服务调用积分服务,完成相应功能 

     1.4 Spring Cloud 

2. Spring Cloud 核心组件 

    2.1 Eureka

  •  Eureka是微服务架构中的注册中心,专门负责服务的注册与发现。
  •  订单服务想要调用库存服务、仓储服务,或者是积分服务,怎么调用?
  •  订单服务压根儿就不知道人家库存服务在哪台机器上啊!他就算想要发起一个请求,都不知     道发送给 谁,有心无力!

     

Eureka Client: 负责将这个服务的信息注册到Eureka Server中

Eureka Server:注册中心,里面有一个注册表,保存了各个服务所在的机器和端口号 

    2.2 Feign

  • 现在订单服务确实知道库存服务、积分服务、仓库服务在哪里了,同时也监听着哪些端口号了。但是新问题又来了:如何从订单服务跟其他服务建立网络连接,接着发送请求过去。 

 

    2.3 Ribbon 

        集群服务:库存服务部署在了5台机器上

  •   192.168.169:9000
  •   192.168.170:9000
  •   192.168.171:9000
  •   192.168.172:9000
  •   192.168.173:9000 

Ribbon就是专门解决这个问题的。它的作用是负载均衡,会帮你在每次请求时选择一台机器,均匀的把 请求分发到各个机器上 

  •  首先Ribbon会从 Eureka Client里获取到对应的服务注册表,也就知道了所有的服务都部署在   了哪 些机器上,在监听哪些端口号。 
  •  然后Ribbon就可以使用默认的Round Robin算法,从中选择一台机器
  •  Feign就会针对这台机器,构造并发起请求。

     2.4 Hystrix 

  • 在微服务架构里,一个系统会有很多的服务。
  • 以上面的业务场景为例:订单服务在一个业务流程里需要调用三个服务。
  • 现在假设订单服务自己最多只有100个线程可以处理请求,然后呢,积分服务不幸的挂了,每次订单服 务调用积分服务的时候,都会卡住几秒钟,然后抛出—个超时异常 

       出现问题:微服务架构中的服务雪崩问题 

  • 如果系统处于高并发的场景下,大量请求涌过来的时候,订单服务的100个线程都会卡在请求积分 服务这块。导致订单服务没有一个线程可以处理请求
  • 然后就会导致别人请求订单服务的时候,发现订单服务也挂了,不响应任何请求了
  • Hystrix是隔离、熔断以及降级的一个框架。 
  • 比如订单服务请求库存服务是一个线程池,请求仓储服务是一个线程池,请求积分服务是一个线程池。 每个线程池里的线程就仅仅用于请求那个服务。

      

       2.5 Zuul

           这个组件是负责网络路由的。 

  • 一般微服务架构中都必然会设计一个网关在里面,像android、ios、pc前端、微信小程  序、H5等等。 不用去关心后端有几百个服务,就知道有一个网关,所有请求都往网关走,网关会根据请求中的一些特 征,将请求转发给后端的各个服务。 有一个网关之后,还有很多好处,比如可以做统一的降级、限流、认证授权、安全,等等。 

              组件总和 

  •  Eureka:各个服务启动时,Eureka Client都会将服务注册到Eureka Server,并且Eureka   Client还 可以反过来从Eureka Server拉取注册表,从而知道其他服务在哪里
  •  Ribbon:服务间发起请求的时候,基于Ribbon做负载均衡,从一个服务的多台机器中选择一   台
  •  Feign:基于Feign的动态代理机制,根据注解和选择的机器,拼接请求URL地址,发起请求
  •  Hystrix:发起请求是通过Hystrix的线程池来走的,不同的服务走不同的线程池,实现了不同   服务 调用的隔离,避免了服务雪崩的问题
  •  Zuul:如果前端、移动端要调用后端系统,统一从Zuul网关进入,由Zuul网关转发请求给对   应的服务

               流程 

  1. 请求统一通过API网关(Zuul)来访问内部服务.
  2. 网关接收到请求后,从注册中心(Eureka)获取可用服务 
  3. 由Ribbon进行均衡负载后,分发到后端具体实例
  4. 微服务之间通过Feign进行通信处理业务
  5. Hystrix负责处理服务超时熔断

3.springCloud关系 

     Spring Cloud 包含很多子项目: Netflix 和 Alibaba 两个标准使用最多

   3.1 Spring Cloud Netflix 第一代 

     针对多种 Netflix 组件提供的开发工具包,其中包括 Eureka、Ribbon、Feign、Hystrix、Zuul、       Archaius 等。 

  • Netflix Eureka:一个基于 Rest 服务的服务治理组件,包括服务注册中心、服务注册与服务发现机 制的实现,实现了云端负载均衡和中间层服务器的故障转移。
  • Netflix Ribbon:客户端负载均衡的服务调用组件。
  • Netflix Hystrix:容错管理工具,实现断路器模式,通过控制服务的节点,从而对延迟和故障提供 更强大的容错能力。
  • Netflix Feign:基于 Ribbon 和 Hystrix 的声明式服务调用组件。
  • Netflix Zuul:微服务网关,提供动态路由,访问过滤等服务。
  • Netflix Archaius:配置管理 API,包含一系列配置管理 API,提供动态类型化属性、线程安全配置 操作、轮询框架、回调机制等功能。

   3.2 Spring Cloud Alibaba 第二代

  • 同 Spring Cloud 一样,Spring Cloud Alibaba 也是一套微服务解决方案。
  • Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。此项目包含开发分布式应用微服务的 必需组件,方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。
  • 依托 Spring Cloud Alibaba,只需要添加一些注解和少量配置,就可以将 Spring Cloud 应用接入阿里微 服务解决方案,通过阿里中间件来迅速搭建分布式应用系统。

    3.2.1 「阿里开源组件」

  • Nacos:阿里巴巴开源产品,一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平 台。
  • Sentinel:面向分布式服务架构的轻量级流量控制产品,把流量作为切入点,从流量控制、熔断降 级、系统负载保护等多个维度保护服务的稳定性。
  • RocketMQ:一款开源的分布式消息系统,基于高可用分布式集群技术,提供低延时的、高可靠的 消息发布与订阅服务。
  • Dubbo:Apache Dubbo™ 是一款高性能 Java RPC 框架,用于实现服务通信。
  • Seata:阿里巴巴开源产品,一个易于使用的高性能微服务分布式事务解决方案。

    3.2.2 「阿里商业化组件」

  • Alibaba Cloud ACM:一款在分布式架构环境中对应用配置进行集中管理和推送的应用配置中心产 品。
  • Alibaba Cloud OSS:阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供 的海量、安全、低成本、高可靠的云存储服务。您可以在任何应用、任何时间、任何地点存储和访 问任意类型的数据。
  • Alibaba Cloud SchedulerX:阿里中间件团队开发的一款分布式任务调度产品,提供秒级、精准、 高可靠、高可用的定时(基于 Cron 表达式)任务调度服务。
  • Alibaba Cloud SMS:覆盖全球的短信服务,友好、高效、智能的互联化通讯能力,帮助企业迅速 搭建客户触达通道。 

4. SpringCloud常用组件

  1. Spring Cloud Netflix Eureka:服务注册中心。
  2. Spring Cloud Zookeeper:服务注册中心。
  3. Spring Cloud Consul:服务注册和配置管理中心。
  4. Spring Cloud Netflix Ribbon:客户端负载均衡。
  5. Spring Cloud Netflix Hystrix:服务容错保护。
  6. Spring Cloud Netflix Feign:声明式服务调用。
  7. Spring Cloud OpenFeign(可替代 Feign):OpenFeign 是 Spring Cloud 在 Feign 的基础上支持了 Spring MVC 的注解,如 @RequesMapping等等。OpenFeign 的 @FeignClient 可以解析 SpringMVC 的 @RequestMapping 注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用 其他服务。 Spring Cloud Netflix Zuul:API 网关服务,过滤、安全、监控、限流、路由。
  8. Spring Cloud Gateway(可替代 Zuul):Spring Cloud Gateway 是 Spring 官方基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技术开发的网关,Spring Cloud Gateway 旨在为微服务架构提供一种简 单而有效的统一的 API 路由管理方式。Spring Cloud Gateway 作为 Spring Cloud 生态系中的网关,目 标是替代 Netflix Zuul,其不仅提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能, 例如:安全,监控/埋点,和限流等。
  9. Spring Cloud Security:安全认证。
  10. Spring Cloud Config:分布式配置中心。配置管理工具,支持使用 Git 存储配置内容,支持应用配置的 外部化存储,支持客户端配置信息刷新、加解密配置内容等。
  11. Spring Cloud Bus:事件、消息总线,用于在集群(例如,配置变化事件)中传播状态变化,可与 Spring Cloud Config 联合实现热部署。
  12. Spring Cloud Stream:消息驱动微服务。
  13. Spring Cloud Sleuth:分布式服务跟踪。
  14. Spring Cloud Alibaba Nacos:阿里巴巴开源产品,一个更易于构建云原生应用的动态服务发现、配置 管理和服务管理平台。
  15. Spring Cloud Alibaba Sentinel:面向分布式服务架构的轻量级流量控制产品,把流量作为切入点,从 流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
  16. Spring Cloud Alibaba RocketMQ:一款开源的分布式消息系统,基于高可用分布式集群技术,提供低 延时的、高可靠的消息发布与订阅服务。
  17. Spring Cloud Alibaba Dubbo:Apache Dubbo™ 是一款高性能 Java RPC 框架,用于实现服务通信。
  18. Spring Cloud Alibaba Seata:阿里巴巴开源产品,一个易于使用的高性能微服务分布式事务解决方案。

5. 版本关系

    Spring Boot

    Spring Cloud

    Spring Cloud Dependencies

    Spring Cloud中文学习指南

    Spring Cloud Alibaba

6. 版本管理规范

7. Nacos 搭建

    Nacos官网

Nacos 单节点,也就是 standalone 模式,默认使用嵌入式数据库实现数据的存储 不方便观察数据存储的基本情况,在0.7 版本以后增加了支持 MySQL 数据源能力。 集群搭建的时候需要将 Nacos 对接 Mysql 进行数据存储。

如果要搭建高可用的集群环境,至少要满足以下条件:

JDK 1.8+;

Maven 3.2.x+;

MySQL 5.6.5+(生产使用建议至少主备模式,或者采用高可用数据库);

3个或3个以上Nacos节点才能构成集群; 

   7.1 配置Nacos数据库源 

  • 进入Mysql数据库 运行下载好的Nacos文件下conf文件夹下Sql文件

 

# db mysql
spring.datasource.platform=mysql
db.num=1
db.url.0=jdbc:mysql://localhost:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
db.user=root
db.password=1234

   7.2 启动Nacos 并访问Nacos管理页面

  • 登录账号 nacos
  • 登录密码 nacos 

 

 8. 消费者和生成者编写

     8.1 新建一个maven项目为父工程  

  • 注!删除父工程里面的src目录 父工程不写代码 只负责给子项目提供依赖 

       8.1.1 修改父工程pom文件并添加以下代码

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

  <modelVersion>4.0.0</modelVersion>
  <groupId>com.jmh</groupId>
  <artifactId>springcloud01</artifactId>
  <version>1.0-SNAPSHOT</version>
  <!--pom代表这个是个父工程-->
  <packaging>pom</packaging>

  <!--指向儿子-->
  <modules>
    <module>nacos_provider</module>
    <module>nacos_consumer</module>
  </modules>

  <name>springcloud01 Maven Webapp</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <!--提供版本-->
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
    <spring-boot.version>2.4.1</spring-boot.version>
    <spring-cloud.version>2020.0.0</spring-cloud.version>
    <spring-cloud-alibaba.version>2021.1</spring-cloud-alibaba.version>
  </properties>

  <!--提供依赖-->
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
    </dependency>
  </dependencies>

  <!--提供依赖版本-->
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>${spring-boot.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
      <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>${spring-cloud.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
      <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-alibaba-dependencies</artifactId>
        <version>${spring-cloud-alibaba.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>


</project>

packing:(打包类型,默认为jar)

pom : 父级项目(pom项目里没有java代码,也不执行任何代码,只是为了聚合工程或传递依赖用的)

jar : 内部调用或者是作服务使用

war : 需要部署的项目

dependencyManagement:(管理jar包的版本,让子项目中引用一个依赖而不用显示的列出版本号) dependencyManagement与dependencies区别: dependencies即使在子项目中不写该依赖项,那么子项目仍然会从父项目中继承该依赖项(全部继 承)

dependencyManagement里只是声明依赖,并不实现引入,因此子项目需要显示的声明需要用的依 赖。 如果不在子项目中声明依赖,是不会从父项目中继承下来的。 只有在子项目中写了了该依赖项,并且没有指定具体版本,才会从父项目中继承该项,并且version和 scope都读取自父pom。 另外如果子项目中指定了版本号,那么会使用子项目中指定的jar版本。modules(用来管理同个项目中的各个模块)

导入三个版本的原因:

 nacos来自Spring Cloud Alibaba的(用于代替SpringCloud Eureka和SpringCloud Config)   feign来自Spring Cloud 其他的正常来自与SpringBoot 

  8.2 新建一个springboot项目为子项目 (生产者构建 Provider)

     8.2.1 修改并添加子项目pom文件  

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.jmh</groupId>
    <artifactId>nacos_provider</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>nacos_provider</name>
    <description>Demo project for Spring Boot</description>

    <!--指向父亲-->
    <parent>
        <artifactId>springcloud01</artifactId>
        <groupId>com.jmh</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>


    <dependencies>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

      8.2.2 修改并添加子项目application.yml文件

server:
  port: 8081
spring:
  cloud:
    nacos:
      server-addr: 127.0.0.1:8848
  application:
    name: nacos-provider

     8.2.3 修改并添加子项目启动类

package com.jmh.nacos_provider;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class NacosProviderApplication {

    public static void main(String[] args) {
        SpringApplication.run(NacosProviderApplication.class, args);
    }

}

 8.3 新建一个springboot项目为子项目  (消费者构建 Consumer)

     8.3.1 修改并添加子项目pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.jmh</groupId>
    <artifactId>nacos_consumer</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>nacos_consumer</name>
    <description>Demo project for Spring Boot</description>

    <!--指向父亲-->
    <parent>
        <artifactId>springcloud01</artifactId>
        <groupId>com.jmh</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <dependencies>
        
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

       8.3.2 修改并添加子项目application.yml文件

server:
  port: 8082
spring:
  cloud:
    nacos:
      server-addr: 127.0.0.1:8848
  application:
    name: nacos-consumer

       8.3.3 修改并添加子项目启动类

package com.jmh.nacos_consumer;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableDiscoveryClient
public class NacosConsumerApplication {

    public static void main(String[] args) {
        SpringApplication.run(NacosConsumerApplication.class, args);
    }


}

9. 启动子项目Tomcat服务器前往Nacos管理页面查看服务

  • 启动子项目Tomcat服务器 

  •  前往Nacos管理页面查看服务

 10. 调用方法

  • 比如我们消费者要问生产者要一个鸡腿!然后我们在两个互不相干的模块怎么互通呢?接下来看小编操作 直接上代码嘞 

     10.1新增子项目【生产者构建 Provider】Controller模块代码 

package com.jmh.nacos_provider.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author 蒋明辉
 * @data 2022/11/2 22:13
 */
@RestController
public class ProviderController {

    @RequestMapping("/run")
    public String run(){
        //生产鸡腿
        return "鸡腿";
    }
}

     10.2修改并添加子项目【消费者构建 Consumer】pom 文件

 <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-loadbalancer</artifactId>
 </dependency>

ribbon状态:停止更新

替代方案:Spring Cloud Loadbalancer 

     10.3新增子项目【消费者构建 Consumer】Controller模块码 

package com.jmh.nacos_consumer.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

/**
 * @author 蒋明辉
 * @data 2022/11/2 22:14
 */
@RestController
public class ConsumerController {

    @Autowired
    private RestTemplate restTemplate;

    @RequestMapping("/run")
    public String run(){
        //问生产者要鸡腿
        String forObject = restTemplate.
                getForObject("http://nacos-provider/run", String.class);
        return forObject;
    }

}

     10.4修改并添加子项目【消费者构建 Consumer】启动类

package com.jmh.nacos_consumer;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableDiscoveryClient
public class NacosConsumerApplication {

    public static void main(String[] args) {
        SpringApplication.run(NacosConsumerApplication.class, args);
    }

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

}

       10.5 启动子项目服务器调用并测试方法

猜你喜欢

转载自blog.csdn.net/m0_63300795/article/details/127662046#comments_27119909