网站首页 包含标签 技术笔记 的所有文章

  • 一致性hash算法作用是什么

    一致性哈希(Consistent Hashing)算法,乍一听大家可能觉得这是高大上的技术名词,但其实它在分布式系统中无疑是个解决大难题的土方法,就像是中国的传统医术在现代仍能医治各种疑难杂症一样。 这个算法自从 1997 年由麻省理工学院的博士生提出后,就在分布式系统中扮演着至关重要的角色。一致性哈希算法在分布式系统中的地位可比咱们生活中的在线记账软件,解决了数据存放位置的大问题。 传统的哈希算法在节点增减时面临着数据重新分配的巨大代价,就像如果你用纸质的账本,每次账目中间有变动(比如,中间有几天忘了记账)时都得整本重写一遍,想想都头疼。而一致性哈希通过精妙地圆环结构使得节点变动只影响邻近的一小部分数据,大大降低了系统维护的复杂度。 说到一致性哈希算法的基本概念,想象我们有一张圆桌,桌面上标着从 0 到 2^32(假设用的是 32 位的哈希函数)的数字,形成一个闭环: 每当有个新服务器来了,我们就给它一个或多个哈希值,让它在这张圆桌的某个地方坐下 每次我们有数据要存储时,就按照数据的哈希值找到在此值之后的第一个服务器,把数据放在那儿 如果这个服务器忙碌了,它会找一个最近的邻居节点来帮助存储数据 这样,每当服务器来来去去时,我们只需要重新调整它们附近的数据即可 这个算法的魅力在于,不管你的网络多么巨大,每次添加或删除一个节点,都只涉及到节点旁边的一小部分数据,而不是整个网络。 这就像在一个巨大的停车场里找车位,即便是一个区域的停车位满了,你也不用担心其他地区的车位会被迁移。 当然,这个算法也有它的缺点。有时候,所有人似乎都想停在同一个车位上,这就造成了负载不均,即哈希环倾斜的情况。 这时,你可能需要一些“虚拟车位”,也即是虚拟节点,让这个停车场的车辆更加均匀地分布。 这种情况我们可以这么理解:项目中某个区域的缓存快满了怎么办? 那就是加新节点! 为了让缓存数据均匀分布,我们通常会采用哈希后取模的方式来确定数据归属的节点。 而在加减节点的过程中,一致性哈希算法可以保证大多数 key 照旧停留在原有的车位上,而不需要把整个车场的车全部重新停一遍。 ...

    2024-01-05 技术教程 231
  • 系统设计-如何做到高可用、高吞吐、高扩展性

    我们经常需要设计具有高可用性、高可扩展性和高吞吐量的系统。它们的确切含义是什么? 下图是一份系统设计小抄,包含“三高”常见的解决方案。 1、高可用性 高可用意味着我们需要达到一个高水平的正常运行时间。我们通常将设计目标描述为 “3 个 9 ” 或 “4 个 9″。”4 个九”,即 99.99% 的正常运行时间,意味着服务每天只能中断 8.64 秒。 要实现高可用性,我们需要在系统中设计冗余。有几种方法可以做到这一点: Hot-Hot 两个实例接收相同的输入,并将输出发送到下游服务。如果其中一方宕机,另一方可以立即接替。由于两边都向下游发送输出,下游系统需要能够处理重复数据。 Hot-Warm 两个实例接收相同的输入,只有 Hot 端向下游服务发送输出。如果 Hot 端宕机, Warm 端将接替并开始向下游服务发送输出。 单领导集群 (Single Leader) 一个领导实例从上游系统接收数据并复制到其他副本。 无领导集群 (Leaderless) 这种集群中没有领导者。任何写入都会复制到其他实例。只要写入实例数加上读取实例数大于实例总数,我们就能获得有效数据。这被称为 quorum。 2、高吞吐量 这意味着服务需要在一段时间内处理大量请求。常用的指标是 QPS(每秒查询次数)或 TPS(每秒事务次数)。 为了实现高吞吐量,我们通常会在架构中添加缓存,以避免经过数据库或磁盘等较慢的 I/O 设备。我们还可以为计算密集型任务增加线程数量。但是,增加过多的线程会降低性能。因此,我们需要找出系统的瓶颈,提高系统的吞吐量。 我们还可以在系统中使用异步处理,以有效地单独隔离耗时耗资源的组件。 3、高扩展性 高扩展性意味着系统可以快速、轻松地扩展,以容纳更多的容量(横向可扩展性)或更多的功能(纵向可扩展性)。通常,我们通过观察响应时间来决定是否需要扩展系统。 要实现高度可扩展性,需要隔离每个服务的职责。为此,微服务被广泛采用。我们还利用服务注册和负载平衡器将请求路由到适当的实例。 ...

    2023-12-22 198
  • 什么是DevOps和NoOps

    DevOps和NoOps是如何改变软件开发生命周期(SDLC)的? 下图比较了传统 SDLC、DevOps 和 NoOps。 在传统的软件开发中,开发、编译打包、测试、发布和监控是孤立的功能。 每个阶段都独立工作,然后移交给下一个阶段。 而 DevOps 鼓励持续开发以及开发人员和运营人员之间的协作。 这缩短了整个生命周期,提供了持续高质量的软件交付。 NoOps 是随着无服务器计算(Serverless)的发展而出现的新概念。由于我们可以使用 FaaS(Function-as-a-Service,函数即服务)和 BaaS(Backend-as-a-Service,后端即服务)来架构系统,因此云服务提供商可以承担大部分运营任务。开发人员可以专注于功能开发,并自动执行运维操作任务。 对于初创企业或较小规模的应用程序来说,NoOps 是一种务实有效的方法,它比 DevOps 更能缩短 SDLC。 ...

    2023-12-22 173
  • 什么是缓存,策略有哪些?

    什么是缓存? 缓存就像是一个超快速的存储区域,保存了计算机或手机经常使用的内容的副本,这样可以在不访问较慢的主存储器的情况下快速获取。 一个现实中的例子可以是,每当我们购买杂货时,通常会倾向于大量购买,这样可以让杂货多存放一段时间,避免频繁去市场购买,这其实就是将杂货缓存在我们附近,而不是每次都从市场购买。 在系统设计中,如果缓存得当,它可以显著提升系统的性能。 缓存策略取决于数据访问模式,即数据是如何读取或写入的。 例如: 系统是读取密集型还是写入密集型? 系统是否需要高一致性? 等等…… 因此,选择正确的写入缓存策略非常关键,下面是一些不同的缓存策略: 1. 缓存旁路(懒加载) 在这种设置中,应用程序缓存被分离出来,应用程序显式地与缓存和数据库一起工作。 这是一种技术,应用程序代码负责管理缓存。 当需要时,应用程序会将数据显式加载到缓存中,而缓存不会主动参与数据获取。 该图示了其工作原理。 使用场景: 适用于读取密集型系统,Redis 或 Memcached 非常受欢迎,我曾经在缓存旁路设置中使用过 Redis 以及 Mongo-db,效果非常显著。 这种读取技术可以与诸如写入旁路缓存之类的数据写入技术相结合,我接下来会解释。 优点: 灵活性:允许选择性缓存特定数据。 控制:应用程序控制数据何时加载到缓存中。 缺点: 提供过期数据:可能会提供过期数据,但如果我们实现了缓存的TTL(生存时间),则可以避免这种情况。 2. 写入旁路 跳过缓存,直接将数据写入数据库,并在读取用户请求的数据时更新缓存。 使用场景: 写入旁路可以与读取通过结合,对于数据写入一次,读取频率较低或几乎不读取的情况下提供良好的性能,例如实时日志或聊天室消息。 同样,这种模式也可以与缓存旁路结合使用。 3. 读取穿透缓存 读取穿透缓存是一种策略,当发生缓存未命中时,缓存会自动从底层数据源检索数据并填充自身。 这种技术与应用程序的数据访问层无缝集成,确保缓存与数据源保持同步。 使用场景、优点和缺点: 读取穿透缓存适用于读取密集的工作负载,当同一数据被多次请求时,例如,一个新博客。 缺点是,当首次请求数据时,总是会导致缓存未命中,并造成额外的数据加载开销。 4. 写入穿透缓存 写入穿透缓存是一种策略,其中写操作同时应用于缓存和底层数据源。 这确保了缓存和数据源保持同步,但与写入后缓存相比可能会引入额外的延迟,它同步应用更新。 使用场景、优点和缺点: 当与读取穿透缓存结合时,写入穿透缓存可以保证每次读取和写入的数据一致性。 但它会增加写操作的额外开销,因为每次写入都需要两次写入操作(缓存和数据库)。 它以异步方式应用更新。 5. 写入后缓存 写入后缓存,也称为写回缓存,涉及在写操作发生时延迟对数据源的更新。 系统不会立即更新底层存储,而是首先更新缓存,然后异步将更改传播到数据源。 使用场景、优点和缺点: 写回缓存提高了写入性能,非常适用于写入密集型任务。 当与读取穿透结合时,适用于混合工作负载,确保最近的数据可用。 ...

    2023-12-22 141
  • HTTP报文格式详解

    HTTP报文分为请求报文和响应报文来说明。 请求报文 请求行:包含请求方法、请求目标(URL或URI)和HTTP协议版本。 请求头部:包含关于请求的附加信息,如Host、User-Agent、Content-Type等。 空行:请求头部和请求体之间用空行分隔。 请求体:可选,包含请求的数据,通常用于POST请求等需要传输数据的情况。 响应报文 状态行:包含HTTP协议版本、状态码和状态信息。 响应头部:包含关于响应的附加信息,如Content-Type、Content-Length等。 空行:响应头部和响应体之间用空行分隔。 响应体:包含响应的数据,通常是服务器返回的HTML、JSON等内容。 ...

    2023-12-18 202
  • 什么是Tomcat,安装及配置教程

    1、Tomcat 介绍 什么是 Tomcat Tomcat 是 Apache 软件基金会一个核心项目,是一个开源免费的轻量级 web 服务器,支持 Servlet / jsp 少量JavaEE规范,Tomcat 也被称为 Web 容器、Servlet 容器。 官网:https://tomcat.apache.org/ 什么是 JavaEE JavaEE:Java Enterprise Edition,Java 企业版。指 Java 企业级开发的技术规范总和。 包含 13 项技术规范:JDBC、JNDI、EJB、RMI、JSP、Servlet、XML、JMS、Java IDL、JTS、JTA、JavaMail、JAF 2、Tomcat 使用配置 2.1、Tomcat 下载启动 Tomcat 下载安装 下载:https://tomcat.apache.org/ 安装:Tomcat 是绿色版,直接解压就可以了,建议:不要有中文的目录,目录层次不要太深 打开apache-tomcat目录就能看到如下目录结构,每个目录中包含的内容需要认识下 Tomcat 启动关闭 启动:双击:bin\startup.bat 关闭 直接 x 掉运行窗口:强制关闭 bin\shutdown.bat:正常关闭 ctrl+c:正常关闭 Tomcat 访问 访问方式:浏览器输入localhost:8080,Tomcat 默认端口是 8080 2.2、Tomcat 启动乱码 问题 控制台有中文乱码,需要修改 conf/logging.prooperties 进入 Tomcat 的 conf 目录 找到 logging.properties 文件 将里面所有的 UTF-8 替换成 GBK 注意:建议使用 Vscode 打开或者其他工具,直接查找替换,避免发生错误 2.3、Tomcat 端口号修改 进入 Tomcat 的 conf 目录下 找到 server.xml 文件,打开 找到下列代码位置,大概在 69 行,修改 port=你想要的位置 <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> 端口号冲突 3、Tomcat 项目部署 项目部署的两种方法 直接将项目复制到 webapps 目录下 采用压缩文件.war 的方式 将整个项目使用压缩工具打包成 zip 文件 改 zip 的扩展名为 war 复制到 webapps 目录下,tomcat 会自动解压成一个同名的目录 注意:里面的文件不能有中文名 部署演示:直接将项目复制到 webapps 目录下 项目名为:hello,将其文件复制到 webapps 目录下 启动 Tomcat 后,访问 hello 部署演示:采用压缩文件.war 的方式 将项目压缩成 zip 文件 改 zip 的扩展名为 war 复制到 webapps 目录下,tomcat 会自动解压成一个同名的目录 访问测试 4、IDEA 中使用 Tomcat 方式 通过 Maven 的 package 命令可以将项目打包成 war 包,将 war 文件拷贝到 Tomcat 的 webapps 目录下,启动 Tomcat 就可以将项目部署成功,然后通过浏览器进行访问即可。 然而我们在开发的过程中,项目中的内容会经常发生变化,如果按照上面这种方式来部署测试,是非常不方便的 如何在 IDEA 中能快速使用 Tomcat 呢? 将本地 Tomcat 集成到 IDEA 中 打开添加本地 Tomcat 的面板 指定本地 Tomcat 配置本地 Tomcat 将项目部署到集成 Tomcat 里面 扩展内容:xxx.war 和 xxx.war exploded 这两种部署项目模式的区别? war 模式是将 WEB 工程打成 war 包,把 war 包发布到 Tomcat 服务器上 war exploded 模式是将 WEB 工程以当前文件夹的位置关系发布到 Tomcat 服务器上 war 模式部署成功后,Tomcat 的 webapps 目录下会有部署的项目内容 war exploded 模式部署成功后,Tomcat 的 webapps 目录下没有,而使用的是项目的 target 目录下的内容进行部署 建议大家都选 war 模式进行部署,更符合项目部署的实际情况 ...

    2023-12-18 340
  • 如何设计安全的API调用

    如何为网站设计安全的API访问? 我们在设计一个网站或平台的时候,经常需要向用户开放API访问。 这样用户就可以程序化地调用一些功能,举几个例子: 交易所开放API让用户可以进行低时延的程序化交易, 微信公众号平台开放API让三方工具进行运营管理工作, Stripe开放API让商家和其他平台能很好地集成支付功能。 当我们向用户开放API访问时,我们需要确保每次API调用都经过鉴权。 这意味着我们需要确认用户是他们所声称的身份。 我们一般使用两种常见的方法来进行鉴权: 基于令牌的身份验证 HMAC(基于哈希的消息验证码)验证 下图说明了它们的工作原理。 1、基于令牌 第1步 用户在客户端输入密码,然后客户端将密码发送到鉴权服务器。 第2步 鉴权服务器验证密码并生成一个有有效期的令牌。 第3步和第4步 现在,客户端可以发送请求,使用HTTP头中带有的令牌访问服务器资源。 这种访问在令牌过期前一直有效。 2、基于 HMAC 这种机制通过使用哈希函数(SHA256 或 MD5)生成消息验证码(签名)。 第1步和第2步 服务器生成两个密钥,一个是公共APP ID(公钥),另一个是 API Key(私钥)。 第3步 现在我们在客户端生成一个HMAC 签名(hmac A),该签名是根据图中列出的一组字段生成的。 注意这里会加入请求的时间戳,这样一个HMAC签名是有有效期的,不会一直有效。 第4步 客户端发送请求来访问服务器资源,HTTP头中包含hmac A。 第5步 服务器收到包含请求数据和鉴权标头的请求。 它从请求中提取必要的字段,并使用存储在服务器端的API Key 生成签名(hmac B)。 第6步和第7步 服务器会比较hmac A(在客户端生成)和hmac B(在服务器端生成)。 如果两者匹配,请求的资源将返回给客户端。 ...

    2023-12-13 243
  • Windows【自动配置IPv4地址】的问题

    问题描述: Windows电脑的网卡明明已经配置了静态的IP地址,但是还会出现自动配置IPv4地址的情况。 解决方法: 这个问题大部分是地址冲突导致的,还有一种可能就是网卡默认配置。 地址冲突解决办法:修改本机电脑的IP地址,或者找到冲突的设备修改它的IP。 网卡默认配置解决方法:管理员运行CMD,输入netsh winsock reset catalog按回车、输入netsh int ip reset reset.log按回车,然后就能配置地址、掩码、网关了。 小知识: 【169.254.×.×】这个是广播地址不是正常获取到的IP地址。 ...

    2023-11-19 208
  • ping和telnet有什么区别

    Ping和Telnet有什么区别 ping 是ICMP协议,只包含控制信息没有端口;telnet是TCP协议,有端口能承载数据; 不能telnet并不代表不能ping, 这是两种不同的数据包, 防火墙可以设置哪种数据包可以通过; 能telnet通,但是不能ping通,有可能是对方主机关闭了ping回显或者是对方防火墙阻止了ping发送的数据包; 如果别人不能telnet本机,最简单的测试办法是:telnet 127.0.0.1 如果失败说明本机的telnet服务没有开启,如果成功说明本机防火墙做了限制; Ping和Telnet的界面 下边这张图是使用了ping和telnet两个命令的效果图,可以看出使用ping更多返回的是对方机器的数据包,延时这类信息。 而使用telnet则是尝试远程连接对方的服务,所以两者其实还是有很明显的本质区别。 小结 ping是icmp探查消息,用于确定两个ip端点的网络层导通性。 telnet是一种远程登录软件工具,是运行在tcp层,使用23端口。 一般计算机部署的时候都会关闭掉telnet端口,以保证安全性,如果真的需要进行远程连接的话,建议使用ssh的方式去访问。 ...

    2023-11-13 225
  • Ceph中创建和管理自定义CRUSH Map笔记整理

    管理和定制CRUSH Map CRUSH和目标放置策略 Ceph 通过一种称为 CRUSH(可伸缩哈希下的受控复制)的放置算法来计算哪些osd应该持有哪些对象,对象被分配到放置组(pg), CRUSH 决定这些 放置组 应该使用哪个 osd来存储它们的对象,即 crush 决定了 pg 到 osd 的映射关系。 CRUSH的算法 CRUSH算法 使 Ceph客户端能够直接与 osd通信,这避免了集中式服务瓶颈,Ceph客户端和 osd使用CRUSH 算法高效地计算对象位置的信息,而不是依赖于一个中央查找表。 Ceph 客户端检索集群映射,并使用 CRUSH Map 从算法上确定如何存储和检索数据,通过避免单点故障和性能瓶颈,这为Ceph 集群提供了大规模的可伸缩性 CRUSH算法 的作用是将 数据统一分布在对象存储中,管理复制,并响应系统增长和硬件故障,当 新增OSD或已有OSD或OSD主机故障 时,Ceph通过CRUSH在主OSD间实现集群对象的再平衡 CRUSH Map 组件 从概念上讲,一个CRUSH map包含两个主要组件: CRUSH层次结构 这将列出所有可用的 osd,并将它们组织成树状的桶结构 CRUSH层次结构通常用来表示osd的位置,默认情况下,有一个root桶代表整个层次结构,其中包含每个OSD主机的一个主机桶 [root@clienta ~]# ceph osd tree ID CLASS WEIGHT TYPE NAME STATUS REWEIGHT PRI-AFF -1 0.09796 root default -3 0.03918 host serverc 0 hdd 0.00980 osd.0 up 1.00000 1.00000 1 hdd 0.00980 osd.1 up 1.00000 1.00000 2 hdd 0.00980 osd.2 up 1.00000 1.00000 9 hdd 0.00980 osd.9 up 1.00000 1.00000 -5 0.02939 host serverd 3 hdd 0.00980 osd.3 up 1.00000 1.00000 4 hdd 0.00980 osd.4 up 1.00000 1.00000 5 hdd 0.00980 osd.5 up 1.00000 1.00000 -7 0.02939 host servere 6 hdd 0.00980 osd.6 up 1.00000 1.00000 7 hdd 0.00980 osd.7 up 1.00000 1.00000 8 hdd 0.00980 osd.8 up 1.00000 1.00000 OSD是树的叶子节点,默认情况下,同一个OSD主机上的所有OSD都放在该主机的桶中,可以自定义树状结构,重新排列,增加层次,将OSD主机分组到不同的桶中,表示其在不同的服务器机架或数据中心的位置 至少有一条CRUSH规则 CRUSH 规则决定了如何从这些桶中分配放置组的osd,这决定了这些放置组的对象的存储位置。不同的池可能会使用不同的CRUSH规则 CRUSH  桶类型 CRUSH 层次结构将 osd 组织成一个由不同容器组成的树,称为桶。对于大型安装,可以创建特定的层次结构来描述存储基础设施:数据中心、机架、主机和OSD设备。 通过创建一个CRUSH map规则,可以使 Ceph 将一个对象的副本放在独立服务器上的osd上,放在不同机架的服务器上,甚至放在不同数据中心的服务器上 总而言之,桶是 CRUSH层次结构中的容器或分支。osd设备是CRUSH等级中的叶子 一些最重要的桶属性有: 桶ID,这些id为负数,以便与存储设备的id区分开来 桶的名称 桶的类型,默认映射定义了几种类型,可以使用ceph osd crush dump命令检索这些类型 [root@clienta ~]# ceph osd crush dump | grep type_name "type_name": "root", "type_name": "root", "type_name": "host", "type_name": "host", "type_name": "host", "type_name": "host", "type_name": "host", "type_name": "host", 桶类型包括root、region、datacenter、room、pod、pdu、row、rack、chassis和host,但你也可以添加自己的类型、位于层次结构根的桶属于根类型 Ceph 在将 PG 副本映射到 osd 时选择桶内物品的算法。有几种算法可用:uniform、list、tree和straw2。每种算法都代表了性能和重组效率之间的权衡。缺省算法为straw2 Uniform(均等分配):Uniform 算法简单地将数据均匀地分配给存储集群中的 OSD(Object Storage Device)。优点是实现简单,能够提供基本的负载均衡效果。然而,它无法考虑 OSD 的实际负载情况,可能导致一些 OSD 负载过高而其他 OSD 负载较轻。 List(列表调度):List 算法根据预定义的 OSD 列表顺序来分配数据。优点是可以根据需求灵活地配置 OSD 列表,适用于特定的负载均衡需求。然而,如果 OSD 列表中的 OSD 负载不均匀,可能导致一些 OSD 过载而其他 OSD 闲置。 Tree(树状调度):Tree 算法使用树状结构来分配数据,将数据在多个层级的 OSD 中进行选择。优点是可以根据 OSD 的性能和负载情况进行智能调度,将数据分配给性能较好的 OSD。然而,实现相对复杂,需要维护和调整树状结构,适用于较大规模的负载均衡场景。 Straw2(稻草算法):Straw2 算法考虑了 OSD 的负载和权重指标,并根据这些指标计算出一个权重值,然后根据权重值来分配数据。优点是可以根据 OSD 的实时负载情况进行智能调度,将数据分配给负载较轻的 OSD。然而,计算权重值需要一定的计算资源,且可能导致数据在短时间内频繁迁移。 自定义故障和性能域 CRUSH 映射是 CRUSH算法 的 中心配置机制,可以编辑此 map 以影响数据放置并自定义CRUSH算法 配置 CRUSH 映射和创建单独的 故障域 允许 osd 和集群节点发生故障,而不会发生任何数据丢失。在问题解决之前,集群只是以降级状态运行 配置 CRUSH Map并创建单独的性能域可以减少使用集群存储和检索数据的客户机和应用程序的性能瓶颈。 定制  CRUSH Map 的典型用例 针对 硬件故障 提供额外的保护。可以配置 CRUSH Map 以匹配底层物理基础设施,这有助于减轻硬件故障的影响 默认情况下,CRUSH算法将复制的对象放置在不同主机上的osd上。可以定制CRUSH map,这样对象副本就可以跨osd放置在不同的架子上,或者放置在不同房间的主机上,或者放置在具有不同电源的不同架子上 将带有 SSD驱动器的 osd  分配给需要快速存储的应用程序使用的池,而将带有传统hdd的osd分配给支持要求较低的工作负载的池 CRUSH map可以包含多个层次结构,你可以通过不同的CRUSH规则进行选择。通过使用单独的 CRUSH 层次结构,可以建立单独的性能域。例如,CRUSH 可以为 hdd 创建一个层次结构,为 ssd 创建另一个层次结构 配置单独性能域的用例示例如下: 分离虚拟机使用的块存储和应用使用的对象存储 将包含不经常访问的数据的“冷”存储区与包含经常访问的数据的“热”存储区分开 一个实际的CRUSH map定义,它包含: 所有可用物理存储设备的列表 所有基础设施桶的列表,以及每个桶中存储设备或其他桶的id。请记住,bucket是基础结构树中的容器或分支,例如,它可能表示一个位置或一块物理硬件 将pg映射到osd的CRUSH规则列表 其他CRUSH可调参数及其设置的列表 集群安装过程部署一个默认的CRUSH映射,可以使用ceph osd crush dump命令打印JSON格式的crush map。你也可以导出映射的二进制副本,并将其反编译为文本文件: [ceph: root@node /]# ceph osd getcrushmap -o ./map.bin [ceph: root@node /]# crushtool -d ./map.bin -o ./map.txt 自定义OSD CRUSH设置 CRUSH Map包含集群中所有存储设备的列表。对于每台存储设备,已获取如下信息: 存储设备的ID 存储设备的名称 存储设备的权重,通常以tb为单位。 例如,4tb的存储设备重量约为4.0。这是设备可以存储的相对数据量,CRUSH算法使用这一数据来帮助确保对象的均匀分布 host serverc { id -3 # do not change unnecessarily id -4 class hdd # do not change unnecessarily # weight 0.039 alg straw2 hash 0 # rjenkins1 item osd.0 weight 0.010 item osd.1 weight 0.010 item osd.2 weight 0.010 item osd.9 weight 0.010 } 可以通过ceph osd crush reweight命令设置OSD的权重。CRUSH的树桶权重应该等于它们的叶子权重的总和。 如果手动编辑 CRUSH Map权重,那么应该执行以下命令来确保CRUSH树桶的权重准确地反映了桶内叶片osd的总和 [ceph: root@node /)# ceph osd crush reweight-all reweighted crush hierarchy 存储设备的类别,存储集群支持多种存储设备,如hdd、ssd、NVMe ssd等。 存储设备的类反映了这些信息,可以使用这些信息创建针对不同应用程序工作负载优化的池。osd自动检测和设置它们的设备类。ceph osd crush set-device-class命令用于显式设置OSD的设备类。 使用ceph osd crush rm device-class 从 osd 中删除一个设备类 ceph osd crush tree命令显示crush map当前的层级: [ceph: root@clienta /]# ceph osd crush tree ID CLASS WEIGHT TYPE NAME -1 0.08817 root default -3 0.02939 host serverc 0 hdd 0.00980 osd.0 1 hdd 0.00980 osd.1 2 hdd 0.00980 osd.2 。 -5 0.02939 host serverd 3 hdd 0.00980 osd.3 5 hdd 0.00980 osd.5 7 hdd 0.00980 osd.7 -7 0.02939 host servere 4 hdd 0.00980 osd.4 6 hdd 0.00980 osd.6 8 hdd 0.00980 osd.8 设备类是通过为每个正在使用的设备类创建一个“影子”CRUSH层次结构来实现的,它只包含该类设备。 然后,CRUSH规则可以在影子层次结构上分发数据。 你可以使用ceph osd crush tree –show-shadow命令查看带有影子的crush 层级` [ceph: root@serverc /]# ceph osd crush tree --show-shadow ID CLASS WEIGHT TYPE NAME -2 hdd 0.09796 root default~hdd -4 hdd 0.03918 host serverc~hdd 0 hdd 0.00980 osd.0 1 hdd 0.00980 osd.1 2 hdd 0.00980 osd.2 9 hdd 0.00980 osd.9 -6 hdd 0.02939 host serverd~hdd 3 hdd 0.00980 osd.3 4 hdd 0.00980 osd.4 5 hdd 0.00980 osd.5 -8 hdd 0.02939 host servere~hdd 6 hdd 0.00980 osd.6 7 hdd 0.00980 osd.7 8 hdd 0.00980 osd.8 使用ceph osd crush class create 命令创建一个新的设备类 使用ceph osd crush class rm 命令删除一个设备类 使用ceph osd crush class ls 命令列出已配置的设备类 [ceph: root@serverc /]# ceph osd crush class ls [ "hdd" ] [ceph: root@serverc /]# ceph osd crush class create ssd created class ssd with id 1 to crush map [ceph: root@serverc /]# ceph osd crush class ls [ "hdd", "ssd" ] [ceph: root@serverc /]# ceph osd crush class rm ssd removed class ssd with id 1 from crush map [ceph: root@serverc /]# ceph osd crush class ls [ "hdd" ] 使用CRUSH规则 CRUSH map还包含数据放置规则,决定如何将pg映射到osd,以存储对象副本或 erasure coded块 ceph osd crush rule ls命令在已有的规则基础上,打印规则详细信息。 ceph osd crush rule dump rule_name命令打印规则详细信息, [ceph: root@serverc /]# ceph osd crush rule ls replicated_rule ecpool [ceph: root@serverc /]# ceph osd crush rule dump ecpool { "rule_id": 1, "rule_name": "ecpool", "ruleset": 1, "type": 3, "min_size": 3, "max_size": 5, "steps": [ { "op": "set_chooseleaf_tries", "num": 5 }, { "op": "set_choose_tries", "num": 100 }, { "op": "take", "item": -1, "item_name": "default" }, { "op": "choose_indep", "num": 0, "type": "osd" }, { "op": "emit" } ] } 编译后的CRUSH map也包含规则,可能更容易阅读: [ceph: root@node /]# ceph osd getcrushmap -o . /map.bin [ceph: root@node /]# crushtool -d . /map.bin -o . /map.txt [ceph: root@node /]# cat . /map.txt . . . output omitted ... rule replicated_rule { AA id 0 BB } type replicated min_size 1 CC max_size 10 DD step take default EE step chooseleaf firstn 0 type host FF step emit GG . . . output omitted ... AA 规则的名称。使用 ceph osd pool create 命令创建池时,使用此名称来选择规则 BB 规则ID。有些命令使用规则ID而不是规则名称。例如ceph osd pool set pool-name rush_ruleset ID,为已存在的池设置规则时使用规则ID CC 如果一个池的副本数少于这个数字,那么CRUSH不选择此规则 DD 如果一个存储池的副本数超过这个数字,那么CRUSH不选择此规则 EE 接受一个桶名,并开始沿着树进行迭代。在本例中,迭代从名为default的桶开始,它是缺省CRUSH层次结构的根。对于由多个数据中心组成的复杂层次结构,可以为数据创建规则,用于强制将特定池中的对象存储在该数据中心的osd中。在这种情况下,这个步骤可以从数据中心桶开始迭代 FF 选择给定类型(host)的桶集合,并从该集合中每个桶的子树中选择一个叶子(OSD)。本例中,规则从集合中的每个主机桶中选择一个OSD,确保这些OSD来自不同的主机。 支持的类型 # types type 0 osd type 1 host type 2 chassis type 3 rack type 4 row type 5 pdu type 6 pod type 7 room type 8 datacenter type 9 zone type 10 region type 11 root 集合中桶的数量通常与池中的副本数量(池大小)相同: 如果firstn后面的数字为0,则根据池中有多少副本选择多少桶 如果桶的数量大于零,且小于池中的副本数量,则选择相同数量的桶。在这种情况下,规则需要另一个步骤来为剩余的副本绘制桶。可以使用这种机制强制指定对象副本子集的位置 如果这个数字小于零,那么从副本数量中减去它的绝对值,然后选择这个数量的桶 GG 输出规则的结果 例如,可以创建以下规则来在不同的机架上选择尽可能多的osd,但只能从DC1数据中心: rule myrackruleinDC1 { id 2 type replicated min_size 1 max_size 10 step take DC1 step chooseleaf firstn 0 type rack step emit } 使用CRUSH可调参数 还可以使用可调参数修改CRUSH算法的行为。可调项可以调整、禁用或启用CRUSH算法的特性。 Ceph在反编译的 CRUSH Map的开始部分定义了可调参数,你可以使用下面的命令获取它们的当前值: [ceph: root@clienta /]# ceph osd crush show-tunables { "choose_local_tries": 0, "choose_local_fallback_tries": 0, "choose_total_tries": 50, "chooseleaf_descend_once": 1, "chooseleaf_vary_r": 1, "chooseleaf_stable": 1, "straw_calc_version": 1, "allowed_bucket_algs": 54, "profile": "jewel", "optimal_tunables": 1, "legacy_tunables": 0, "minimum_required_version": "jewel", "require_feature_tunables": 1, "require_feature_tunables2": 1, "has_v2_rules": 0, "require_feature_tunables3": 1, "has_v3_rules": 0, "has_v4_buckets": 1, "require_feature_tunables5": 1, "has_v5_rules": 0 } 调整CRUSH可调项可能会改变CRUSH将放置组映射到osd的方式。当这种情况发生时,集群需要将对象移动到集群中的不同osd,以反映重新计算的映射。在此过程中,集群性能可能会下降。 可以使用ceph osd crush tunables profile 命令选择一个预定义的配置文件,而不是修改单个可调项。 [ceph: root@serverc /]# ceph osd crush tunables profile Invalid command: profile not in legacy|argonaut|bobtail|firefly|hammer|jewel|optimal|default osd crush tunables legacy|argonaut|bobtail|firefly|hammer|jewel|optimal|default : set crush tunables values to <profile> Error EINVAL: invalid command [ceph: root@serverc /]# [ceph: root@serverc /]# ceph osd crush tunables optimal adjusted tunables profile to optimal 将配置文件的值设置为optimal,以启用Red Hat Ceph Storage当前版本的最佳(最优)值。 CRUSH Map 管理 集群保持一个编译后的CRUSH map的二进制表示。你可以通过以下方式修改它: 使用ceph osd crush命令 提取二进制 CRUSH Map并将其编译为纯文本,编辑文本文件,将其重新编译为二进制格式,然后将其导入到集群中 通常使用ceph osd crush命令更新CRUSH Map会更容易。但是,还有一些不太常见的场景只能通过使用第二种方法来实现。 使用Ceph命令定制CRUSH Map 下面的例子创建了一个新的桶: [ceph: root@node /]# ceph osd crush add-bucket name type 例如,这些命令创建三个新桶,一个是数据中心类型,两个是机架类型: [ceph: root@node /)# ceph osd crush add-bucket DC1 datacenter added bucket DCl type datacenter to crush map [ceph: root@node /)# ceph osd crush add-bucket rackA1 rack added bucket rackAl type rack to crush map [ceph: root@node /)# ceph osd crush add-bucket rackB1 rack added bucket rackBl type rack to crush map 然后,可以使用以下命令以层次结构组织新桶 [ceph: root@node /]# ceph osd crush move name type=parent 还可以使用此命令重新组织树。例如,将上例中的两个机架桶挂载到数据中心桶上,将数据中心桶挂载到默认的根桶上 [ceph: root@node /]# ceph osd crush move rackA1 datacenter=DC1 moved item id -10 name ' rackA1' to location {datacenter=DCl} in crush map [ceph: root@node /]# ceph osd crush move rackB1 datacenter=DC1 moved item id -11 name ' rackB1' to location {datacenter=DC1} in crush map [ceph: root@node /)# ceph osd crush move DC1 root=default moved item id -9 name ' DC1' to location {root=default} in crush map ID CLASS WEIGHT TYPE NAME -1 0.09796 root default -9 0 datacenter DC1 -10 0 rack rackA1 -11 0 rack rackB1 -3 0.03918 host serverc 0 hdd 0.00980 osd.0 1 hdd 0.00980 osd.1 2 hdd 0.00980 osd.2 9 hdd 0.00980 osd.9 -5 0.02939 host serverd 3 hdd 0.00980 osd.3 4 hdd 0.00980 osd.4 5 hdd 0.00980 osd.5 -7 0.02939 host servere 6 hdd 0.00980 osd.6 7 hdd 0.00980 osd.7 8 hdd 0.00980 osd.8 设置 osd 位置 在创建了自定义桶层次结构之后,将 osd 作为该树的叶子放置。每个 OSD 都有一个位置,它是一个字符串,定义从树的根到该OSD的完整路径。 例如,挂在 rackA1 桶上的 OSD 的位置为: root=default datacenter=DC1 rack=rackA1 当Ceph启动时,它使用ceph-crush-location工具来自动验证每个OSD都在正确的CRUSH位置。 如果OSD不在CRUSH Map中预期的位置,它将被自动移动。默认情况下,这是root=default host=hostname。 可以用自己的脚本替换ceph-crush-location实用程序,以更改osd在CRUSH Map中的位置。 为此,在/etc/ceph/ceph.conf中指定crush_ location_hook参数 [osd] crush_location_hook = /path/to/your/script Ceph使用以下参数执行该脚本: --cluster cluster-name --id osd-id --type osd。 脚本必须在其标准输出中以一行的形式打印位置。Ceph文档有一个自定义脚本示例,该脚本假设每个系统都有一个名为/etc/rack的包含所在机架名称的机架文件: #! /bin/sh echo "root=default rack=$(cat /etc/rack) host=$(hostname -s)" 特定osd的位置定义 可以在/etc/ceph/ceph.conf中设置crush_location参数。重新定义特定osd的位置。 例如,设置osd.0和osd.1,在文件中各自的部分中添加crush_ location参数: [osd.0] crush_location = root=default datacenter=DC1 rack=rackA1 [osd.1] crush_location = root=default datacenter=DC1 rack=rackB1 添加CRUSH Map规则 复制池 创建了一个Ceph可以用于复制池的规则: [ceph: root@node /]# ceph osd crush rule create-replicated name \ root failure-domain-type [class] 其中: Name 为规则的名称 root 是CRUSH Map层次结构中的起始节点 failure-domain-type 是用于复制的桶类型 类是要使用的设备的类,例如SSD或hdd。可选参数 下面的示例创建新的inDC2规则来在DC2数据中心存储副本,将副本分发到各个机架: [ceph: root@node /]# ceph osd crush rule create-replicated inDC2 DC2 rack [ceph: root@node /]# ceph osd crush rule ls replicated_rule erasure-code inDC2 定义规则后,在创建复制池时使用它: [ceph: root@node /]# ceph osd pool create myfirstpool 50 50 inDC2 pool 'myfirstpool' created 纠删码池 对于erasure code,Ceph自动为您创建的每个erasure code池创建规则。规则的名称为新池的名称。 Ceph使用您在创建池时指定的erasure code配置文件中定义的规则参数 下面的例子首先创建新的myprofile erasure code配置文件,然后基于这个配置文件创建myecpool池: [ceph: root@node /]# ceph osd erasure-code-profile set myprofile \ k=2 m=1 crush-root=DC2 crush-failture-domain=rack crush-device-class=ssd [ceph: root@node /)# ceph osd pool create myecpool 50 50 erasure myprofile [ceph: root@node /]# ceph osd crush rule ls 通过编译二进制版本自定义CRUSH Map 你可以用以下命令来反编译和手动编辑CRUSH Map: ceph osd getcrushmap和ceph osd setcrushmap命令提供了一种备份和恢复集群CRUSH Map的有效方法 优化放置组PG 放置组(pg)允许集群通过将对象聚合到组中以可伸缩的方式存储数百万个对象。根据对象的ID、池的ID和池中放置组的数量将对象组织成放置组。 在集群生命周期中,pg个数需要根据集群布局的变化进行调整 CRUSH 试图确保对象在池中osd之间的均匀分布,但也存在pg变得不平衡的情况。 放置组自动缩放器可用于优化PG分发,并在默认情况下打开。如果需要,还可以手动设置每个池的pg数量 对象通常是均匀分布的,前提是池中比osd多一个或两个数量级(十个因子)的放置组。 如果没有足够的pg,那么对象的分布可能会不均匀。 如果池中存储了少量非常大的对象,那么对象分布可能会变得不平衡 配置pg,以便有足够的对象在集群中均匀分布。如果 pg的数量设置过高,则会显著增加CPU和内存的使用。Red Hat建议每个OSD大约100到200个放置组来平衡这些因素 计算放置组的数量 对于单个池的集群,可以使用以下公式,每个OSD 100个放置组 Total PGs = (OSDs * 100)/Number of replicas Red Hat推荐使用每个池计算Ceph放置组,https://access.redhat.com/labs/cephpgc/manual/ 手动映射PG 使用 ceph osd pg-upmap-iterns 命令手动将pg映射到指定的osd,因为以前的Ceph客户端不支持,所以必须配置ceph osd set-require-min-compat-client启用pg-upmap命令 [ceph: root@node /]# ceph osd set-require-min-compat-client luminous 下面的例子将PG 3.25从ODs 2和0映射到1和0: [ceph: root@node /]# ceph pg map 3.25 osdmap e384 pg 3.25 (3.25) -> up [2,0) acting [2,0) [ceph: root@node /]# ceph osd pg-upmap-items 3.25 2 1 set 3.25 pg_ upmap items mapping to [2->1) [ceph: root@node /]# ceph pg map 3.25 osdmap e387 pg 3.25 (3.25) •> up [1,0) acting [1,0) 以这种方式重新映射数百个pg是不现实的 osdmaptool 命令在这里很有用,它获取一个池的实际 Map,分析它,并生成ceph osd pg-upmap-items命令来运行一个最优分布: 将映射导出到一个文件,下面的命令将映射保存到./om文件: [ceph: root@node /]# ceph osd getmap -o ./om got osdmap epoch 387 使用osdmaptool命令的--test-map-pgs选项显示pg的实际分布。打印ID为3的池的分布信息: [ceph: root@node /]# osdmaptool ./om --test-map-pgs --pool 3 osdmaptool: osdmap file './om' pool 3 pg_num 50 #osd count first primary c wt wt osd.0 34 19 19 0.0184937 1 osd.1 39 14 14 0.0184937 1 osd.2 27 17 17 0.0184937 1 ... output omitted . .. 输出显示了osd.2只有27个PG而osd.1有39 PG 生成重新平衡pg的命令。 使用osdmaptool命令的--upmap选项将命令存储在一个文件中: [ceph: root@node /]# osdmaptool ./om --upmap ./cmds.txt --pool 3 osdmaptool: osdmap file './om' writing upmap command output to: ./cmds.txt checking for upmap cleanups upmap, max-count 100, max deviation 0.01 [ceph: root@node /]# cat ./cmds.txt ceph osd pg-upmap-items 3.1 0 2 ceph osd pg-upmap-items 3.3 1 2 ceph osd pg-upmap-items 3.6 0 2 ... output omitted ... 执行命令: [ceph: root@node /]# bash ./cmds.txt set 3.1 pg upmap items mapping to [0->2] set 3.3 pg upmap_items mapping to [1->2] set 3.6 pg_upmap_items mapping to [0->2] ... output omitted ... 2管理OSD Map 描述OSD Map 集群OSD map包含每个OSD的地址、状态、池列表和详细信息,以及OSD的接近容量限制信息等。Ceph使用这些最后的参数来发送警告,并在OSD达到满容量时停止接受写请求 当集群的基础设施发生变化时,比如 osd 加入或离开集群,MONs 会相应地更新相应的映射。Mons保持着map修订的历史。 Ceph使用一组被称为epoch的有序增量整数来标识每个map的每个版本 ceph status -f json-pretty 命令显示每个 map 的 epoch。使用ceph map dump子命令显示每个单独的映射,例如 ceph osd dump [ceph: root@clienta /]# ceph status -f json-pretty { "fsid": "2ae6d05a-229a-11ec-925e-52540000fa0c", "health": { "status": "HEALTH_OK", "checks": {}, "mutes": [] }, "election_epoch": 48, "quorum": [ 0, 1, 2, 3 ], "quorum_names": [ "serverc.lab.example.com", "clienta", "serverd", "servere" ], "quorum_age": 1961, "monmap": { "epoch": 4, "min_mon_release_name": "pacific", "num_mons": 4 分析OSD Map更新 每当有 OSD 加入或离开集群时,Ceph 都会更新 OSD 的map。一个OSD可以因为OSD故障或硬件故障而离开 Ceph 集群 虽然整个集群的分布式映射(map)由监控器(MONs)来维护,但是对象存储设备(OSD)并不使用监控器的领导者(leader)来管理存储器的映射。 相反,OSD之间会直接交换它们所持有的映射,并且每次交换都会标记(epoch)出来。当一个 OSD 检测到自己的运行速度落后时,会触发对其对等 OSD 执行映射的更新,以确保所有的 OSD 都具有最新的映射信息。 在大的集群中,OSD map更新频繁,所以总是分发完整的map是不现实的。相反,接收 OSD 的节点执行增量映射更新 Ceph 还将 osd 和客户端之间的消息标记为epoch。每当客户端连接到OSD时,OSD就会检查 epoch。 如果 epoch 不匹配,那么OSD将响应正确的增量,以便客户机可以更新其OSD映射。这就不需要主动传播,因为客户端只有在下一次联系时才会了解更新后的映射 使用Paxos更新集群Map 要访问Ceph集群,客户机首先要从MONs获取集群映射的副本。为了使集群正常运行,所有的MONs必须具有相同的集群映射。 MONs使用Paxos算法作为一种机制来确保它们对集群状态达成一致。Paxos是一种分布式共识算法。 每当MON修改map时,它就通过Paxos将更新发送给其他监视器。Ceph只有在大多数监控器都同意更新后才会提交新版本的map。 MON向Paxos提交map更新,只有在Paxos确认更新后才将新版本写入本地键值存储。读操作直接访问键值存储。 OSD Map 传播 osd 定期向监控器报告其状态。此外,OSD还可以通过交换心跳来检测对等体的故障,并将故障报告给监视器。 当leader监视器得知OSD出现故障时,它会更新Map,增加epoch,并使用 Paxos 更新协议通知其他监视器,同时撤销它们的租约。 在大多数监控器确认更新后,集群有了仲裁,leader 监控器发出新的租约,以便监控器可以分发更新的OSD映射。 OSD Map命令管理员使用以下命令管理 OSD Map: 命令 动作 ceph osd dump 将OSD映射转储到标准输出 ceph osd getmap -o binfile 导出当前映射的二进制副本 osdmaptool --print binfile 在标准输出中显示人类可读的映射副本 osdmaptool --export-crush crushbinfile binfile 从OSD map 中提取CRUSH map osdmaptool --import-crush crushbinfile binfile 嵌入一个新的CRUSH map osdmaptool --test-map-pg pgid binfile 验证给定PG的映射 ...

    2023-11-12 214
  • HTTP和HTTPS的区别

    HTTPS是HTTP的安全版本,两者都用于在客户端和服务器之间传输数据,但HTTPS添加了加密和安全性层,以保护数据的机密性和完整性。 区别: 安全性: HTTP:HTTP是一种不安全的协议,数据在传输过程中以明文形式传输,容易受到窃听和篡改的风险。 HTTPS:HTTPS通过使用加密机制(通常是TLS/SSL)来保护数据的机密性,使数据在传输过程中加密,从而提供更高的安全性。 端口: HTTP:HTTP默认使用端口80进行通信。 HTTPS:HTTPS默认使用端口443进行通信。 加密: HTTP:HTTP不提供加密,数据可以在网络上传输时被窃听。 HTTPS:HTTPS使用TLS/SSL协议进行数据加密和解密,确保数据在传输过程中的保密性。 证书: HTTP:HTTP不涉及数字证书的使用。 HTTPS:HTTPS需要服务器获得数字证书,并由权威的证书颁发机构(CA)签发,以验证服务器的身份。客户端可以使用证书来确保它们正在连接到合法的服务器。 认证和身份验证: HTTP:HTTP不提供身份验证机制,任何人都可以发送HTTP请求。 HTTPS:HTTPS提供了对服务器和(可选)客户端的身份验证,确保双方的合法性。 SEO(搜索引擎优化): HTTP:搜索引擎可能更喜欢使用HTTPS的网站,因为它们提供了更高的安全性,可以影响搜索排名。 ...

    2023-11-11 234
  • HTTP和TCP的关系和区别

    关系: HTTP建立在TCP之上:HTTP是一个应用层协议,而TCP是传输层协议。HTTP通常使用TCP作为它的传输层协议,以在网络上传输数据。HTTP与TCP之间的关系可以类比为在实体之上建立一个通信通道。 HTTP利用TCP的可靠性:TCP提供了可靠的、面向连接的数据传输。HTTP利用TCP的可靠性来确保数据的正确传递,包括数据的分段和重新组装、错误检测和重传等。 区别: 层次:TCP是传输层协议,负责在两台计算机之间建立连接、可靠地传输数据流,以及处理数据分段和重传等传输细节。HTTP是应用层协议,负责定义数据的格式和如何在客户端和服务器之间传输数据。 功能:TCP关注于数据传输的可靠性和流控制,而HTTP关注于定义如何呈现和传输文档、图像、视频等内容。HTTP通过请求-响应模型允许客户端请求网络资源,并服务器响应这些请求。 端口:TCP使用端口来标识不同的应用程序或服务,允许多个不同的应用程序在同一台计算机上共享网络连接。HTTP默认使用TCP端口80(HTTP)或443(HTTPS)。 通信模式:TCP是一种点对点的通信协议,即两台计算机之间的通信。HTTP是一种客户端-服务器通信模式,客户端发送请求,服务器返回响应。 状态:TCP是无状态的协议,它不保留关于连接的持久状态信息。HTTP也是无状态的,每个HTTP请求和响应之间是相互独立的,不保留客户端之间的状态。 ...

    2023-11-11 207
  • 浅拷贝和深拷贝的区别

    浅拷贝 浅拷贝仅复制对象本身,而不会递归复制其内部包含的对象或数据结构。 对于复杂对象,如包含指针或引用的对象,浅拷贝会导致多个对象共享相同的内部数据。 浅拷贝通常是通过复制对象的成员变量来实现的,但对于内部指针或引用,只是复制了指针或引用本身,而不是它们引用的对象。 深拷贝 深拷贝会递归地复制对象本身及其内部的所有对象和数据结构,确保每个复制的对象都是全新的,没有共享内部数据。 对于复杂对象,深拷贝可以消除共享数据的问题,每个对象都有自己的拷贝。 深拷贝需要在拷贝过程中为每个内部对象或数据结构创建全新的副本,通常需要更多的时间和内存。 总结 使用浅拷贝时,多个对象可能会出现数据不一致的问题,因为它们共享相同的内部数据。 深拷贝确保了每个对象都是独立的,但可能需要更多的资源。 ...

    2023-11-10 189
  • b树与b+树的区别

    数据存储方式 B树:B树的每个节点既存储数据也存储索引。这意味着B树的非叶子节点既包含索引键也包含对应的数据。 B+树:B+树的非叶子节点仅存储索引键,而数据全部存储在叶子节点。B+树的所有叶子节点通过指针连接成一个有序链表,便于范围查询。 叶子节点关联性 B树:B树的叶子节点和非叶子节点没有直接关联,各自独立存在。 B+树:B+树的叶子节点之间通过链表相连,形成了一个有序的链表。这有助于范围查询,因为数据按顺序排列。 范围查询效率 B树:在B树上进行范围查询相对较慢,因为需要访问非叶子节点和叶子节点。 B+树:B+树在范围查询时非常高效,因为只需遍历叶子节点的链表。 非叶子节点的索引键 B树:非叶子节点的索引键可以是重复的,可能导致不必要的冗余数据。 B+树:B+树的非叶子节点的索引键一般是不重复的,确保了索引的唯一性。 叶子节点个数 B树:B树的叶子节点数量和数据记录数量相等。 B+树:B+树的叶子节点数量比数据记录数量多,因为叶子节点主要用于存储数据和维护链表,而非叶子节点用于索引。 B+树 B树 ...

    2023-11-10 169
  • get和post区别

    数据传输方式 GET:通过URL将数据附加在请求中,数据暴露在URL中,通常用于请求数据,对请求参数有长度限制,通常在2048字符以内。 POST:通过请求正文传输数据,数据不暴露在URL中,通常用于发送数据,对请求参数没有固定的长度限制,可以传输大量数据。 安全性 GET:传输的数据在URL中可见,因此不适合传输敏感信息,如密码。 POST:传输的数据在请求正文中,相对更安全,适合传输敏感信息。 缓存 GET:请求可以被缓存,对相同URL的多次GET请求可以从缓存中获取响应,具有幂等性(多次请求产生相同结果)。 POST:请求不能被缓存,每次POST请求都会向服务器发送数据,不具有幂等性。 幂等性 GET:GET请求通常应该是幂等的,即多次执行相同的GET请求应该产生相同的结果。 POST:POST请求通常不是幂等的,多次执行相同的POST请求可能会导致不同的结果。 书签和浏览器历史 GET:可以被添加为书签,可以在浏览器历史中记录。 POST:通常不会被添加为书签,不会出现在浏览器历史中。 数据类型 GET:通常用于请求资源,如网页、图片等。 POST:通常用于提交表单数据、上传文件等。 总结 ...

    2023-11-10 168
  • 什么是SYN FLOOD洪水攻击,原理是什么?

    同Tear Drop泪滴攻击一样,SYN Flood也是一种拒绝服务攻击,其目标是通过发送大量伪造的TCP连接请求(SYN包)来消耗目标系统的资源,从而使得被攻击方资源耗尽而无法响应合法的连接请求的攻击方式。 SYN FLOOD攻击原理 SYN FLOOD攻击发生在OSI参考模型的传输层,它的攻击原理是利用TCP协议的三次握手过程协议缺陷来实现的。 正常情况下,客户端和服务器建立TCP连接三次握手过程是这样的:   1)建立连接时,客户端发送一个SYN同步报文给服务器端,该报文中包含了本端的初始化序列号,同时设置本段的连接状态为SYN-SENT。 2)服务器端收到SYN同步报文后,给客户端回应SYN+ACK 报文,该报文中包含本段的初始化序列号。同时设置本端连接状态为SYN-RCVD。 3)客户端收到服务器端的SYN+ACK后,向服务器端发送ACK报文进行确认,此包发送完毕,客户端和服务器进入ESTABLISHED状态。 三次握手的完成标志着一个TCP连接的成功建立。 但是,当客户端向服务器端发送SYN包后,对服务器端回应的SYN+ACK包不进行处理,会出现什么结果呢,如下图? 服务器端发送完SYN+ACK 报文后,会建立一个半连接状态的socket套接口,同时会启动一个定时器,若在超时时间内未收到客户端回应的ACK报文,服务器端将会进行超时重传SYN+ACK报文给客户端,默认重传次数为5次。 第1次重传:1秒 第2次重传:2秒 第3次重传:4秒 第4次重传:8秒 第5次重传:16秒 第5次重传后还要等待32秒,若仍收不到 ACK 报文,才会关闭连接。 这样等等待时间=(1+2+4+8+16)+32=63秒,也就是大于1分钟的时间。 这样,若客户端不停的发送SYN报文并对服务端回应的报文不回答,就会导致服务器端不停的创建半连接状态的**socket **而耗尽资源,从而服务器端无法处理正常的客户端的连接请求,造成拒绝服务攻击,即SYN FLOOD洪水攻击。 SYN FLOOD攻击的特点 攻击手段简单:SYN FLOOD攻击是一种常见的DoS攻击手段。 防不胜防:SYN FLOOD是一种难以防范的攻击方式,因为其攻击行为在某些情况下很难被察觉和区分。例如,一个SYN FLOOD攻击可能会伪造合法的IP地址,使得攻击行为看起来像是来自正常的网络流量。这使得防火墙、IDS等安全设备很难对其进行有效的检测和拦截。 攻击效果显著:SYN FLOOD攻击能够快速地使目标系统资源耗尽,导致其无法响应合法的连接请求。这使得攻击者能够成功地实施DoS攻击,使目标网站或服务完全瘫痪。 危害范围广泛:SYN FLOOD攻击不仅能够对主机进行攻击,还能够危害路由器、防火墙等网络系统。事实上,只要目标系统打开TCP服务,SYN FLOOD攻击就能够对其实施攻击。 ...

    2023-11-07 188
  • Redis主从复制原理详解

    众所周知,一个数据库系统想要实现高可用,主要从以下两个方面来考虑: 保证数据安全不丢失 系统可以正常提供服务 而 Redis 作为一个提供高效缓存服务的数据库,也不例外。 上期我们提到的 Redis 持久化策略,其实就是为了减少服务宕机后数据丢失,以及快速恢复数据,也算是支持高可用的一种实现。 除此之外,Redis 还提供了其它几种方式来保证系统高可用,业务中最常用的莫过于主从同步(也称作主从复制)、Sentinel 哨兵机制以及 Cluster 集群。 同时,这也是面试中出现频率最高的几个主题,这期我们先来讲讲 Redis 的主从复制。 2. 主从复制简介 Redis 同时支持主从复制和读写分离:一个 Redis 实例作为主节点 Master,负责写操作。 其它实例(可能有 1 或多个)作为从节点 Slave,负责复制主节点的数据。 2.1 架构组件 主节点Master 数据更新:Master 负责处理所有的写操作,包括写入、更新和删除等。 数据同步:写操作在 Master 上执行,然后 Master 将写操作的结果同步到所有从节点 Slave 上。 从节点Slave 数据读取:Slave 负责处理读操作,例如获取数据、查询等。 数据同步:Slave 从 Master 复制数据,并在本地保存一份与主节点相同的数据副本。 2.2 为什么要读写分离 1)防止并发 从上图我们可以看出,数据是由主节点向从节点单向复制的,如果主、从节点都可以写入数据的话,那么数据的一致性如何保证呢? 有聪明的小伙伴可能已经想到了,那就是加锁! 但是主、从节点分布在不同的服务器上,数据跨节点同步时又会出现分布式一致性的问题。而在高频并发的场景下,解决加锁后往往又会带来其它的分布式问题,例如写入效率低、吞吐量大幅下降等。 而对于 Redis 这样一个高效缓存数据库来说,性能降低是难以忍受的,所以加锁不是一个优秀的方案。 那如果不加锁,使用最终一致性方式呢? 这样 Redis 在主、从库读到的数据又可能会不一致,带来业务上的挑战,用户也是难以接受的。 业务为用户服务,技术为业务服务。 所以,为了权衡数据的并发问题和用户体验,我们只允许在主节点上写入数据,从节点上读取数据。 2)易于扩展 我们都知道,大部分使用 Redis 的业务都是读多写少的。所以,我们可以根据业务量的规模来确定挂载几个从节点 Slave,当缓存数据增大时,我们可以很方便的扩展从节点的数量,实现弹性扩展。 同时,读写分离还可以实现数据备份和负载均衡,从而提高可靠性和性能。 3)高可用保障 不仅如此,Redis 还可以手动切换主从节点,来做故障隔离和恢复。这样,无论主节点或者从节点宕机,其他节点依然可以保证服务的正常运行。 3. 主从复制实现 3.1 开启主从复制 要开启主从复制,我们需要用到 replicaof 命令。 当我们确定好主节点的 IP 地址和端口号,在从库执行 replicaof <masterIP> <masterPort> 这个命令,就可以开启主从复制。 注意,在 Redis5.0 之前,该命令为 slaveof 开启主从复制后,应用层采用读写分离,所有的写操作在主节点进行,所有读操作在从节点进行。 主从节点会保持数据的最终一致性:主库更新数据后,会同步给从库。 3.2 主从复制过程 那主从库同步什么时候开始和结束呢? 是一次性传输还是分批次写入?Redis 主从节点在同步过程中网络中断了,没传输完成的怎么办? 带着这些疑问我们来分析下,首先,Redis 第一次数据同步时分 3 个阶段。 1)建立连接,请求数据同步 主从节点建立连接,从库请求数据同步。 从服务器从 replicaof 配置项中获取主节点的 IP 和 Port,然后进行连接。 连接成功后,从服务器会向主服务器发送 PSYNC 命令,表示要进行同步。同时,命令中包含 runID 和 offset 两个关键字段。 runID:每个 Redis 实例的唯一标识,当主从复制进行时,该值为 Redis 主节点实例的ID。由于首次同步时还不知道主库的实例ID,所以该值第一次为 ? offset:从库数据同步的偏移量,当第一次复制时,该值为 -1,表示全量复制 主服务器收到 PSYNC 命令后,会创建一个专门用于复制的后台线程(replication thread),然后记录从节点的 offset 参数并开始进行 RDB 同步。 2)RDB 同步 主库生成 RDB 文件,同步给从库。 当从服务器连接到主服务器后,主服务器会将自己的数据发送给从服务器,这个过程叫做全量复制。主服务器会执行 bgsave 命令,然后 fork 出一个子进程来遍历自己的数据集并生成一个 RDB 文件,将这个文件发送给从服务器。 在这期间,为了保证 Redis 的高性能,主节点的主进程不会被阻塞,依旧对外提供服务并接收数据写入缓冲区中。 从服务器接收到 RDB 文件后,会清空自身数据,然后加载这个文件,将自己的数据集替换成主服务器的数据集。 3)命令同步 在第一次同步过程中,由于是全量同步,所以用时可能比较长,这期间主库依旧会写入新数据。 但是,在数据同步一开始就生成的 RDB 文件中显然是没有这部分新增数据的,所以第一次数据同步后需要再发送一次这部分新增数据。 这样,主服务器需要在发送完 RDB 文件后,将期间的写操作重新发送给从服务器,以保证从服务器的数据集与主服务器保持一致。 3.3 增量同步 1)命令传播 在完成全量复制后,主从服务器之间会保持一个 TCP 连接,主服务器会将自己的写操作发送给从服务器,从服务器执行这些写操作,从而保持数据一致性,这个过程也称为基于长连接的命令传播(command propagation)。 增量复制的数据是异步复制的,但通过记录写操作,主从服务器之间的数据最终会达到一致状态。 2)网络断开后数据同步 命令传播的过程中,由于网络抖动或故障导致连接断开,此时主节点上新的写命令将无法同步到从库。 即便是抖动瞬间又恢复网络连接,但 TCP 连接已经断开,所以数据需要重新同步。 从 Redis 2.8 开始,从库已支持增量同步,只会把断开的时候没有发生的写命令,同步给从库。 详细过程如下: 网络恢复后,从库携带之前主库返回的 runid,还有复制的偏移量 offset 发送 psync runid offset 命令给主库,请求数据同步; 主库收到命令后,核查 runid 和 offset,确认没问题将响应 continue 命令; 主库发送网络断开期间的写命令,从库接收命令并执行。 这时,有细心的小伙伴可能要问了,网络断开后,主库怎么知道哪些数据是新写入的呢? 这是个好问题,接下来我们详细说明一下。 3)增量复制的关键 Master 在执行写操作时,会将这些命令记录在 repl_backlog_buffer (复制积压缓冲区)里面,并使用 master_repl_offset 记录写入的位置偏移量。 而从库在执行同步的写命令后,也会用 slave_repl_offset 记录写入的位置偏移量。正常情况下,从库会和主库的偏移量保持一致。 但是,当网络断开后,主库继续写入,而从库没有收到新的同步命令,所以偏移量就停止了。所以,master_repl_offset 会大于 slave_repl_offset。 注意:主从库实现增量复制时,都是在 repl_backlog_buffer 缓冲区上进行。 网络断开前后,主从库的同步图如下:   repl_backlog_buffer 复制积压缓冲区是一个环形缓冲区,如果缓冲区慢了(比如超过 1024),则会从头覆盖掉前面的内容。 所以,当网络恢复以后,主节点只需将 master_repl_offset 和 slave_repl_offset 之间的内容同步给从库即可(图中 256~512 这部分数据)。 需要注意的是,主库的积压缓冲区默认为 1M,如果从库网络断开太久,缓冲区之前的内容已经被覆盖,这时主从的数据复制就只能采取全量同步了。 所以我们需要根据业务量和实际情况来设置 repl_backlog_buffer 的值。 4. 小结 面让架构易于扩展,另一方面防止单体故障:当主库挂了,可以立即拉起从库,不至于让业务停滞太久。 而首次主从复制包括建立连接,RDB 同步和命令同步三个阶段。 为了保证同步的效率,除了第一次需要全量同步以外,例如当主从节点断连后,则只需要增量同步,这是由主从库的复制偏移量以及主库的 repl_backlog_buffer 复制积压缓冲区来控制的。 好了,以上就是本文的所有内容了,希望今天的文章能让大家更深入地了解 Redis 主从复制,并在面试或者实际工作中学以致用,探索更多的细节。 ...

    2023-11-07 216
  • NTP时间同步过程

    NTP通过时间戳和网络延迟计算来调整本地时钟,以确保系统时钟与NTP服务器的时钟尽可能一致,实现高精度的时间同步。 第一步、NTP客户端发起时间请求 NTP客户端向NTP服务器发起时间请求,请求服务器的准确时间。这个请求通常包括客户端的当前时间戳。 通常,这是通过UDP协议的端口123完成的。NTP客户端可以是计算机、路由器、交换机或其他网络设备。 第二步、NTP服务器响应 NTP服务器收到客户端的请求,并在响应中包括自己的时间戳。服务器的时间通常比客户端的时间更准确。服务器的响应包括四个时间戳:T1、T2、T3、T4。 T1:客户端发送请求的时间。 T2:服务器接收到请求的时间。 T3:服务器发送响应的时间。 T4:客户端接收响应的时间。 NTP服务器可以是Stratum 1服务器(通常是高精度时间源,如原子钟或GPS时钟)或Stratum 2服务器,依次类推。 第三步、计算网络延迟 客户端使用T1、T2、T3、T4时间戳来计算网络延迟和时钟偏移。根据这些时间戳,客户端可以计算出网络延迟,即信号从客户端发送到服务器再返回所需的时间。你在示例中计算了延迟,这在NTP中非常重要,因为网络延迟会对时钟同步产生影响。 第四步、调整本地时钟 客户端使用计算得到的网络延迟和服务器的时间戳来调整自己的本地时钟。这个调整会将客户端的时钟与服务器的时钟对齐,以减小时钟偏移。 ?请记住:时间同步不是一次性事件,而是定期进行的。 客户端设备通常每隔一段时间(通常是每10分钟或每小时)与NTP服务器进行一次时间同步,以确保时钟的准确性。 此后的时间同步交换通常只需要一次消息交换,因为客户端已经与NTP服务器建立了时间校准。 ...

    2023-11-07 184
  • 为什么要同步网络时间

    说白了,同步网络时间就是为了应对许多应用和系统对时间的准确性要求非常高的问题,简单罗列一下原因就是: 许多应用程序和系统使用时间戳来记录事件的发生顺序。即使是微小的时间差异,如毫秒级别的差异,都可能导致事件顺序错误,对于事务的准确性和可靠性非常关键。 在一些关键应用中,如金融交易和网络通信,即使是短暂的停机都可能导致巨大的损失。通过同步网络时间,可以确保各种网络设备和应用的时间保持一致,从而避免因时间不同步而导致的问题。 在网络故障排除和恢复中,准确的时间信息对于确定问题的根本原因和追踪故障非常重要。同步网络时间可以帮助精确地记录事件时间戳,有助于快速诊断和修复问题。 许多行业和组织面临合规性和法规要求,其中要求保持时间同步以确保数据的准确性和完整性。同步网络时间有助于满足这些法规要求。 在科学研究和实验中,时间的准确性对于数据采集和分析至关重要。同步网络时间可确保实验结果的可重复性和准确性 ...

    2023-11-07 169
  • 什么是NTP

    NTP,英文全称:Network Time Protocol,中文全名网络时间协议,是一种用于在计算机网络中同步设备时钟的协议。 它的主要目标是确保网络中的各个设备都具有一致的时间参考,以便它们可以协同工作,进行时间戳记录、数据同步和各种计算任务。 NTP采用分层结构来确保时间同步,使网络中的所有设备都能获得准确的时间信息。 ...

    2023-11-06 199

联系我们

在线咨询:点击这里给我发消息

QQ交流群:KirinBlog

工作日:8:00-23:00,节假日休息

扫码关注