草庐IT

【K8S系列】第七讲:有状态服务 VS 无状态服务

颜淡慕潇 2023-05-10 原文

目录

序言: 

1.无状态服务介绍

2 有状态服务介绍

2.1 稳定的网络标识

2.2  稳定持久化存储

3 总结


序言: 

昨天有位大佬,问这个问题

   

 ………………………………………………

 

决定学习之后,有了这篇文章.

1.无状态服务介绍

1.数据方面:无状态服务不会在本地存储持久化数据.多个实例可以共享相同的持久化数据

2.结果方面:多个服务实例对于同一个用户请求的响应结果是完全一致

3.关系方面:这种多服务实例之间是没有依赖关系

4.影响方面:在k8s控制器 中动态启停无状态服务的pod并不会对其它的pod产生影响

5.示例方面:nginx实例,tomcat实例,web应用

6.资源方面:相关的k8s资源有:ReplicaSet、ReplicationController、Deployment

7.创建方式:Deployment被设计用来管理无状态服务的pod

每个pod完全一致,原因如下:

  • 无状态服务内的多个Pod创建的顺序是没有顺序
  • 无状态服务内的多个Pod的名称是随机的.pod被重新启动调度后,它的名称与IP都会发生变化
  • 无状态服务内的多个Pod背后是共享存储的

8.缩容方式:随机缩容

        由于是无状态服务,所以这些控制器创建的pod序号都是随机值。并且在缩容也是随机,并不会明确缩容某一个pod。因为所有实例得到的返回值都是一样,所以缩容任何一个pod都可以

2 有状态服务介绍

1.数据方面:有状态服务需要在本地存储持久化数据,典型的是分布式数据库的应

2.结果方面:实例之间,请求结果可能存在不一致

3.关系方面:分布式节点实例之间有依赖的拓扑关系.比如,主从关系.

4.影响方面:如果K8S停止分布式集群中任 一实例pod,就可能会导致数据丢失或者集群的crash

5.示例方面:mysql数据库、kafka、zookeeper、Redis主从架构

6.资源方面:statefulSet

7.创建方式:statefulSet管理

    Pod的特点

  • 唯一性: 每个Pod会被分配一个唯一序号
  • 顺序性: Pod启动,更新,销毁是线性的,按顺序进行
  • 稳定的网络标识: Pod主机名,DNS地址不会随着Pod被重新调度而发生变化.
  • 稳定的持久化存储: Pod被重新调度后,仍然能挂载原有的PV,从而保证了数据的完整性和一致性.

8.缩容方式:有顺序的缩容

        StatefulSet 缩容只会操作 一个 pod 实例,因此有状态应用的缩容相对于无状态的缩容速度会慢。

举例来说, 一个分布式存储应用若同时下线多个节点 ,则可能导致其数据丢失

比如说,一个数据项副本数设置为 2 的数据存储应用, 若同时有两个节点下线,如果一份数据它正好保存在这两个节点上,这份数据就会丢失

因此缩容是线性的 ,则分布式存储应用需要时间把丢失的副本复制到其他节点 ,从而保证数据不会丢失。其实,这也是第七点中所讲的顺序性。

2.1 稳定的网络标识

如何理解稳定的网络标识?以redis为例:可以这样理解:

例如:需要创建名为test-redis-podStateful模型,

根据配置的Replica=3的设置,K8S会创建三个Pod,依次命名为:

  1. test-redis-pod-0
  2. test-redis-pod-1
  3. test-redis-pod-2

K8S为有状态的服务Pod分配稳定的网络标识,具体实现基于test-redis-pod-0名称,借助Headless DNS进行如下解析,获取后端其中一个Pod的地址.

$(pod name).$(service name).$(namespace).svc.cluster.local

下面通过Pod名称访问Redis集群的Master节点地址的方法.

session.save_path = "tcp://test-redis-pod-0.test-redis-service.default.svc.cluster.local:6379"

在Redis Pod内部,主从节点之间数据同步的需求,Slave节点对应的配置文件中需要一个稳定的Master地址.

下边脚本通过稳定访问test-redis-pod-0 名称来间接获得Redis Master节点IP地址,

然后写入到Redis Slave的配置文件中,这样后续Slave节点与Master节点可以完成增量数据的同步.

if [ "${server_host}" != "test-redis-pod-0" ];then
        #echo "server-count: ${server_counts}" >> /data/redistest.log

        while [ -z "${master_address}" ];do
            echo "master_address is not available, ${master_address} waiting for redis master..." >> /data/redistest.log
            master_address=$(replication_master_address)
            sleep 1s
        done
    fi

    echo "master_address: $(master_address)" >> /data/redistest.log
    if [ ! -z "$master_address" ]; then
        printf "\nslaveof %s 6379\n" "$master_address" >> $conf
    fi

在Redis Pod外部, 可以这样来访问具体的Pod服务.

$(pod name).$(service name).$(namespace).svc.cluster.local

2.2  稳定持久化存储

如何理解稳定的持久化存储,可以参考下图:

如图:

1.唯一:每个Redis Pod对应一个PVC/PV.当Pod发生调度时,需要在别的节点启动时,根据Pod背后关联的存储信息,可以保证其名称的稳定性.

2.复用Pod还是会attach挂载到原来的PV/PVC中,从而确定每个Pod有自己专用的存储卷.

3 总结

主要介绍了无状态和有状态服务的基础概念,从八个方面介绍了两者的区别,

并以redis集群为例,详细讲解了稳定的网络标识和稳定的持久化存储

  

介绍了:

  • Deployment部署无状态服务
  • Stateful新的部署组件.

  

Stateful 主要是通过支持Pod一些特性

  • 名称唯一性
  • 稳定的网络标识
  • 稳定的持久化存储

  

从而实现在K8S中部署运维有状态服务

有关【K8S系列】第七讲:有状态服务 VS 无状态服务的更多相关文章

  1. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  2. ruby - 在 Ruby 程序执行时阻止 Windows 7 PC 进入休眠状态 - 2

    我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0

  3. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  4. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

    我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

  5. ruby-on-rails - Railstutorial : db:populate vs. 工厂女孩 - 2

    在railstutorial中,作者为什么选择使用这个(代码list10.25):http://ruby.railstutorial.org/chapters/updating-showing-and-deleting-usersnamespace:dbdodesc"Filldatabasewithsampledata"task:populate=>:environmentdoRake::Task['db:reset'].invokeUser.create!(:name=>"ExampleUser",:email=>"example@railstutorial.org",:passwo

  6. ruby-on-rails - 使用一系列等级计算字母等级 - 2

    这里是Ruby新手。完成一些练习后碰壁了。练习:计算一系列成绩的字母等级创建一个方法get_grade来接受测试分数数组。数组中的每个分数应介于0和100之间,其中100是最大分数。计算平均分并将字母等级作为字符串返回,即“A”、“B”、“C”、“D”、“E”或“F”。我一直返回错误:avg.rb:1:syntaxerror,unexpectedtLBRACK,expecting')'defget_grade([100,90,80])^avg.rb:1:syntaxerror,unexpected')',expecting$end这是我目前所拥有的。我想坚持使用下面的方法或.join,

  7. ruby-on-rails - 启动 Rails 服务器时 ImageMagick 的警告 - 2

    最近,当我启动我的Rails服务器时,我收到了一长串警告。虽然它不影响我的应用程序,但我想知道如何解决这些警告。我的估计是imagemagick以某种方式被调用了两次?当我在警告前后检查我的git日志时。我想知道如何解决这个问题。-bcrypt-ruby(3.1.2)-better_errors(1.0.1)+bcrypt(3.1.7)+bcrypt-ruby(3.1.5)-bcrypt(>=3.1.3)+better_errors(1.1.0)bcrypt和imagemagick有关系吗?/Users/rbchris/.rbenv/versions/2.0.0-p247/lib/ru

  8. ruby-on-rails - s3_direct_upload 在生产服务器中不工作 - 2

    在Rails4.0.2中,我使用s3_direct_upload和aws-sdkgems直接为s3存储桶上传文件。在开发环境中它工作正常,但在生产环境中它会抛出如下错误,ActionView::Template::Error(noimplicitconversionofnilintoString)在View中,create_cv_url,:id=>"s3_uploader",:key=>"cv_uploads/{unique_id}/${filename}",:key_starts_with=>"cv_uploads/",:callback_param=>"cv[direct_uplo

  9. ruby-on-rails - 跳过状态机方法的所有验证 - 2

    当我的预订模型通过rake任务在状态机上转换时,我试图找出如何跳过对ActiveRecord对象的特定实例的验证。我想在reservation.close时跳过所有验证!叫做。希望调用reservation.close!(:validate=>false)之类的东西。仅供引用,我们正在使用https://github.com/pluginaweek/state_machine用于状态机。这是我的预订模型的示例。classReservation["requested","negotiating","approved"])}state_machine:initial=>'requested

  10. ruby - 用 Ruby 编写一个简单的网络服务器 - 2

    我想在Ruby中创建一个用于开发目的的极其简单的Web服务器(不,不想使用现成的解决方案)。代码如下:#!/usr/bin/rubyrequire'socket'server=TCPServer.new('127.0.0.1',8080)whileconnection=server.acceptheaders=[]length=0whileline=connection.getsheaders想法是从命令行运行这个脚本,提供另一个脚本,它将在其标准输入上获取请求,并在其标准输出上返回完整的响应。到目前为止一切顺利,但事实证明这真的很脆弱,因为它在第二个请求上中断并出现错误:/usr/b

随机推荐