A082_springcloud_微服务场景_Eureka

目录

1.内容介绍

1. 为什么需要spring cloud;(理解)
2. spring cloud概述;(理解)
3. spring cloud入门;(掌握)
4. Eureka注册中心集群;(掌握)
5. 服务集群-同一个服务注册多份;(掌握)
6. 服务集群-负载均衡调用ribbon/fegin;(掌握)

2.为什么需要spring cloud

2.1.Monolith(单体应用)架构
2.1.1.什么是单体应用

首先请回想一下我们所开发的服务是什么样子的。通常情况下,这个服务所对应的代码由多个项目所组成,各个项目会根据自身所提供功能的不同具有一个明确的边界。在编译时,这些项目将被打包成为一个个JAR包,并最终合并在一起形成一个WAR包。接下来,我们需要将该WAR包上传到Web容器中,解压该WAR包,并重新启动服务器。在执行完这一系列操作之后,我们对服务的编译及部署就已经完成了。这种将所有的代码及功能都包含在一个WAR包中的项目组织方式被称为Monolith
在这里插入图片描述

2.1.2.缺点
    在项目很小的情况下这种单体应用比较简单,但是随着项目越变越大,代码越来越多。就会存在以下缺点。
    ①编译难,部署难,测试难
     代码量变多,即使更改一行代码,也需花大量时间编译,部署前要编译打包,解压等所以部署难,部署完了还要测试所以测试难。
    ②技术选择难(不同模块不能独立技术选型)
     在变得越来越大的同时,我们的应用所使用的技术也会变得越来越多。这些技术有些是不兼容的,就比如在一个项目中大范围地混合使用C++和Java几乎是不可能的事情。在这种情况下,我们就需要抛弃对某些不兼容技术的使用,而选择一种不是那么适合的技术来实现特定的功能。
    ③扩展难(不能只扩展压力大的功能模块)
     按照Monolith组织的代码将只产生一个包含了所有功能的WAR包,因此在对服务的容量进行扩展的时候,我们只能选择重复地部署这些WAR包来扩展服务能力,而不是仅仅扩展出现系统瓶颈的组成:

在这里插入图片描述

是这种扩展方式极大地浪费了资源。就以上图所展示的情况为例:在一个服务中,某个组成的负载已经达到了90%,也就是到了不得不对服务能力进行扩容的时候了。而同一服务的其它三个组成的负载还没有到其处理能力的20%。由于Monolith服务中的各个组成是打包在同一个WAR包中的,因此通过添加一个额外的服务实例虽然可以将需要扩容的组成的负载降低到了45%,但是也使得其它各组成的利用率更为低下。
2.2.MicroService(微服务)架构
2.2.1.为什么需要

使用微服务架构就可以解决单体项目缺点。

2.2.2.什么是MicroService架构

微服务架构是一种架构模式,它提倡将单一应用程序划分成一组小的服务,服务之间互相协调、互相配合,为用户提供最终价值。每个服务运行在其独立的进程中,服务与服务间采用轻量级的通信机制互相沟通(通常是基于HTTP的RESTful API)。每个服务都围绕着具体业务进行构建,并且能够被独立地部署到生产环境、类生产环境等。另外,应尽量避免统一的、集中式的服务管理机制,对具体的一个服务而言,应根据业务上下文,选择合适的语言、工具对其进行构建。

微服务架构是一种架构风格,一个大型复杂软件应由多个微服务组成。系统中的各个微服务可被独立技术选型,独立开发,独立部署,独立运维,各个微服务之间是松耦合的。每个微服务仅关注于完成一件任务并很好地完成该任务。在所有情况下,每个任务代表着一个小的业务功能。 由各个微服务提供功能最终组成完整功能。
在这里插入图片描述
在这里插入图片描述

2.2.3.微服务远程调用方式

在微服务中服务间的远程调用。那么服务间的远程调用方式有哪些呢?

常见的远程调用方式有以下几种:

  • RPC:Remote Produce Call远程过程调用,类似的还有RMI。自定义数据格式,基于原生TCP通信,速度快,效率高。早期的webservice,现在热门的dubbo,都是RPC的典型
  • Http:http其实是一种网络传输协议,基于TCP,规定了数据传输的格式。现在客户端浏览器与服务端通信基本都是采用Http协议。也可以用来进行远程服务调用。缺点是消息封装臃肿。
    现在热门的Rest风格,就可以通过http协议来实现 springcloud http
2.2.3.1 认识RPC

RPC,即 Remote Procedure Call(远程过程调用),是一个计算机通信协议。 该协议允许运行于一台计算机的程序调用另一台计算机的子程序,而程序员无需额外地为这个交互作用编程。说得通俗一点就是:A计算机提供一个服务,B计算机可以像调用本地服务那样调用A计算机的服务。

通过上面的概念,我们可以知道,实现RPC主要是做到两点:

- 实现远程调用其他计算机的服务
  - 要实现远程调用,肯定是通过网络传输数据。A程序提供服务,B程序通过网络将请求参数传递给A,A本地执行后得到结果,再将结果返回给B程序。这里需要关注的有两点:
    - 1)采用何种网络通讯协议?
      - 现在比较流行的RPC框架,都会采用TCP作为底层传输协议
    - 2)数据传输的格式怎样?
      - 两个程序进行通讯,必须约定好数据传输格式。就好比两个人聊天,要用同一种语言,否则无法沟通。所以,我们必须定义好请求和响应的格式。另外,数据在网路中传输需要进行序列化,所以还需要约定统一的序列化的方式。

- 像调用本地服务一样调用远程服务 
  - 如果仅仅是远程调用,还不算是RPC,因为RPC强调的是过程调用,调用的过程对用户而言是应该是透明的,用户不应该关心调用的细节,可以像调用本地服务一样调用远程服务。所以RPC一定要对调用的过程进行封装

RPC调用流程图:
在这里插入图片描述

2.2.3.2 认识Http

Http协议:超文本传输协议,是一种应用层协议。规定了网络传输的请求格式、响应格式、资源定位和操作的方式等。但是底层采用什么网络传输协议,并没有规定,不过现在都是采用TCP协议作为底层传输协议。说到这里,大家可能觉得,Http与RPC的远程调用非常像,都是按照某种规定好的数据格式进行网络通信,有请求,有响应。没错,在这点来看,两者非常相似,但是还是有一些细微差别。

- RPC并没有规定数据传输格式,这个格式可以任意指定,不同的RPC协议,数据格式不一定相同。
- Http中还定义了资源定位的路径,RPC中并不需要
- 最重要的一点:RPC需要满足像调用本地服务一样调用远程服务,也就是对调用过程在API层面进行封装。Http协议没有这样的要求,因此请求、响应等细节需要我们自己去实现。
  - 优点:RPC方式更加透明,对用户更方便。Http方式更灵活,没有规定API和语言,跨语言、跨平台
  - 缺点:RPC方式需要在API层面进行封装,限制了开发的语言环境。

例如我们通过浏览器访问网站,就是通过Http协议。只不过浏览器把请求封装,发起请求以及接收响应,解析响应的事情都帮我们做了。如果是不通过浏览器,那么这些事情都需要自己去完成。
在这里插入图片描述

2.2.3.3 如何选择

既然两种方式都可以实现远程调用,我们该如何选择呢?

  • 速度来看,RPC要比http更快,虽然底层都是TCP,但是http协议的信息往往比较臃肿,不过可以采用gzip压缩。
  • 难度来看,RPC实现较为复杂,http相对比较简单
  • 灵活性来看,http更胜一筹,因为它不关心实现细节,跨平台、跨语言。

因此,两者都有不同的使用场景:

  • 如果对效率要求更高,并且开发过程使用统一的技术栈,那么用RPC还是不错的。 dubbo
  • 如果需要更加灵活,跨语言、跨平台,显然http更合适 springcloud

那么我们该怎么选择呢?
微服务,更加强调的是独立、自治、灵活。而RPC方式的限制较多,因此微服务框架中,一般都会采用基于Http的Rest风格服务。

2.2.3.4 Http客户端工具

既然Springclud微服务选择了Http,那么我们就需要考虑自己来实现对请求和响应的处理。不过开源世界已经有很多的http客户端工具,能够帮助我们做这些事情,例如:

- HttpClient
- OKHttp
- URLConnection
- Spring的RestTemplate
	Spring提供了一个RestTemplate模板工具类,对基于Http的客户端进行了封装,并且实现了对象与json的序列化和反序列化,非常方便。RestTemplate并没有限定Http的客户端类型,而是进行了抽象,目前常用的3种都有支持:
	- HttpClient
	- OkHttp
	- JDK原生的URLConnection(默认)

在这里插入图片描述
在这里插入图片描述
先简单认识,后面使用

2.2.4.优势

复杂度可控:
在将应用分解的同时,规避了原本复杂度无止境的积累。每一个微服务专注于单一功能,并通过定义良好的接口清晰表述服务边界。由于体积小、复杂 度低,每个微服务可由一个小规模开发团队完全掌控,易于保持高可维护性和开发效率。

独立部署(独立。。。):
由于微服务具备独立的运行进程,所以每个微服务也可以独立部署。当某个微服务发生变更时无需编译、部署整个应用。由微服务组成的应用相当于具备一系列可并行的发布流程,使得发布更加高效,同时降低对生产环境所造成的风险,最终缩短应用交付周期。

技术选型灵活:
微服务架构下,技术选型是去中心化的。每个团队可以根据自身服务的需求和行业发展的现状,自由选择最适合的技术栈。由于每个微服务相对简单,故需要对技术栈进行升级时所面临的风险就较低,甚至完全重构一个微服务也是可行的。

容错:
当某一组建发生故障时,在单一进程的传统架构下,故障很有可能在进程内扩散,形成应用全局性的不可用。在微服务架构下,故障会被隔离在单个服务中。若设计良好,其他服务可通过重试、平稳退化等机制实现应用层面的容错。

扩展:
单块架构应用也可以实现横向扩展,就是将整个应用完整的复制到不同的节点。当应用的不同组件在扩展需求上存在差异时,微服务架构便体现出其灵活性,因为每个服务可以根据实际需求独立进行扩展。

在这里插入图片描述

2.3.Monolith&microSrvice使用场景
2.3.1.选择依据

既然微服务架构这个NB,那么是否所有项目都适用呢?
在这里插入图片描述
从上图中可以看到,在刚开始的阶段,使用Microservice架构模式开发应用的效率明显低于Monolith。但是随着应用规模的增大,基于Microservice架构模式的开发效率将明显上升,而基于Monolith模式开发的效率将逐步下降。

这是因为Microservice是一个架构模式,而不是一个特定的技术解决方案。其并不会将开发中的各个难点全部转移,而只是允许通过更为合适的技术来适当简化单个子服务的开发,或者绕过开发中可能遇到的部分难点。但是为了支持各个子服务的运行,我们还需要创建一系列公共服务。这些公共服务需要在编写第一个子服务的同时进行。这是导致Microservice架构模式在开发初期会具有较低效率的一个原因。
然而使用特定技术并不会绕过开发中所能遇到的所有难点。由于在Microservice架构中,各个子服务都集中精力处理本身的业务逻辑,而所有的公共功能都交由公共服务来完成,因此公共服务在保持和各个子服务的松耦合性的同时还需要提供一个足够通用的,能够在一定程度上满足所有当前和未来子服务要求的解决方案。而这也是导致Microservice架构模式在开发初期会具有较低效率的另外一个原因。
而在开发的后期,随着Monolith模式中应用的功能逐渐变大,增加一个新的功能会影响到该应用中的很多地方,因此其开发效率会越来越差。反过来,由于Microservice架构模式中的各个子服务所依赖的公共服务已经完成,而且子服务本身可以选择适合自己的实现技术,因此子服务的实现通常只需要关注自身的业务逻辑即可。这也是Microservice架构模式在后期具有较高效率的原因。
当我们再次通过Microservice架构模式搭建应用的时候,其在开发时的效率劣势也将消失,原因就是因为在前一次基于Microservice架构模式开发的时候,我们已经创建过一次公共服务,因此在这个新的应用中,我们将这些公共服务拿来并稍事改动即可:

2.3.2.选型

单体应用架构:中小型项目(功能相对较少),公司官网,管理系统(学生管理,CRM,OA,财务系统)等

微服务架构:大型项目(功能比较多) 商城,erp,人力资源,宠物乐园等-互联网项目

2.4.MicroService实现技术方案

spring微服务解决方案:
alibaba Dubbo,停止更新
 Springcloud netflix 1.0,springcloud的全称,停止更新
 Springcloud alibaba 2.0
 Kubernates-k8s
Service mesh-istio

2.4.1.MicroService只是一种架构思想

是一种架构的理念,提出了微服务的设计原则,从理论为具体的技术落地提供了指导思想。

2.4.2.实现技术-springboot

Java中可以使用传统ssm ssj等架构,当然更加推荐Springboot。Spring Boot是一套快速配置脚手架,可以基于Spring Boot快速开发单个微服务;

2.4.3.服务治理框架

由于微服务架构中存在多个微服务,那么如何管理和协调这些服务呢?就需要服务治理框架,而springcloud就是一个基于Spring Boot实现的服务治理工具包。

微服务架构是一种思想,需要技术落地, 在spring微服务解决方案中,springboot用来实现单个服务,而服务间协调调用要使用服务治理框架springcloud来实现。

Dubbo也是一套微服务解决方案

2.5.小结

相较于单体应用这个架构模式,微服务架构更加适用于大型项目,虽然刚开始成本高,但是随着项目开展成本会变得越来越低。并且微服务只是一种架构思想,具体可以通过springboot快速开发一个单一服务,但是多个服务协调管理,就需要服务治理框架springcloud等。

大项目–微服务架构–spring微服务解决方案-springboot&springcloud

3.Spring cloud概述

3.1.是什么

Spring cloud是一个基于Spring Boot实现的服务治理工具包,用于微服务架构中管理和协调各个服务的。

3.2.组成部分

Spring Cloud是一系列框架的有序集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。Springcloud并没有重复制造轮子,它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过Spring Boot风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。

以下是主要组成部分:
在这里插入图片描述
所有组成。19个
Spring Cloud共集成了19个子项目,里面都包含一个或者多个第三方的组件或者框架!

Spring Cloud 工具框架

1、Spring Cloud Config 配置中心,利用git集中管理程序的配置。
2、Spring Cloud Netflix 集成众多Netflix的开源软件
3、Spring Cloud Bus 消息总线,利用分布式消息将服务和服务实例连接在一起,用于在一个集群中传播状态的变化
4、Spring Cloud for Cloud Foundry 利用Pivotal Cloudfoundry集成你的应用程序
5、Spring Cloud Cloud Foundry Service Broker 为建立管理云托管服务的服务代理提供了一个起点。
6、Spring Cloud Cluster 基于Zookeeper, Redis, Hazelcast, Consul实现的领导选举和平民状态模式的抽象和实现。
7、Spring Cloud Consul 基于Hashicorp Consul实现的服务发现和配置管理。
8、Spring Cloud Security 在Zuul代理中为OAuth2 rest客户端和认证头转发提供负载均衡
9、Spring Cloud Sleuth SpringCloud应用的分布式追踪系统,和Zipkin,HTrace,ELK兼容。
10、Spring Cloud Data Flow 一个云本地程序和操作模型,组成数据微服务在一个结构化的平台上。
11、Spring Cloud Stream 基于Redis,Rabbit,Kafka实现的消息微服务,简单声明模型用以在Spring Cloud应用中收发消息。
12、Spring Cloud Stream App Starters 基于Spring Boot为外部系统提供spring的集成
13、Spring Cloud Task 短生命周期的微服务,为SpringBooot应用简单声明添加功能和非功能特性。
14、Spring Cloud Task App Starters
15、Spring Cloud Zookeeper 服务发现和配置管理基于Apache Zookeeper。
16、Spring Cloud for Amazon Web Services 快速和亚马逊网络服务集成。
17、Spring Cloud Connectors 便于PaaS应用在各种平台上连接到后端像数据库和消息经纪服务。
18、Spring Cloud Starters (项目已经终止并且在Angel.SR2后的版本和其他项目合并)
19、Spring Cloud CLI 插件用Groovy快速的创建Spring Cloud组件应用。

当然也在不断增加。。。。

五大神兽(组件):
服务注册发现(注册中心)——Netflix Eureka : 帮我们管理服务的通信地址(ip,端口)
客户端负载均衡——Netflix Ribbon\Feign : 解决服务负载均衡 调用的
断路器——Netflix Hystrix :解决微服务故障的,保护微服务的
服务网关——Netflix Zuul :统一访问入口,微服务的大门(安保部门)
分布式配置——Spring Cloud Config :统一管理微服务的配置

springcloud Netflix:springcloud 1.0:市面上用得多,Netflix已经没有开源精神。
springcloud alibaba:springcloud 2.0,以后的趋势,特别是在国内。

3.3.Spring cloud pk dubbo

1)从两个公司的背景来谈:Dubbo,是阿里巴巴服务化治理的核心框架,并被广泛应用于中国各互联网公司;Spring Cloud是大名鼎鼎的Spring家族的产品。阿里巴巴是一个商业公司,虽然也开源了很多的顶级的项目,但从整体战略上来讲,仍然是服务于自身的业务为主。Spring专注于企业级开源框架的研发,不论是在中国还是在世界上使用都非常广泛,开发出通用、开源、稳健的开源框架就是他们的主业。

2)从社区活跃度这个角度来对比,Dubbo虽然也是一个非常优秀的服务治理框架,并且在服务治理、灰度发布、流量分发这方面做的比Spring Cloud还好,除过当当网在基础上增加了rest支持外,已有两年多的时间几乎都没有任何更新了。在使用过程中出现问题,提交到github的Issue也少有回复。

相反Spring Cloud自从发展到现在,仍然在不断的高速发展,从github上提交代码的频度和发布版本的时间间隔就可以看出,现在Spring Cloud即将发布2.0版本,到了后期会更加完善和稳定。

3)从整个大的平台架构来讲,dubbo框架只是专注于服务之间的治理,如果我们需要使用配置中心、分布式跟踪这些内容都需要自己去集成,这样无形中使用dubbo的难度就会增加。Spring Cloud几乎考虑了服务治理的方方面面,更有Spring Boot这个大将的支持,开发起来非常的便利和简单。

4)从技术发展的角度来讲,Dubbo刚出来的那会技术理念还是非常先进,解决了各大互联网公司服务治理的问题,中国的各中小公司也从中受益不少。经过了这么多年的发展,互联网行业也是涌现了更多先进的技术和理念,Dubbo一直停滞不前,自然有些掉队,有时候我个人也会感到有点可惜,如果Dubbo一直沿着当初的那个路线发展,并且延伸到周边,今天可能又是另一番景象了。

Spring 推出Spring Boot/Cloud也是因为自身的很多原因。Spring最初推崇的轻量级框架,随着不断的发展也越来越庞大,随着集成项目越来越多,配置文件也越来越混乱,慢慢的背离最初的理念。随着这么多年的发展,微服务、分布式链路跟踪等更多新的技术理念的出现,Spring急需一款框架来改善以前的开发模式,因此才会出现Spring Boot/Cloud项目,我们现在访问Spring官网,会发现Spring Boot和Spring Cloud已经放到首页最重点突出的三个项目中的前两个,可见Spring对这两个框架的重视程度。

总结一下,dubbo曾经确实很牛逼,但是Spring Cloud是站在近些年技术发展之上进行开发,因此更具技术代表性。

3.4.总结

Spring cloud是微服务架构中服务治理工具集,有很多产品组成。核心为五大神兽。相较于dubbo更加靠谱。

4.微服务场景模拟-入门

两者(user-provider),服务消费者(user-consumer)

4.1.引入

前面已经理解了一些关于spring cloud的理论介绍,接下来就来搭建一个服务调用案例,以便以后学习微服务架构。当然入门都需要一些步骤:
1)搭建环境
  以maven多模块化的方法搭建
2)服务提供者=提供服务
3)服务消费者-调用服务
在这里插入图片描述

4.2.搭建环境
4.2.1.Idea创建springboot项目
  1. 普通maven 项目
  2. Spring-initatier
    在这里插入图片描述
    但是不支持模块管理,需要手动处理
4.2.2.结构分析

在这里插入图片描述

   user_interface/facade/common 公共代码
      domain,query,接口,util
   user_provider_8001 :服务提供者
      public User getUser
   user_consumer_9001:服务消费者
     User user = 调用代码
4.2.3.搭建父模块

Parent:
限定springboot版本
限定springcloud版本

   <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.5.RELEASE</version>
    </parent>
	<properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Finchley.SR1</spring-cloud.version>
        <springboot.version>2.0.5.RELEASE</springboot.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            
        </dependencies>
    </dependencyManagement>

在这里插入图片描述

4.3.服务提供者
4.3.1.工程搭建
  user_interface/facade 	公共代码
  domain,query,				接口,util
  user_provider_8001 :		服务提供者
  public User getUser
4.3.2.导入jar
<dependencies>
   <!--公共代码依赖-->
   <dependency>
       <groupId>cn.itsource.springcloud</groupId>
       <artifactId>User_interface</artifactId>
       <version>1.0-SNAPSHOT</version>
   </dependency>

   <!--springboot支持-->
   <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-web</artifactId>
   </dependency>
   <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-test</artifactId>
   </dependency>

   
</dependencies>
4.3.3.Yml配置
server:
  port: 8001
spring:
  application:
    name: USER-PROVIDER #不要使用下划线
    
4.3.4.入口类
@SpringBootApplication
public class UserProviderApplication_8001 {
    public static void main(String[] args) {
        SpringApplication.run(UserProviderApplication_8001.class);
    }
}
4.3.5.写服务代码
@RestController
@RequestMapping("/provider")
public class UserController {

    //    @Autowired
   //    private IUserService userService;
    @GetMapping("/user/{id}") //user/1
    public User getUser(@PathVariable("id") Long id) {

        // 正常应该调用service获取用户,现在模拟一下
        return new User(id, "zs");
    }
}
4.3.6.测试

http调用

http://localhost:8011/provider/user/1

4.4.服务消费者
4.4.1.创建项目
user_consumer_9001:		服务消费者
	 User user = 		调用代码
4.4.2.导入jar
<!--公共代码依赖-->
<dependency>
    <groupId>cn.itsource.springcloud</groupId>
    <artifactId>User_interface</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

<!--springboot支持-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
</dependency>
4.4.3.配置yml
server:
  port: 9001
spring:
  application:
    name: USER-CONSUMER
    
4.4.4.入口类
package cn.itsource.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class UserConsumerAppliction_9001 {
    public static void main(String[] args) {
        SpringApplication.run(UserConsumerAppliction_9001.class);
    }
}
4.4.5.调用接口
@Configuration // <beans></beans>
public class CfgBean {

    @Bean //<bean class="org.springframework.web.client.RestTemplate"></bean>
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}
@RestController
@RequestMapping("/consumer")
public class UserController {

    //多个方法调用只需改一处就ok
    public static  final String URL_PREFIX = "http://localhost:8001";

    @Autowired
    private RestTemplate restTemplate;

    @RequestMapping("/user/{id}")
    public User getUser(@PathVariable("id")Long id){
        //调用远程服务 http请求
        String url = URL_PREFIX+"/provider/user/"+id;
        return restTemplate.getForObject(url,User.class );
    }
}

一个简单的远程服务调用案例就实现了。

4.4.6.测试

正常来说可以通过:http://localhost:9001/consumer/user/1 来进行测试了,但是有强依赖问题。

4.5.总结

通过springboot实现服务提供者,然后再服务消费者以restTemplate以restful的方式完成服务调用。

5.Eureka注册中心-入门

5.1.介绍
5.1.1.为什么需要需要服务注册中心

简单回顾一下,刚才我们写了什么:

  • user-provider:一个提供根据id查询用户的微服务
  • user-consumer:一个服务调用者,通过RestTemplate远程调用user-provider

流程如下:
在这里插入图片描述
存在什么问题?

  • 在consumer中,我们把url地址硬编码到了代码中,不方便后期维护
  • consumer需要记忆user-service的地址,如果出现变更,可能得不到通知,地址将失效
  • consumer不清楚user-service的状态,服务宕机也不知道
  • user-service只有1台服务,不具备高可用性
  • 即便user-service形成集群,consumer还需自己实现负载均衡

其实上面说的问题,概括一下就是分布式服务必然要面临的问题:

  • 服务管理
    • 如何自动注册和发现
    • 如何实现状态监管
    • 如何实现动态路由
  • 服务如何实现负载均衡
  • 服务如何解决容灾问题
  • 服务如何实现统一配置

以上的问题,我们都将在注册中心实现。

5.1.2.常见的注册中心

由于Spring Cloud为服务治理做了一层抽象接口,所以在Spring Cloud应用中可以支持多种不同的服务注册中心,比如:Netflix Eureka、Consul、Zookeeper,Nacas。在Spring Cloud服务治理抽象层的作用下,我们可以无缝地切换服务治理实现,并且不影响任何其他的服务注册、服务发现、服务调用等逻辑。

选择Eureka

5.1.3.Eureka是什么

Eureka是netflix的一个子模块,也是核心模块之一,Eureka是一个基于REST的服务,用于定位服务,以实现云端中间层服务发现和故障转移。服务注册与发现对于微服务架构来说是非常重要的,有了服务发现和注册,只需要使用服务的标识符,就可以访问到服务,而不需要修改服务,而不需要修改服务调用的配置文件了,功能类似于dubbo的注册中心,比如zookeeper。

5.1.4.原理

Eureka是一个服务注册与发现组件,简单说就是用来统一管理微服务的通信地址,它包含了EurekaServer服务端(也叫注册中心)和EurekaClient客户端两部分组成,EureakServer是独立的服务,而EurekaClient需要集成到每个微服务中。

微服务(EurekaClient)在启动的时候会向EureakServer提交自己的通信地址清单如:服务名,ip,端口,在EurekaServer会形成一个微服务的通信地址列表 — 这叫服务注册

服务名Ip:端口
User-provier[“Localhost:4010”,Localhost:4020]
User-consumerLocalhost:5010

微服务(EurekaClient)会定期的从EureakServer拉取一份微服务通信地址列表缓存到本地。一个微服务在向另一个微服务发起调用的时候会根据目标服务的服务名找到其通信地址清单,然后基于HTTP协议向目标服务发起请求。—这叫服务发现

另外,微服务(EurekaClient)采用“心跳”机制向EureakServer发请求进行服务续约,其实就是定时向EureakServer发请求报告自己的健康状况,告诉EureakServer自己还活着,不要把自己从服务地址清单中掉,那么当微服务(EurekaClient)宕机未向EureakServer续约,或者续约请求超时,注册中心机会从地址清单中剔除该续约失败的服务
在这里插入图片描述

5.2.Eureka注册中心搭建
5.2.1.创建项目

创建一个普通maven项目
eureka_server_7001

5.2.2.Pom
<!--springboot支持-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
</dependency>

<!--Eureka服务端支持-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
5.2.3.yml配置

:

server:
  port: 7001
eureka:
  instance:
    hostname: localhost
  client:
    registerWithEureka: false #是否要注册到eureka
    fetchRegistry: false #表示是否从Eureka Server获取注册信息
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ #单机配置
5.2.4.主类
@SpringBootApplication
@EnableEurekaServer //标识是eureka服务端
public class EnrekaServerApplication_7001 {
    public static void main(String[] args) {
        SpringApplication.run(EnrekaServerApplication_7001.class);
    }
}
5.2.5.启动并测试

启动入库类访问localhost:7001
在这里插入图片描述

5.2.6.注意事项

1)自我保护引发的错误
在这里插入图片描述
Eureka自我保护机制导致,不影响使用.

2)显示IP地址
问题:
在这里插入图片描述
解决方案: 在客户端实现

eureka:
  client:
    service-url:
     defaultZone: http://localhost:7001/eureka  #告诉服务提供者要把服务注册到哪儿
  instance:
    prefer-ip-address: true #显示客户端真实ip
5.3.服务提供者注册到Eureka
5.3.1.导入jar
 <!--eureka客户端支持 -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
5.3.2.修改配置
spring:
  application:
    name: user-provider
eureka:
  client:
    service-url:
     defaultZone: http://localhost:7001/eureka #告诉服务提供者要把服务注册到哪儿
 instance:
    prefer-ip-address: true # 当调用getHostname获取实例的hostname时,返回ip而不是host名称
    ip-address: 127.0.0.1 # 指定自己的ip信息,不指定的话会自己寻找
5.3.3.启动类启用Eureka
@SpringBootApplication
@EnableEurekaClient //表示是eureka的客户端
public class UserProviderApplication_8001 {
    public static void main(String[] args) {
        SpringApplication.run(UserProviderApplication_8001.class);
    }
}
5.3.4.测试

启动入库类访问localhost:7001
在这里插入图片描述

5.4.服务消费者从Eureka调用服务
5.4.1.导入jar
<!-- Eureka客户端 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
5.4.2.修改配置
eureka:
  client:
    service-url:
     defaultZone: http://localhost:7001/eureka #告诉服务提供者要把服务注册到哪儿
 instance:
    prefer-ip-address: true # 当调用getHostname获取实例的hostname时,返回ip而不是host名称
    ip-address: 127.0.0.1 # 指定自己的ip信息,不指定的话会自己寻找
5.4.3.入口类用Eureka客户端
package cn.itsource.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@EnableEurekaClient
public class UserConsumerAppliction_9001 {

@Bean
    public RestTemplate restTemplate() {
        return new RestTemplate(new OkHttp3ClientHttpRequestFactory());
    }
    public static void main(String[] args) {
        SpringApplication.run(UserConsumerAppliction_9001.class);
    }
}

5.4.4.整改服务调用
	 @Autowired
	private DiscoveryClient discoveryClient;// Eureka客户端,可以获取到服务实例信息
	
	// String baseUrl = "http://localhost:8081/user/";
        // 根据服务名称,获取服务实例
        List<ServiceInstance> instances = discoveryClient.getInstances("user-service");
        // 因为只有一个UserService,因此我们直接get(0)获取
        ServiceInstance instance = instances.get(0);
        // 获取ip和端口信息
        String baseUrl = "http://"+instance.getHost() + ":" + instance.getPort()+"/user/";
       this.restTemplate.getForObject(baseUrl + id, User.class)

只解决写死url,但是还没有负载均衡,属于明天内容

5.4.5.测试

http请求访问

6.Eureka注册中心集群

6.1.为什么需要集群

如果只有一个注册中心服务器,会存在单点故障所以要集群。

6.2.怎么做

准备三个EurekaServer 相互注册,也就是说每个EurekaServer都需要向所有的EureakServer注册,包括自己 ,每个EurekaServer即充当了服务端,也充当了客户端。咱们的其他微服务(order,user)只需要把注册地址指向所有的EurekaServer就可以了。
在这里插入图片描述
生产环境把Eureka jar包部署多个服务器就ok了,但是现在是开发阶段同一台主机不同端口号来代替服务器 ,方案也有两种。
方案1:拷贝一份代码为多份,修改端口不一样。分别启动
方案2:一份代码,多份配置。 每一个配置启动一份。

6.2.1.修改配置
Hosts
127.0.0.1 eureka1
127.0.0.1 eureka2
127.0.0.1 eureka3
application.yml
spring:
  profiles:
    active: eureka3 #默认启动eureka1

application-eureka1.yml
server:
  port: 1010
eureka:
  instance:
    hostname: eureka1
  client:
    serviceUrl:
      defaultZone: http://eureka1:1010/eureka,http://eureka2:1020/eureka,http://eureka3:1030/eureka
spring:
  application:
    name: eureka1

application-eureka2.yml
server:
  port: 1020
eureka:
  instance:
    hostname: eureka2
  client:
    serviceUrl:
      defaultZone: http://eureka1:1010/eureka,http://eureka2:1020/eureka,http://eureka3:1030/eureka
spring:
  application:
    name: eureka2

application-eureka3.yml
server:
  port: 1030
eureka:
  instance:
    hostname: eureka3
  client:
    serviceUrl:
      defaultZone: http://eureka1:1010/eureka,http://eureka2:1020/eureka,http://eureka3:1030/eureka
spring:
  application:
    name: eureka3
6.2.2.启动三份

在这里插入图片描述
修改
Application.yml中配置分别启动三个

6.2.3.服务提供者和服务消费者修改

#defaultZone: http://localhost:7001/eureka
http://eureka1:1010/eureka,http://eureka2:1011/eureka,http://eureka3:1012/eureka

6.3.总结

如果是只有一个Eureka注册中心,会存在单点故障,要做集群,做了集群后,服务提供者和消费者注册服务或发现服务时要配置集群(把多个Eureka都配置上).

7.服务负载均衡

7.1.为什么需要负载均衡

为了提供并发量,有时同一个服务提供者可以部署多个(商品服务)。这个客户端在调用时要根据一定的负载均衡策略完成负载调用。
在这里插入图片描述

  1. 服务提供者集群
    部署多份,项目上线,同一个jar在多个服务器完成部署那就OK了
    开发的时候,有两种方案:
    方案1:拷贝一份代码为多份,修改端口不一样。分别启动
    方案2:一份代码,多份配置。 每一个配置启动一份。

  2. 服务消费者负载均衡都用
    客户端调用没有实现负载均衡.
    在这里插入图片描述

7.2.服务生产者集群部署
7.2.1 配置
application.yml
spring:
  profiles:
    active: user1

application-user1.yml
server:
  port: 4010
spring:
  application:
    name: user-provider #不要有下划线
eureka:
  client:
    service-url:
     defaultZone: http://eureka1:1010/eureka,http://eureka2:1020/eureka,http://eureka3:1030/eureka
  instance:
    prefer-ip-address: true # 当调用getHostname获取实例的hostname时,返回ip而不是host名称
    ip-address: 127.0.0.1 # 指定自己的ip信息,不指定的话会自己寻找
    hostname: user-provider:4010 #主机名

application-user2.yml
server:
  port: 4020
spring:
  application:
    name: user-provider #不要有下划线
eureka:
  client:
    service-url:
     defaultZone: http://eureka1:1010/eureka,http://eureka2:1020/eureka,http://eureka3:1030/eureka
  instance:
    prefer-ip-address: true #当调用getHostname获取实例的hostname时,返回ip而不是host名称
    ip-address: 127.0.0.1 #指定自己的ip信息,不指定的话会自己寻找
    hostname: user-provider:4020 #主机名

改造服务提供者controller

package cn.itsource.controller;
import cn.itsource.domain.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/user/provider/")
public class UserController {

    @Autowired
    private ApplicationContext context;

    //正常要调用service,进而调用数据库,但是现在模拟一下,直接返回
    @RequestMapping("/{id}")
    public User getById(@PathVariable("id") Long id){

        String[] activeProfiles = context.getEnvironment().getActiveProfiles();
        System.out.println(activeProfiles[0]);
        return new User(id,"zs");
    }
}
7.2.2 启动

改动默认启动,分别启用user1,user2

7.3.服务消费者常见负载均衡实现技术
7.3.1.Ribbon

通过RestTmplate,以url完成服务的调用

7.3.2.Feign

feign底层还是ribbon,只是进行了封装,让我们以接口的方式进行调用

7.4.Ribbon负载均衡调用
7.4.1.是什么

Ribbon是Netflix发布的云中间层服务开源项目,主要功能是提供客户端负载均衡算法。Ribbon客户端组件提供一系列完善的配置项,如,连接超时,重试等。简单的说,Ribbon是一个客户端负载均衡器,我们可以在配置文件中列出load Balancer后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器,我们也很容易使用Ribbon实现自定义的负载均衡算法。

Ribbon是一个客户端负载均衡器,它可以按照一定规则来完成多台服务器负载均衡调用,这些规则还支持自定义。

7.4.2.集成原理

在这里插入图片描述

7.4.3.负载均衡测试

1)导入jar

   <!--客户端负载均衡实现 ribbon-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>

2)代码

@Configuration
public class CfgBean {

    @Bean
    @LoadBalanced //开启负载均衡
    public RestTemplate getRestTemplate(){
        return  new RestTemplate();
    }
}
@RestController
@RequestMapping("/consumer")
public class UserController {

    //多个方法调用只需改一处就ok
    //public static  final String URL_PREFIX = "http://localhost:8001";
    public static  final String URL_PREFIX = "http://USER-PROVIDER"; //通过服务名从注册中心获取服务列表,通过负载均衡调用

    @Autowired
    private RestTemplate restTemplate;

    @RequestMapping("/user/{id}")
    public User getUser(@PathVariable("id")Long id){
        //调用远程服务 http请求
        String url = URL_PREFIX+"/provider/user/"+id;
        return restTemplate.getForObject(url,User.class );
    }
}

为了看到测试效果,改造了服务提供者

package cn.itsource.controller;
import cn.itsource.domain.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.*;
import java.applet.AppletContext;

@RestController
@RequestMapping("/user/provider")
public class UserController {

    @Autowired
    private ApplicationContext context;

    @GetMapping("/{id}")
    public User getById(@PathVariable(value = "id")Long id){

        System.out.println(context.getEnvironment().getActiveProfiles());
        String activeProfiles = context.getEnvironment().getActiveProfiles()[0];
        //正常来说需要查询数据库 service-mapper,现在模拟实现,自己new一个返回
        return new User(id,"zs"+activeProfiles);

    }
}

测试
在这里插入图片描述
不断刷新会出现轮询效果

7.4.4.负载均衡策略

ribbon通过服务名获取到服务列表后,要根据一定规则来选择一个服务实例来完成调用.这个规则就叫负载均衡策略.

1)IRule
通过配置不同IRule的子类,可以选择不同负载均衡策略,也就是从服务列表以特定策略选择一个服务来完成调用。当然也可以自定义。所以负载均衡策略可以分为内置和自定义。

2)内置负载均衡策略
在这里插入图片描述
在这里插入图片描述

7.4.5.优化

1)超时配置
使用Ribbon进行服务通信时为了防止网络波动造成服务调用超时,我们可以针对Ribbon配置超时时间以及重试机制

ribbon:
  readTimeout: 3000					#读取超时时间
  connectTimeout: 3000				#链接超时时间
  maxAutoRetries: 1 				#重试机制:同一台实例最大重试次数
  maxAutoRetriesNextServer: 1 		#重试负载均衡其他的实例最大重试次数
  okToRetryOnAllOperations: false  	#是否所有操作都重试,因为针对post请求如果没做幂等处理可能会造成数据多次添加/修改

当然也可以针对具体的服务进行超时配置:如"<服务名>.ribbon…"

2)饥饿加载
我们在启动服务使用Ribbon发起服务调用的时候往往会出现找不到目标服务的情况,这是因为Ribbon在进行客户端负载均衡的时候并不是启动时就创建好的,而是在实际请求的时候才会去创建,所以往往我们在发起第一次调用的时候会出现超时导致服务调用失败,我们可以通过设置Ribbon的饥饿加载来改善此情况,即在服务启动时就把Ribbon相关内容创建好。

ribbon:
  eager-load:
    enabled: true #开启饥饿加载
    clients: user-server #针对于哪些服务需要饥饿加载

https://zhuanlan.zhihu.com/p/29747134?from_voters_page=true

7.5.Feign负载均衡
7.5.1.是什么

前面的可以发现当我们通过RestTemplate调用其它服务的API时,所需要的参数须在请求的URL中进行拼接,如果参数少的话或许我们还可以忍受,一旦有多个参数的话,这时拼接请求字符串就会效率低下,并且显得好傻。
在这里插入图片描述

  • Feign是一个声明式的Web Service客户端,它的目的就是让Web Service调用更加简单。Feign提供了HTTP请求的接口模板(上面标的有访问地址),通过编写简单的接口和插入注解,就可以定义好HTTP请求的参数、格式、地址等信息。而Feign则会完全代理HTTP请求,我们只需要像调用方法一样调用它就可以完成服务请求及相关处理。Feign整合了Ribbon和Hystrix(关于Hystrix我们后面再讲),可以让我们不再需要显式地使用这两个组件。

  • 总起来说,Feign具有如下特性:
    可插拔的注解支持,包括Feign注解和JAX-RS注解;
    支持可插拔的HTTP编码器和解码器;
    支持Hystrix和它的Fallback;
    支持Ribbon的负载均衡;
    支持HTTP请求和响应的压缩。
    这看起来有点像我们springmvc模式的Controller层的RequestMapping映射。这种模式是我们非常喜欢的。Feign是用@FeignClient来映射服务的。

  • Feign是以接口方式进行调用,而不是通过RestTemplate来调用地址,feign底层还是ribbon,它进行了封装,让我们调用起来更加happy.
    在这里插入图片描述

7.5.2.操作-服务消费者

创建项目user-consumer-feign-5011 (copy) 修改本项目pom.xml <artifactId>

在父亲里面加一个此项目<module>

1)导入jar

替换ribbon jar为feigin
<!--feign的支持-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>

2)配置yml
端口

3)入口类

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients(basePackages = "cn.itsource.client") //如果是主内所在子包,可以不用加basePackages,但是最好加上
public class UserConsumerFeignApp5011 {
    public static void main(String[] args) {
        SpringApplication.run(UserConsumerFeignApp5011.class,args);
    }
}

4)写代码测试

公共代码user-common

jar
<dependencies>
    <!--springboot支持-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
</dependencies>
代码
//调用服务名字
@FeignClient(value = "USER-PROVIDER")
@RequestMapping("/provider")
public interface UserCilent {
    @GetMapping("/user/{id}") //user/1
     User getUser(@PathVariable("id") Long id);
}

注意:要和服务提供者里面访问地址和参数等保持一致。最好拷贝服务提供者的controler来进行修改

代码

@RestController
@RequestMapping("/consumer")
public class UserController {
    @Autowired
    private UserCilent userCilent;
    @RequestMapping("/user/{id}")
    public User getUser(@PathVariable("id")Long id){
        System.out.println(userCilent.getClass());
        return userCilent.getUser(id);
    }
}
7.5.3 Feign的超时配置

如果在服务调用时出现了 “feign.RetryableException : Read timed out…”错误日志,说明Ribbon处理超时 ,我们可以配置Ribbon的超时时间:

ribbon:
    ConnectTimeout: 3000
    ReadTimeout: 6000

如果服务调用出现“com.netflix.hystrix.exception.HystrixRuntimeException:… timed - out and no fallback available” 错误日志,是因为Hystrix超时,默认Feign集成了Hystrix,但是高版本是关闭了Hystrix,我们可以配置Hystrix超时时间:

feign:
   hystrix:
       enabled: true #开启熔断支持hystrix:
  command:
      default:
        execution:
          isolation:
            thread:
              timeoutInMilliseconds: 6000   #hystrix超时时间

测试:
 启动注册中心
 启动服务提供者
 启动服务消费者测试

7.6.小结

当对同一个服务部署多个时,就要涉及负载均衡调用了,这是可以选择Ribbon和Feign。

8.课程总结

8.1.重点

1.微服务架构理解。
2.Springcloud入门
3.负载均衡

8.2.难点

1.微服务架构理解

8.3.如何掌握?

1.多多理解
2.学会看说明手册

8.4.排错技巧(技巧)

1…
2…

9.课后练习

1.总结
2.课堂作业

10.面试题

1.简单说一下微服务架构
2.Dubbo和springcloud的区分
3.Springcloud怎么实现负载均衡

11.扩展知识或课外阅读推荐(可选)

11.1.扩展知识

Dubbo
微服务架构经验和教训

11.2.课外阅读

微服务那点儿事情
https://blog.csdn.net/w05980598/article/details/79007194/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 在Linux中删除镜像的命令是docker rmi。具体的使用方法为: docker rmi [OPTIONS] IMAGE [IMAGE...] 其中,OPTIONS是可选参数,IMAGE是要删除的镜像名称或ID。如果要删除多个镜像,可以在IMAGE后面加上多个镜像名称或ID,用空格隔开。 例如,要删除名称为myimage的镜像,可以使用以下命令: docker rmi myimage 如果要删除多个镜像,可以使用以下命令: docker rmi myimage1 myimage2 myimage3 或者: docker rmi myimage1 myimage2 myimage3 ... 注意,删除镜像时需要先停止使用该镜像的容器,否则会提示“Error response from daemon: conflict: unable to delete”错误。可以使用docker ps命令查看正在运行的容器,然后使用docker stop命令停止容器。 ### 回答2: 在 Linux 中删除镜像的命令是很简单的,用户只需要使用 docker rmi 命令即可完成删除。具体操作步骤如下。 1. 首先需要确定本机上所有的镜像,使用 docker images 命令检查本地的所有镜像情况,如下所示: docker images 这个命令会列出本地所有的仓库镜像,显示格式如下: REPOSITORY TAG IMAGE ID CREATED SIZE ubuntu latest 5e8b97a2a082 11 weeks ago 72.9MB hello-world latest bf756fb1ae65 11 months ago 13.3kB 2. 然后,就可以使用 docker rmi 命令删除不需要的镜像,使用方法如下: docker rmi IMAGE ID 其中,IMAGE ID 参数指定要删除的镜像 ID。 如果要同时删除多个镜像,可以将 ID 放在一个空格中,例如: docker rmi IMAGE ID1 IMAGE ID2 IMAGE ID3 注意,如果试图删除正在使用的镜像,则必须先停止其运行。可以使用 docker stop 命令停止运行的容器,然后再使用 docker rmi 命令删除该镜像。 另外,如果删除的镜像被其他镜像所依赖,则需要先删除那些依赖它的镜像才能删除该镜像。 总之,在使用 docker rmi 删除镜像时,要注意操作的安全性。建议在删除之前再次确认要删除的镜像,以避免误删或者对系统造成损害。 ### 回答3: 在Linux系统中,我们可以使用Docker来创建和部署容器,这个过程中使用的镜像文件可能会变得过时,或者是出现了问题,需要删除掉。那么,怎样才能删除Linux的镜像文件呢? 删除本地镜像的命令非常简单,可以使用下面的命令: docker rmi [镜像名称] 其中,镜像名称可以是完整的镜像ID或者是tag名称。 如果要删除多个镜像,可以在命令中添加多个镜像名称或ID,如下所示: docker rmi [镜像名称1] [镜像名称2] [镜像名称3] 如果要删除所有本地镜像,则可以使用以下命令: docker rmi $(docker images -q) 在删除镜像的过程中,可能会出现一些问题,例如无法删除正在使用的镜像,或者AST 作为部分镜像 ID 的重复 ID 等等。针对这些问题,我们可以进行一些相应的操作来解决。 首先,我们可以尝试强制删除镜像,以此来绕过一些限制。使用以下命令: docker rmi -f [镜像名称] 此命令将忽略镜像的标记,并删除所有标记,只留下完整的镜像ID。 如果需要删除正在使用的镜像,则需要先将容器停止并删除,然后再删除镜像。使用以下命令: docker stop [容器名称或ID] docker rm [容器名称或ID] docker rmi [镜像名称] 如果您希望删除所有停止的容器,可以使用以下命令: docker container prune 在删除镜像的过程中,可能会出现一些重复的镜像ID。可以使用以下命令将它们删除: docker images | grep "^[^<]\{3\} \|\<none\>\|" | awk '{print $3}' | xargs docker rmi 使用上述命令,将首先显示与正常镜像不同的垃圾数据和标签,然后将使用awk和xargs删除ID。此命令可以删除所有空的、垃圾的和无用的镜像。 总体而言,删除Linux镜像的命令非常简单,只需要使用docker rmi命令即可。需要注意的是,删除镜像前必须先停止镜像相关的容器,否则将无法删除。在删除镜像的过程中,也有可能会出现一些问题,可以根据情况进行相应的操作来解决。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值