Ceph集群擴容及數據再均衡原理分析

用戶文件在Ceph RADOS中存儲、定位過程大概包括:用戶文件切割成對象、對象映射到PG、PG分組PGP、PG映射到OSD。這些過程中,可能涉及了大量概念和變量,而其實它們大部分是通過HASH、CRUSH等算法計算出來的,初始參數可能也就只有這么幾個:用戶文件inode、layout、crush_map等。Ceph所有組件和客戶端通過計算就能得到所有對象的Location,而且只要輸入的參數信息不變,Location就不會變,另外通過PG作為中間層將對象與OSD解綁,使得對象在Ceph RADOS分布更均勻,在OSD增刪時,能夠保證只有盡可能少的對象發生遷移。在PG、PGP調整或OSD增刪后,某些Location發生變化的對象的遷移路線,需要了解各級HASH映射的原理、步驟,更多的計算和分析才能得知。在此基礎上才能分析調整PG和PGP對Ceph集群的影響做一些可靠的定性分析,進而指導我們采用更合適的策略去實現Ceph集群的擴容和數據再均衡。

1. 從用戶文件到對象

從用戶文件到對象的映射過程就是對用戶文件進行切割的過程。CephFS會將用戶文件按照一定的對象大小進行切割,得到若干對象,OSD負責對象的管理。例如,設定對象大小為4MB,則CephFS按照文件字節邏輯地址將1GB的用戶文件切割成1GB/4MB=1024個對象,對象的編號obj_offset取值范圍為[0,1024)。Obj_name = FileInode.obj_offset,FileInode為用戶文件inode的十六進制碼,obj_offset是用戶文件被切割后對象的編號,代表用戶文件的第幾個對象。

如下圖所示:

通過Striper::file_to_extents將用戶文件內容映射到各對象,參數包括用戶文件的布局layout,用戶文件內容的字節邏輯地址偏移offset和長度len等。

對象大小是否可配置?

文件布局可以控制如何把文件內容映射到各Ceph RADOS對象,可以使用虛擬擴展屬性或xattrs來讀、寫某一個文件的布局。布局字段包括object_size,但只能在文件size為0的情況下,才能重新配置。

# 通過以下命令讀取布局字段:
getfattr -n ceph.file.layout.object_size file# 通過以下命令修改布局字段:
setfattr -n ceph.file.layout.object_size -v 10485760 file

2. 從對象到OSD

從對象到OSD的過程包括:對象名hash、對象到PG、PG分組PGP、PG到OSD等主要過程。這里將以某個cephfs用戶文件為例闡述詳細的映射過程。

2.1. 創建文件

  1. 創建一個文件

touch /mnt/cephfs/file002
  1. 查看文件ino

ls -i /mnt/cephfs/file0021099511876737 /mnt/cephfs/file002

  1. Ino進制轉換

printf "%x\n" 10995118767371000003cc81

  1. 查看pool信息

ceph osd ?pool ls detailpool 5 'cephfs_data' replicated size 2 min_size 1 crush_rule 0 object_hash rjenkins pg_num 1024 pgp_num 1024 last_change 142 flags hashpspool stripe_width 0 expected_num_objects 16986931 application cephfspool 7 'cephfs_meta' replicated size 2 min_size 1 crush_rule 0 object_hash rjenkins pg_num 1024 pgp_num 1024 last_change 142 flags hashpspool stripe_width 0 expected_num_objects 169869 application cephfs

一個pool有pool_id、pool_name、副本數、pg_num、pgp_num等主要信息參數。pg_num和pgp_num調整分析也是本文的主要內容。從pool的詳細查詢結果可知,5號pool的名字為cephfs_data,采用2副本策略,pg和pgp都為1024。

2.2. 查找零號對象

通過命令可以找到/mnt/cephfs/file002的零號對象存儲在哪個OSD上。

ceph osd map cephfs_data 1000003cc81.00000000osdmap e213 pool 'cephfs_data' (5) object '1000003cc81.00000000' -> pg 5.b184543c (5.3c) -> up ([4,10], p4) acting ([4,10], p4)

從以上結果可知,零號對象1000003cc81.00000000存儲在pg 5.3c,對應的OSD SET是 [4,10],OSD SET為2副本,pg 5.3c的主副本存儲在osd.4中,次副本存儲在osd.10中。

2.3. 對象名HASH

pg 5.b184543c是如何組成的?

以‘.’為分割符,可以分成兩部分5和0xb184543c。5取自pool ‘cephfs_data’的pool_id,而0xb184543是obj_name ‘1000003cc81.00000000’的HASH hex值。

在源碼中,HASH函數ceph_str_hash_rjinkins,根據obj_name計算出一個隨機值。對于同樣的對象名,計算出來的結果永遠都是相同的。而對象名字構成中,用戶文件inode號保證了不同文件之間的對象名字不同,而obj_offset確保了同一用戶文件中不同對象的名字不同。

2.4. 從對象到PG

從“pg 5.b184543c (5.3c)”可知,使用的是5號pool,object 1000003cc81.00000000的HASH hex為“0xb184543c”,本文用obj_hash表示,也稱為對象的placement seed,此值會被保存在代表pg的類pg_t的對象中,這里簡稱為pg_seed。

那pg 5.3c為什么只取了object hash hex碼的后2兩位呢?

是因為5號pool的pg總數為1024個,1024對應0x400,則mask = 0x400 - 1 =0x3ff,因此只需要取0x3ff & b184543c = 0x3c,這樣就完成了從對象到PG的映射。最終,一個pg可以表示為pool_id.(mask & obj_hash),一個pool中pg的編號取值范圍為[0,mask]。

2.5. PG分組PGP

眾所周知,Ceph官方建議一個pool的pg_num = pgp_num,而且為2的冪次方。而說白了,PG分組PGP就是將眾多PG分成各個PGP組。在二者相等的情況下,一個PGP中就只有一個PG。

但如果PGP小于PG呢?根據抽屜原理,肯定存在某些PGP分配到了2個或2個以上的PG。這種情況是否存在呢?答案是肯定的,該狀態可能只是個中間態,在用戶采用了小步調多次調整策略實施PG和PGP的調整,來配合集群OSD添加,最終pg_num會等于pgp_num。

例如,Ceph集群通過增加OSD數量達到擴容的目的,擴容后每個OSD平均承擔的PG數量將會小于Ceph官方建議的100~200個,因為在這個取值范圍內,集群數據分布均衡度與OSD負載都是比較合適的。因此,擴容后需要相應的調大pg_num和pgp_num,二者的調整是兩個獨立的順序操作,因此會存在二者不相等的中間狀態。另外,為了保證集群的穩定性,通常是小步調多次的調整pg_num和pgp_num,經過多輪的調整后達到整體調整目標。

這里可能會有一個疑問是,處于相同或不同PGP中的各PG,會有什么聯系呢?

答案是,同一個pool中處于相同PGP中的各個PG會被映射到相同的OSD SET,而處于不同PGP中的各個PG一般會被映射到不同的OSD SET,但也不能完全排除被映射到相同OSD SET的可能性,這塊的內容涉及到了ceph引以為傲的CRUSH算法,由于本文重點不在此,后期將有專門的文章做介紹。

下圖中,ceph_state_mod通過PG的pg_seed與pgp_num_mask按位&,將各PG映射到PGP。

2.6. 從PG到OSD

Ceph數據存儲策略有副本和EC兩種,本文基于副本策略。用戶可以選擇2副本、3副本等,副本越多空間利用率就越低,而可靠性就越高,因此需要用戶在空間利用率與可靠性二者之間做平衡。多副本情況下,PG到OSD的映射其實是PG到OSD SET的映射,OSD SET的成員個數為副本數,而首成員為主副本,其他成員為次副本,客戶端的讀寫由主副本負責,這塊內容涉及到了ceph集群的讀寫流程,這里不做太詳細的介紹,后期文章再做分析。

下圖中,_pg_to_raw_osds完成PG到OSD SET的映射,首先調用了pool.raw_pg_tp_pps完成了PG到PGP的分組,會得到分組唯一標識的placement ps即pps。然后,通過crush->find_rule找到pool的ruleno。最后,調用crush->do_rule基于ruleno和pps完成PG到OSD SET的映射。

雖然,兩個PG的ps可能不同,但pps可能相同,那映射到的OSD SET就會相同,可以說它們選擇了相同的OSD SET來存儲數據,也就是說同一個OSD上會承擔多個PG,每個OSD上平均承擔的PG越多,在非常大量的對象情況下,每個OSD上存儲的數據就越均衡。每個OSD上承擔的PG越多,OSD管理PG的壓力就越大,因此官方對每個OSD平均承擔的PG數的合理取值范圍為100~200。

CRUSH算法是ceph非常非常引以為傲的的特色,通過它,ceph中的每個組件或客戶端都能自己計算出對象到OSD SET的映射,并不需要提供映射表查詢的中心節點,從而避免了中心節點的瓶頸問題。本文重點不在CRUSH算法,此處不做詳細闡述分析,后期會有單獨文章做介紹。

3. 對象文件的命名規則

這里需要說明一下,本文中涉及的對象文件名字與對象名字不同,盡管二者就是同一個對象。對象文件名字指的是對象在linux xfs文件系統中的文件名字。

當前,OSD的兩個主要類型為Filestore和Bluestore,本文基于Filestore。Filestore類型的OSD一般利用linux本地文件系統xfs存儲和管理對象文件,用戶文件被切割成對象文件后,一個對象就對應xfs的一個文件,一個xfs文件通過文件路徑Path和文件名FileName定位,舉例如下:

?/var/lib/ceph/osd/ceph-4/current/5.3c_head/DIR_C/DIR_3/DIR_4/1000003cc81.00000000__head_B184543C__5

該對象文件的Path = “/var/lib/ceph/osd/ceph-4/current/5.3c_head/DIR_C/DIR_3/DIR_4/”,FileName = “1000003cc81.00000000__head_B184543C__5”。

Path也包含了許多含義,ceph-4代表了osd.4,5.3c代表了5號pool中0x3c的pg,這些信息與前面章節一致。而DIR_C、DIR_3和DIR_4是pg dir split的結果,目的是為了保證每個目錄中文件數不要過多,xfs某個目錄特別大時,對于執行目錄的ls等操作不利,而且過大的目錄在被讀進內存時,會消耗過多的內存,對該目錄進行flush時也會花費更多的時間,當然還有其他缺點存在。

不難發現,將“_”作為分隔符,可以將FileName分割成若干部分,1000003cc81.00000000是對象名字,B184543C為對象名字的HASH hex值即pg的ps,5就是pool cephfs_data的號。對象文件名字結構如下所示:

很多組成部分在文章前面已經做了介紹,這里只做以下補充:

  1. key和hash不能同時指定,而且常見的是hash;

  2. snap_num為head,代表普通對象,否則為snapshot對象。可以給rbd image創建snapshot,這時候底層對象就有snapshot信息了;

  3. namespace可以認為是對pool空間的進一步劃分,在邏輯上隔離各個用戶。一個pool可以劃分多個namespace,這些namespace中的對象都使用該pool。尤其應用在ceph rgw服務中。

到此為止,我們已經對用戶文件是如何在Ceph中存儲的過程有了大概的了解。該過程可以概括為:用戶文件切割成對象、對象映射到PG、PG映射到OSD。這個過程中,可能涉及了大量概念和變量,而其實它們大部分是通過HASH、CRUSH等算法計算出來的,初始參數可能也就只有這么幾個:用戶文件inode、layout、crush_map等,通過計算就能得到所有對象的Location,而且只要輸入的參數信息不變,Location就不變,另外通過PG作為中間層將對象與OSD解綁,而且使得對象在ceph RADOS中均勻分布。但本人覺得這也有一點點的小缺點,就是在PG、PGP調整或OSD增刪后,某些Location發生變化的對象遷移路線并不是那么直接和直觀,需要了解各級HASH映射的原理、步驟,更多的計算和分析才能得知。

4. PG調整的影響

為了簡化問題,抓住重點,假設對象的分布如下:

根據文章前面的內容,表格中所有代號都能找到定義和計算方法,這里做一個簡單的總結:?

  1. obj_hash = hash(obj_name);

  2. pg_seed = obj_hash;

  3. pgId = pg_seed & pg_mask;

  4. pgpId = pg_seed & pgp_mask;

4.1. PG非冪次方調整

將pg_num由2調整為3,pgp_num依然為2。調整后,對象的分布如下:

從表中可知:?

  1. pg_2分擔了原屬于pg_0的obj_2和obj_8,pg_2與pg_0對應同一個OSD SET,因此obj_2和obj_8只是OSD內部的遷移;

  2. pg_2分擔了原屬于pg_1的obj_5和obj_11,pg_2與pg_1對應不同的OSD SET,obj_5和obj_11涉及到了OSD之間的遷移,不同OSD之間就會有網絡通信開銷;

  3. pg_0分擔了原屬于pg_1的obj_3和obj_9,也會涉及網絡通信開銷;

  4. pg_1分擔了原屬于pg_0的obj_4和obj_10,也會涉及網絡通信開銷。

總之,共涉及OSD內部遷移2次,共涉及OSD之間遷移6次。我們將OSD內部遷移率定義為inter_mig_ratio,將OSD之間遷移率定義為ext_mig_ratio,則計算結果為:

由于OSD內部遷移,只是將一個對象文件從源目錄mv到目的目錄,由于源目錄與目的目錄共享同一個OSD的根目錄,因此mv操作只涉及xfs文件系統元數據的更新,不涉及對象文件數據的讀取和寫入,可以稱OSD內部遷移為輕遷移;

而OSD之間遷移,源OSD需要讀取對象文件數據,網絡通信發送到目的OSD,目的OSD再創建該對象文件,目的OSD寫入對象文件數據,源OSD刪除該對象文件,稱OSD之間遷移為重遷移。

我們將OSD內部一次對象遷移的工作量定義為1,將OSD之間一次對象遷移的工作量定義為4,則總的工作量為:

因此,inter_mig_ratio反應了輕遷移率,而ext_mig_ratio反應了重遷移率,盡量減少重遷移,降低重遷移率,將重遷移變成輕遷移,最終減少數據遷移對ceph集群整體穩定性和性能的影響。

4.2. PG冪次方調整

將pg_num由2調整為4,pgp_num依然為2。調整后,對象的分布如下:

從表中可知:?

  1. pg_2分擔了原屬于pg_0的obj_2、obj_6和obj_10,pg_2與pg_0對應同一個OSD SET,因此obj_2、obj_6和obj_10只是OSD內部的遷移;

  2. pg_3分擔了原屬于pg_1的obj_3、obj_7和obj_11,pg_3與pg_1對應同一個OSD SET,因此obj_3、obj_7和obj_11也只是OSD內部的遷移。

總之,共涉及OSD內部遷移6次。

4.3. PG非冪次與冪次調整對比

inter_mig_ratio

ext_mig_ratio

work_load

非冪次(2->3)

16.67%

50%

2.17

冪次(2->4)

50%

0%

0.5

由上表可知,本文中PG非冪次調整引入的工作量遠遠高于冪次調整引入的工作量,因此建議PG調整最好選擇冪次調整,盡量減少PG調整引入的工作量,降低PG調整對ceph集群穩定性和性能的負面影響。

比如,PG由2調整到16,當然可以選擇直接調整到目標16,PG調整一步到位。也可以選擇小步調多次調整,推薦這樣的調整步調2->4->8->16。一步到位的調整策略與小步調多次調整策略各有優缺點,前者實現PG調整一次到位,但單次調整就引入大量的OSD內部遷移,雖然沒有OSD之間遷移;后者將單次引入的大量OSD內部遷移分散到了多次調整里,因此單次小步調調整引入的OSD內部遷移相對較少,降低了PG調整對ceph集群穩定性和性能的負面影響,但是由于后者分成多次調整達到最終目標,相對前者會引入額外的中間態OSD內部遷移,因此后者總的OSD內部遷移量會高于前者。因為實踐證明,后者的優點大于缺點,因此推薦采用PG小步調多次調整策略。

5. PGP調整的影響

為了簡化問題,抓住重點,假設OSD SET只有0和1,對象的分布如下:

5.1. PGP非冪次方調整

將pgp_num由2調整為3,pg_num依然為4。調整后,對象的分布如下:

從表中可知:?

  1. pgp_2分擔了原屬于pgp_0的pg_2,而pgp_2使用OSD SET 0,而pg_2原本就使用OSD SET 0,因此這一變動不會有任何數據遷移;

  2. pgp_0分擔了原屬于pgp_1的pg_3,而pg_3對應的OSD SET由1號變成了0號,因此pg_3的所有對象將由OSD SET 0遷移到OSD SET 1,涉及到了OSD之間的遷移,不同OSD之間就會有網絡通信開銷。

總之,共涉及OSD內部遷移0次,涉及OSD之間遷移6次。則inter_mig_ratio、ext_mig_ratio和work_load為:

因此,inter_mig_ratio代表了輕遷移率,而ext_mig_ratio代表了重遷移率,盡量減少重遷移,降低重遷移率,將重遷移變成輕遷移,最終減少數據遷移對ceph集群整體穩定性和性能的影響。

5.2. PGP冪次方調整

將pgp_num由2調整為3,pg_num依然為4。調整后,對象的分布如下:

總之,共涉及OSD內部遷移0次,涉及OSD之間遷移0次。則inter_mig_ratio、ext_mig_ratio和work_load為:

通過以上表格發現,雖然pg_2和pg_3對應的pgp有變化,但對應的OSD SET未發生變化,因此該調整,不會發生任何的數據遷移。?

5.3. PGP非冪次與冪次調整對比

PGP調整章節的分析內容僅限于ceph集群OSD SET組合情況未變話,而實際情況導致OSD SET組合情況變更的條件包括:副本策略變化、OSD增減、故障域變更等等。

inter_mig_ratio

ext_mig_ratio

work_load

非冪次(2->3)

0%

25%

1

冪次(2->4)

0%

0%

0

由上表可知,PGP冪次調整優于非冪次調整。

6. 疑問和思考

用戶文件的對象切割,對象名字的組成部分,對象到PG的映射過程,PG與PGP的關系,PG到OSD的映射過程,最后介紹了PG和PGP冪次和非冪次調整策略對ceph集群穩定性和性能的負面影響分析,但PG和PGP調整最終目標是好的,是為了配合ceph集群OSD擴容,是為了ceph集群數據分布的更均衡和合理,只是在選擇PG和PGP調整策略時要有所選擇,而并不是盲目的去實施。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/12097.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/12097.shtml
英文地址,請注明出處:http://en.pswp.cn/web/12097.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

sql實踐

1.從excel導入數據 在excel導入數據時要先在數據庫中創建對應的數據庫表 CREATE TABLE your_table_name (crawl_datetime DATE,url CHAR(255),company_name CHAR(255),company_size CHAR(255),company_type CHAR(255),job_type CHAR(255),job_name CHAR(255),edu CHAR(255),e…

暗區突圍TWITCH掉寶關聯帳號不了 無法關聯帳號 關聯不上

Twitch,作為全球知名的游戲直播平臺,常常攜手熱門游戲如《暗區突圍》舉辦互動活動,為玩家帶來獨特的參與體驗。在這個過程中,“綁定關聯”成為了連接直播觀眾與游戲世界的橋梁。簡單來說,Twitch綁定關聯《暗區突圍》指…

leetcode——鏈表的中間節點

876. 鏈表的中間結點 - 力扣(LeetCode) 鏈表的中間節點是一個簡單的鏈表OJ。我們要返回中間節點有兩種情況:節點數為奇數和節點數是偶數。如果是奇數則直接返回中間節點,如果是偶數則返回第二個中間節點。 這道題的解題思路是&a…

OpenAI 發布了免費的 GPT-4o,國內大模型還有哪些機會?

大家好,我是程序員X小鹿,前互聯網大廠程序員,自由職業2年,也一名 AIGC 愛好者,持續分享更多前沿的「AI 工具」和「AI副業玩法」,歡迎一起交流~ 這是今天在某乎看到一個問題:OpenAI 發完 GPT-4o&…

關閉 Visual Studio Code 項目中 的eslint的語法校驗 lintOnSave: false;; 項目運行起來之后 自動打開瀏覽器 端口

1、在 vue.config.js 配置 一個屬性 lintOnSave: false 2、配置兩個屬性 open: true, // 自動打開瀏覽器 port: 3000 // 端口 port 端口號根據自己的項目實際開發來 配置

Lumina-T2X 一個使用 DiT 架構的內容生成模型,可通過文本生成圖像、視頻、多視角 3D 對象和音頻剪輯。

Lumina-T2X 是一個新的內容生成系列模型,統一使用 DiT 架構。通過文本生成圖像、視頻、多視角 3D 對象和音頻剪輯。 可以在大幅提高生成質量的前提下大幅減少訓練成本,而且同一個架構支持不同的內容生成。圖像質量相當不錯。 由 50 億參數的 Flag-DiT …

structured concurrency

1. 基于 c executions的異步實現 - 從理論到實踐 - 知乎 (zhihu.com)

kubeadm部署k8s v1.30

k8s 1.30主要新功能 kubelet 重啟后穩健的 VolumeManager 重建(SIG Storage) 防止在卷還原過程中未經授權的卷模式轉換(SIG Storage) Pod 調度可用性(SIG Scheduling) PodTopologySpread 中的最小域數&a…

VitePress變成可視化了

VitePressSimple 非技術人員搭建博客的門檻又降低了,這個開源項目把VitePress變成可視化了。 要搭建博客、教程網站,VitePress是門檻最低的方案之一,唯一和技術有關的就是會用到編輯器來操作。 現在好了,VitePressSimple直接把Vit…

Java 枚舉的使用與反射應用

文章目錄 一、定義方式1.1 簡單定義1.2 帶參數定義 二、反射應用1. 反射獲取枚舉常量2. 反射獲取枚舉屬性3. 動態調用枚舉方法4. 動態設置枚舉屬性5. 判斷枚舉類型6. 反射獲取枚舉信息 單例模式:枚舉類型是一種有限實例的類,枚舉常量在定義時就被限定為一…

解決在云服務器上無法使用QQ郵箱發送郵件的問題

最近在做測試demo的時候發現,在本地可以使用qq郵箱的服務來進行郵件的發送,但是把項目部署到云服務器上就沒辦法發送郵件,并且報錯是連接超時: 向xxxxxqq.com用戶發送綁定郵箱驗證碼異常:Mail server connection fail…

leetcode234-Palindrome Linked List

題目 給你一個單鏈表的頭節點 head ,請你判斷該鏈表是否為回文鏈表 。如果是,返回 true ;否則,返回 false 。 示例 1: 輸入:head [1,2,2,1] 輸出:true 分析 可以用快慢指針的方式找到鏈表的…

自用代碼生成器代碼

代碼生成器 pom.xml文件中 <?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.ap…

【軟件測試】自動化測試 Selenium 篇(一)

一、什么是自動化測試 1、自動化測試介紹 自動化測試指軟件測試的自動化&#xff0c;在預設狀態下運行應用程序或者系統&#xff0c;預設條件包括正常和異常&#xff0c;最后評估運行結果。將人為驅動的測試行為轉化為機器執行的過程。 自動化就相當于將人工測試手段進行轉換…

【激活函數--下】非線性函數與ReLU函數

文章目錄 一、非線性函數在神經網絡中的重要性二、ReLU函數介紹及其實現2.1 ReLU函數概述2.2 ReLU函數的Python實現及可視化 一、非線性函數在神經網絡中的重要性 在神經網絡中&#xff0c;激活函數的選擇對于網絡的性能和能力至關重要。階躍函數和Sigmoid函數除了是激活函數的…

數據可視化-課堂記錄

week02 # 數據可視化的發展歷史 作用 格式塔原則 # 數據可視化的流程# 數據分析 指標體系建設 確定一個行業指標體系實現報表&#xff08;power bi python matplotlib seaborn pyecharts echarts&#xff09; # 數據分析面試 技術&#xff1a;sqlexcelpythonpowerbispss …

JS 實現冒泡排序

冒泡排序原理&#xff1a; 升序冒泡&#xff1a;兩次循環&#xff0c;相鄰元素兩兩比較&#xff0c;如果前面的大于后面的&#xff0c;就交互位置&#xff1b; 降序冒泡&#xff1a;兩次循環&#xff0c;相鄰元素兩兩比較&#xff0c;如果前面的小于后面的&#xff0c;就交互…

stable-diffusion-webui配置

源碼地址 https://github.com/AUTOMATIC1111/stable-diffusion-webui.git報錯Fresh install fail to load AttributeError: NoneType object has no attribute _id pydantic降級 pip uninstall pydantic pip install pydantic1.10.11記得要把clip-vit-large-patch14放在opena…

業務邏輯攻擊是什么,如何有效進行防護

想象一下&#xff1a;您的開發團隊剛推出了一款令人驚嘆的全新應用程序&#xff0c;它具有頂級的API安全性&#xff0c;通過客戶端保護對其進行了強化&#xff0c;甚至還設置了針對機器人攻擊的防御措施。你感到這款產品很有安全保障&#xff0c;自己的團隊出色地完成了工作。 …

解決Java Web應用中下載文件無法打開的問題

在Java Web應用中&#xff0c;文件下載是一個常見的功能。但有時候&#xff0c;即使代碼看起來正確&#xff0c;下載的文件卻無法正確打開。 問題描述 假設我們有以下代碼用于下載文件&#xff1a; response.addHeader("Content-Disposition", "attachment;fi…