Linux์—์„œ ๋””์Šคํฌ ํ™œ๋™์ด ์žˆ๋Š” ํ”„๋กœ์„ธ์Šค ์‹๋ณ„

TL; DR: ์ด ๊ธฐ์‚ฌ์—์„œ๋Š” ๋””์Šคํฌ์— ๋ฐ์ดํ„ฐ๋ฅผ ์“ฐ๋Š” Linux ํ”„๋กœ๊ทธ๋žจ์„ ์‹๋ณ„ํ•˜๋Š” ํŽธ๋ฆฌํ•˜๊ณ  ๋น ๋ฅด๋ฉฐ ์•ˆ์ •์ ์ธ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋””์Šคํฌ ํ•˜์œ„ ์‹œ์Šคํ…œ์—์„œ ํฌ๊ฑฐ๋‚˜ ๋น„์ •์ƒ์ ์œผ๋กœ ๋นˆ๋ฒˆํ•œ ๋กœ๋“œ๋ฅผ ์‹๋ณ„ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋˜๋ฉฐ ํŒŒ์ผ ์‹œ์Šคํ…œ์˜ ์˜ค๋ฒ„ํ—ค๋“œ๋ฅผ ์ถ”์ •ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ํŠนํžˆ PC์˜ SSD, EMMC ๋ฐ ๋‹จ์ผ ๋ณด๋“œ ์ปดํ“จํ„ฐ์˜ ํ”Œ๋ž˜์‹œ ๋ฉ”๋ชจ๋ฆฌ์— ํ•ด๋‹น๋ฉ๋‹ˆ๋‹ค.
์ด ๊ธฐ์‚ฌ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋™์•ˆ BTRFS ํŒŒ์ผ ์‹œ์Šคํ…œ์— ์ˆ˜ ํ‚ฌ๋กœ๋ฐ”์ดํŠธ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์“ฐ๋ฉด 3MB์˜ ์‹ค์ œ ๋ฐ์ดํ„ฐ๊ฐ€ ๋””์Šคํฌ์— ๊ธฐ๋ก๋œ๋‹ค๋Š” ์‚ฌ์‹ค์„ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค.

์†Œ๊ฐœ

"์•„ ๋ง๋„ ์•ˆ๋˜๋Š” ์†Œ๋ฆฌ์ž…๋‹ˆ๋‹ค. ์ตœ์‹  SSD์˜ ๋ฉ”๋ชจ๋ฆฌ ์…€์€ ์ˆ˜์‹ญ ๋…„ ๋™์•ˆ ์ •์ƒ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋ฉด ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ฑฑ์ •ํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค. ์Šค์™‘, ๊ฐ€์ƒ ๋จธ์‹  ๋ฐ ๋ธŒ๋ผ์šฐ์ € ํ”„๋กœํ•„ ํด๋”๋ฅผ HDD๋กœ ์ „์†กํ•˜๋Š” ๊ฒƒ์€ ํ›จ์”ฌ ์ ์Šต๋‹ˆ๋‹ค."-์— ๋Œ€ํ•œ ์งˆ๋ฌธ์— ๋Œ€ํ•œ ์ผ๋ฐ˜์ ์ธ ๋Œ€๋‹ต 150TBW๋ฅผ ๋ณด์žฅํ•˜๋Š” ์†”๋ฆฌ๋“œ ์Šคํ…Œ์ดํŠธ ๋“œ๋ผ์ด๋ธŒ์˜ ์‹ ๋ขฐ์„ฑ. ์ผ๋ฐ˜์ ์ธ ์†Œํ”„ํŠธ์›จ์–ด๊ฐ€ ์“ธ ์ˆ˜ ์žˆ๋Š” ๋ฐ์ดํ„ฐ์˜ ์–‘์„ ์ถ”์ •ํ•˜๋ฉด ํ•˜๋ฃจ์— 10-20GB๊ฐ€ ์ด๋ฏธ ํฐ ์ˆ˜์น˜์ธ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ตœ๋Œ€ 40GB๊ฐ€ ํ›จ์”ฌ ๋” ๋งŽ์Šต๋‹ˆ๋‹ค. ์ด ์ˆซ์ž๋ฅผ ๊ณ ๋ คํ•˜๋ฉด ๋Œ€๋‹ต์€ ๋งค์šฐ ํ•ฉ๋ฆฌ์ ์ž…๋‹ˆ๋‹ค. ๋‹ฌ์„ฑํ•˜๋Š” ๋ฐ 10๋…„์ด ๊ฑธ๋ฆฝ๋‹ˆ๋‹ค. ๋ณด์žฅ ๋งค์ผ 40GB์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ธฐ๋กํ•˜์—ฌ ๋ฎ์–ด์“ด ์…€ ์ˆ˜์— ๋Œ€ํ•œ ๊ฐ’์ž…๋‹ˆ๋‹ค.
ํ•˜์ง€๋งŒ 6๋…„ ๋งŒ์— ์ €๋Š” ์ด๋ฏธ ์„ธ ๋ฒˆ์งธ SSD๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ฒซ ๋ฒˆ์งธ SSD์˜ ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ๊ณ ์žฅ๋‚ฌ๊ณ , ๋‘ ๋ฒˆ์งธ SSD๋Š” ํ•˜๋ฃจ์— ์—ฌ๋Ÿฌ ๋ฒˆ ์…€ ๊ฐ„์— ๋ฐ์ดํ„ฐ๋ฅผ ์ด๋™ํ•˜๊ธฐ ์‹œ์ž‘ํ•˜์—ฌ ๋…นํ™” ์„œ๋น„์Šค๊ฐ€ 30์ดˆ ์ง€์—ฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์ƒˆ SSD๋ฅผ ์‚ฌ์šฉํ•œ ์ง€ 7๊ฐœ์›”์ด ์ง€๋‚˜์„œ SMART๋ฅผ ํ†ตํ•ด ๋“œ๋ผ์ด๋ธŒ ์ž์ฒด์—์„œ ๋ณด๊ณ ๋˜๋Š” ๊ธฐ๋ก๋œ ๋ฐ์ดํ„ฐ์˜ ์–‘์„ ํ™•์ธํ•˜๊ธฐ๋กœ ํ–ˆ์Šต๋‹ˆ๋‹ค.
19.7TB.
ํŒŒํ‹ฐ์…˜ ์ •๋ ฌ ๋ฐ FS ์„ค์ •์— ๋Œ€ํ•œ ๊ถŒ์žฅ ์‚ฌํ•ญ์— ๋”ฐ๋ผ ๊ตฌ์„ฑํ–ˆ์Œ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ๋‹จ 7๊ฐœ์›” ๋งŒ์— ๊ธฐ๋ก๋œ ๋ฐ์ดํ„ฐ์˜ ๋ณด์žฅ๋œ ์–‘์˜ 13%๋ฅผ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. ์Šค์™‘์„ ๊ฑฐ์˜ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ๊ฐ€์ƒ ๋จธ์‹  ๋””์Šคํฌ๊ฐ€ ์œ„์น˜ํ•ฉ๋‹ˆ๋‹ค. HDD์—!
์ด๋Š” ๋น„์ •์ƒ์ ์œผ๋กœ ํฐ ์ˆ˜์น˜๋กœ, ์ด ๋น„์œจ์—์„œ๋Š” 5๋…„ ๋””์Šคํฌ ๋ณด์ฆ ๊ธฐ๊ฐ„์ด ๋˜๊ธฐ ์ „์— ๋ณด์ฆ TBW๋ฅผ ์ดˆ๊ณผํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋‚ด ์ปดํ“จํ„ฐ๋Š” ํ•˜๋ฃจ์— 93GB๋ฅผ ์“ธ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค! 10๋ถ„ ์•ˆ์— ๋””์Šคํฌ์— ์–ผ๋งˆ๋‚˜ ๋งŽ์€ ๋ฐ์ดํ„ฐ๊ฐ€ ๊ธฐ๋ก๋˜๋Š”์ง€ ํ™•์ธํ•ด์•ผ ํ•˜๋Š”๋ฐ...

Total:
Writes Queued: 24,712, 2,237MiB
Writes Completed: 25,507, 2,237MiB
Write Merges: 58, 5,472KiB

2.2 GiB, ์˜คํ˜ธํ˜ธ!

๋””์Šคํฌ ์žฅ์น˜์— ๊ธฐ๋ก๋œ ๋ฐ์ดํ„ฐ ์–‘ ํ™•์ธ

์žฅ์น˜๊ฐ€ SMART(SSD, EMMC, ์ผ๋ถ€ ์‚ฐ์—…์šฉ MicroSD)๋ฅผ ์ง€์›ํ•˜๋Š” ๊ฒฝ์šฐ ๊ฐ€์žฅ ๋จผ์ € ํ•ด์•ผ ํ•  ์ผ์€ ํ”„๋กœ๊ทธ๋žจ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋“œ๋ผ์ด๋ธŒ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. smartctl, skdump ๋˜๋Š” mmc (mmc-utils์—์„œ).

smartctl ํ”„๋กœ๊ทธ๋žจ์˜ ์ถœ๋ ฅ ์˜ˆ

$ sudo smartctl -a /dev/sdb
smartctl 7.0 2019-03-31 r4903 [x86_64-linux-5.3.11-200.fc30.x86_64] (local build)
Copyright (C) 2002-18, Bruce Allen, Christian Franke, www.smartmontools.org

=== START OF INFORMATION SECTION ===
Model Family:     Samsung based SSDs
Device Model:     Samsung SSD 860 EVO mSATA 250GB
Serial Number:    S41MNC0KA13477K
LU WWN Device Id: 5 002538 e700fa64b
Firmware Version: RVT41B6Q
User Capacity:    250โ€ฏ059โ€ฏ350โ€ฏ016 bytes [250 GB]
Sector Size:      512 bytes logical/physical
Rotation Rate:    Solid State Device
Form Factor:      mSATA
Device is:        In smartctl database [for details use: -P show]
ATA Version is:   ACS-4 T13/BSR INCITS 529 revision 5
SATA Version is:  SATA 3.1, 6.0 Gb/s (current: 3.0 Gb/s)
Local Time is:    Tue Nov 19 01:48:50 2019 MSK
SMART support is: Available - device has SMART capability.
SMART support is: Enabled

=== START OF READ SMART DATA SECTION ===
SMART overall-health self-assessment test result: PASSED

General SMART Values:
Offline data collection status:  (0x00) Offline data collection activity
                                        was never started.
                                        Auto Offline Data Collection: Disabled.
Self-test execution status:      (   0) The previous self-test routine completed
                                        without error or no self-test has ever 
                                        been run.
Total time to complete Offline 
data collection:                (    0) seconds.
Offline data collection
capabilities:                    (0x53) SMART execute Offline immediate.
                                        Auto Offline data collection on/off support.
                                        Suspend Offline collection upon new
                                        command.
                                        No Offline surface scan supported.
                                        Self-test supported.
                                        No Conveyance Self-test supported.
                                        Selective Self-test supported.
SMART capabilities:            (0x0003) Saves SMART data before entering
                                        power-saving mode.
                                        Supports SMART auto save timer.
Error logging capability:        (0x01) Error logging supported.
                                        General Purpose Logging supported.
Short self-test routine 
recommended polling time:        (   2) minutes.
Extended self-test routine
recommended polling time:        (  85) minutes.
SCT capabilities:              (0x003d) SCT Status supported.
                                        SCT Error Recovery Control supported.
                                        SCT Feature Control supported.
                                        SCT Data Table supported.

SMART Attributes Data Structure revision number: 1
Vendor Specific SMART Attributes with Thresholds:
ID# ATTRIBUTE_NAME          FLAG     VALUE WORST THRESH TYPE      UPDATED  WHEN_FAILED RAW_VALUE
  5 Reallocated_Sector_Ct   0x0033   100   100   010    Pre-fail  Always       -       0
  9 Power_On_Hours          0x0032   098   098   000    Old_age   Always       -       5171
 12 Power_Cycle_Count       0x0032   099   099   000    Old_age   Always       -       459
177 Wear_Leveling_Count     0x0013   096   096   000    Pre-fail  Always       -       62
179 Used_Rsvd_Blk_Cnt_Tot   0x0013   100   100   010    Pre-fail  Always       -       0
181 Program_Fail_Cnt_Total  0x0032   100   100   010    Old_age   Always       -       0
182 Erase_Fail_Count_Total  0x0032   100   100   010    Old_age   Always       -       0
183 Runtime_Bad_Block       0x0013   100   100   010    Pre-fail  Always       -       0
187 Uncorrectable_Error_Cnt 0x0032   100   100   000    Old_age   Always       -       0
190 Airflow_Temperature_Cel 0x0032   058   039   000    Old_age   Always       -       42
195 ECC_Error_Rate          0x001a   200   200   000    Old_age   Always       -       0
199 CRC_Error_Count         0x003e   100   100   000    Old_age   Always       -       0
235 POR_Recovery_Count      0x0012   099   099   000    Old_age   Always       -       29
241 Total_LBAs_Written      0x0032   099   099   000    Old_age   Always       -       38615215765

SMART Error Log Version: 1
No Errors Logged

SMART Self-test log structure revision number 1
No self-tests have been logged.  [To run self-tests, use: smartctl -t]

SMART Selective self-test log data structure revision number 1
 SPAN  MIN_LBA  MAX_LBA  CURRENT_TEST_STATUS
    1        0        0  Not_testing
    2        0        0  Not_testing
    3        0        0  Not_testing
    4        0        0  Not_testing
    5        0        0  Not_testing
Selective self-test flags (0x0):
  After scanning selected spans, do NOT read-scan remainder of disk.
If Selective self-test is pending on power-up, resume after 0 minute delay.

๋‚ด SSD๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜ 241 Total_LBA_Written์— ๊ธฐ๋ก๋œ ๋ฐ์ดํ„ฐ์˜ ์–‘์„ ๋ฐ”์ดํŠธ๊ฐ€ ์•„๋‹Œ ๋…ผ๋ฆฌ ๋ธ”๋ก(LBA)์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. ์ œ ๊ฒฝ์šฐ ๋…ผ๋ฆฌ ๋ธ”๋ก์˜ ํฌ๊ธฐ๋Š” 512๋ฐ”์ดํŠธ์ž…๋‹ˆ๋‹ค(smartctl ์ถœ๋ ฅ์˜ ์„นํ„ฐ ํฌ๊ธฐ์—์„œ ๋ณผ ์ˆ˜ ์žˆ์Œ). ๋ฐ”์ดํŠธ๋ฅผ ์–ป์œผ๋ ค๋ฉด ๋งค๊ฐœ๋ณ€์ˆ˜ ๊ฐ’์— 512๋ฅผ ๊ณฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

38615215765 ร— 512 รท 1000 รท 1000 รท 1000 รท 1000 = 19,770 ะขะ‘
38615215765 ร— 512 รท 1024 รท 1024 รท 1024 รท 1024 = 17,981 ะขะธะ‘

ํ”„๋กœ๊ทธ๋žจ skdump ๋‚ด SSD์—์„œ๋Š” Total_LBA_Written ๊ฐ’์„ ๋‚˜๋ฆ„์˜ ๋ฐฉ์‹์œผ๋กœ ํ•ด์„ํ•˜๋ ค๊ณ  ์‹œ๋„ํ•˜๋ฏ€๋กœ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. 1296217.695 TB, ์ด๋Š” ๋ถ„๋ช…ํžˆ ์ž˜๋ชป๋œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์žฅ์น˜ ์ˆ˜์ค€์—์„œ ๊ธฐ๋ก๋œ ์ •๋ณด์˜ ์–‘์„ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ํ”„๋กœ๊ทธ๋žจ์„ ์‚ฌ์šฉํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. btrace ํŒจํ‚ค์ง€์—์„œ blktrace. ํ”„๋กœ๊ทธ๋žจ์ด ์‹คํ–‰๋˜๋Š” ์ „์ฒด ์‹œ๊ฐ„์— ๋Œ€ํ•œ ์ผ๋ฐ˜ ํ†ต๊ณ„์™€ ๊ธฐ๋ก์„ ์ˆ˜ํ–‰ํ•œ ๊ฐœ๋ณ„ ํ”„๋กœ์„ธ์Šค ๋ฐ ์Šค๋ ˆ๋“œ(์ปค๋„ ํฌํ•จ)๊ฐ€ ๋ชจ๋‘ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ ๋ช…๋ น์„ ์‹คํ–‰ํ•˜์—ฌ 10๋ถ„ ์•ˆ์— ์ •๋ณด๋ฅผ ์ˆ˜์ง‘ํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ /dev/sdb๋Š” ๋””์Šคํฌ์ž…๋‹ˆ๋‹ค.

# btrace -w 600 -a write /dev/sdb

์ผ๋ฐ˜์ ์ธ ๋ช…๋ น ์ถœ๋ ฅ

โ€ฆ
  8,16   0     3253    50.085433192     0  C  WS 125424240 + 64 [0]
  8,16   0     3254    50.085550024     0  C  WS 193577744 + 64 [0]
  8,16   0     3255    50.085685165     0  C  WS 197246976 + 64 [0]
  8,16   0     3256    50.085936852     0  C  WS 125736264 + 128 [0]
  8,16   0     3257    50.086060780     0  C  WS 96261752 + 64 [0]
  8,16   0     3258    50.086195031     0  C  WS 94948640 + 64 [0]
  8,16   0     3259    50.086327355     0  C  WS 124656144 + 64 [0]
  8,16   0     3260    50.086843733 15368  C WSM 310218496 + 32 [0]
  8,16   0     3261    50.086975238   753  A WSM 310218368 + 32 <- (8,20) 291339904
  8,16   0     3262    50.086975560   753  Q WSM 310218368 + 32 [dmcrypt_write/2]
  8,16   0     3263    50.086977345   753  G WSM 310218368 + 32 [dmcrypt_write/2]
  8,16   0     3264    50.086978072   753  I WSM 310218368 + 32 [dmcrypt_write/2]
  8,16   0     3265    50.086979159   753  D WSM 310218368 + 32 [dmcrypt_write/2]
  8,16   0     3266    50.087055685     0  C WSM 310218368 + 32 [0]
  8,16   0     3267    50.087060168   753  A WSM 310218592 + 160 <- (8,20) 291340128
  8,16   0     3268    50.087060367   753  Q WSM 310218592 + 160 [dmcrypt_write/2]
  8,16   0     3269    50.087061242   753  G WSM 310218592 + 160 [dmcrypt_write/2]
  8,16   0     3270    50.087061698   753  I WSM 310218592 + 160 [dmcrypt_write/2]
  8,16   0     3271    50.087062361   753  D WSM 310218592 + 160 [dmcrypt_write/2]
  8,16   0     3272    50.087386179     0  C WSM 310218592 + 160 [0]
  8,16   0     3273    50.087436417 15368  A FWS 0 + 0 <- (253,1) 0
  8,16   0     3274    50.087437471 15368  Q FWS [LS Thread]
  8,16   0     3275    50.087440862 15368  G FWS [LS Thread]
  8,16   0     3276    50.088300047     0  C  WS 0 [0]
  8,16   0     3277    50.088470917   753  A WFSM 18882688 + 8 <- (8,20) 4224
  8,16   0     3278    50.088471091   753  Q WFSM 18882688 + 8 [dmcrypt_write/2]
  8,16   0     3279    50.088471688   753  G WFSM 18882688 + 8 [dmcrypt_write/2]
  8,16   0     3280    50.088474334 32254  D WSM 18882688 + 8 [kworker/0:2H]
  8,16   0     3281    50.088515572     0  C WSM 18882688 + 8 [0]
  8,16   0     3282    50.089229069     0  C WSM 18882688 [0]
CPU0 (8,16):
 Reads Queued:           0,        0KiB  Writes Queued:         345,   25,932KiB
 Read Dispatches:        0,        0KiB  Write Dispatches:      331,   25,788KiB
 Reads Requeued:         0               Writes Requeued:         0
 Reads Completed:        0,        0KiB  Writes Completed:    1,597,  117,112KiB
 Read Merges:            0,        0KiB  Write Merges:            1,       16KiB
 Read depth:             0               Write depth:           177
 IO unplugs:             0               Timer unplugs:           0
CPU1 (8,16):
 Reads Queued:           0,        0KiB  Writes Queued:         502,   39,948KiB
 Read Dispatches:        0,        0KiB  Write Dispatches:      495,   40,076KiB
 Reads Requeued:         0               Writes Requeued:         0
 Reads Completed:        0,        0KiB  Writes Completed:        0,        0KiB
 Read Merges:            0,        0KiB  Write Merges:            0,        0KiB
 Read depth:             0               Write depth:           177
 IO unplugs:             0               Timer unplugs:           0
CPU2 (8,16):
 Reads Queued:           0,        0KiB  Writes Queued:         297,   26,800KiB
 Read Dispatches:        0,        0KiB  Write Dispatches:      287,   26,800KiB
 Reads Requeued:         0               Writes Requeued:         0
 Reads Completed:        0,        0KiB  Writes Completed:        0,        0KiB
 Read Merges:            0,        0KiB  Write Merges:            0,        0KiB
 Read depth:             0               Write depth:           177
 IO unplugs:             0               Timer unplugs:           0
CPU3 (8,16):
 Reads Queued:           0,        0KiB  Writes Queued:         418,   24,432KiB
 Read Dispatches:        0,        0KiB  Write Dispatches:      408,   24,448KiB
 Reads Requeued:         0               Writes Requeued:         0
 Reads Completed:        0,        0KiB  Writes Completed:        0,        0KiB
 Read Merges:            0,        0KiB  Write Merges:            2,      272KiB
 Read depth:             0               Write depth:           177
 IO unplugs:             0               Timer unplugs:           0

Total (8,16):
 Reads Queued:           0,        0KiB  Writes Queued:       1,562,  117,112KiB
 Read Dispatches:        0,        0KiB  Write Dispatches:    1,521,  117,112KiB
 Reads Requeued:         0               Writes Requeued:         0
 Reads Completed:        0,        0KiB  Writes Completed:    1,597,  117,112KiB
 Read Merges:            0,        0KiB  Write Merges:            3,      288KiB
 IO unplugs:             0               Timer unplugs:           0

Throughput (R/W): 0KiB/s / 2,338KiB/s
Events (8,16): 9,287 entries
Skips: 0 forward (0 -   0.0%)

btrace ์‹ค์ œ ๋…น์Œ๋œ ๋ฐ์ดํ„ฐ์˜ ์–‘์„ ๋ช…ํ™•ํ•˜๊ฒŒ ๋ณผ ์ˆ˜ ์žˆ์ง€๋งŒ ์ถœ๋ ฅ์—์„œ โ€‹โ€‹์–ด๋–ค ํ”„๋กœ๊ทธ๋žจ์ด ๋…น์Œํ•˜๊ณ  ์žˆ๋Š”์ง€ ์ดํ•ดํ•˜๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค.

๋“œ๋ผ์ด๋ธŒ์— ์“ฐ๋Š” ํ”„๋กœ๊ทธ๋žจ ํ™•์ธ

ํ”„๋กœ๊ทธ๋žจ iotop ๋””์Šคํฌ์— ์“ฐ๋Š” ํ”„๋กœ์„ธ์Šค์™€ ์“ฐ์—ฌ์ง„ ๋ฐ์ดํ„ฐ์˜ ํฌ๊ธฐ๋ฅผ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.
๊ฐ€์žฅ ํŽธ๋ฆฌํ•œ ์ถœ๋ ฅ์€ ๋‹ค์Œ ๋งค๊ฐœ๋ณ€์ˆ˜์— ์˜ํ•ด ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค.

# iotop -obPat

์ƒ˜ํ”Œ ํ”„๋กœ๊ทธ๋žจ ์ถœ๋ ฅ

02:55:47 Total DISK READ :       0.00 B/s | Total DISK WRITE :      30.65 K/s
02:55:47 Actual DISK READ:       0.00 B/s | Actual DISK WRITE:       0.00 B/s
    TIME  PID  PRIO  USER     DISK READ  DISK WRITE  SWAPIN      IO    COMMAND
b'02:55:47   753 be/4 root          0.00 B      0.00 B  0.00 %  0.04 % [dmcrypt_write/2]'
b'02:55:47   788 be/4 root         72.00 K     18.27 M  0.00 %  0.02 % [btrfs-transacti]'
b'02:55:47 15057 be/4 valdikss    216.00 K    283.05 M  0.00 %  0.01 % firefox'
b'02:55:47  1588 ?dif root          0.00 B      0.00 B  0.00 %  0.00 % Xorg -nolisten tcp -auth /var/run/sddm/{398f030f-9667-4dff-b371-81eaae48dfdf} -background none -noreset -displayfd 18 -seat seat0 vt1'
b'02:55:47 15692 be/4 valdikss    988.00 K      9.41 M  0.00 %  0.00 % python3 /usr/bin/gajim'
b'02:55:47 15730 ?dif valdikss      9.07 M      0.00 B  0.00 %  0.00 % telegram-desktop --'
b'02:55:47  2174 ?dif valdikss   1840.00 K      2.47 M  0.00 %  0.00 % yakuake'
b'02:55:47 19827 be/4 root         16.00 K    896.00 K  0.00 %  0.00 % [kworker/u16:7-events_unbound]'
b'02:55:47 19074 be/4 root         16.00 K    480.00 K  0.00 %  0.00 % [kworker/u16:4-btrfs-endio-write]'
b'02:55:47 19006 be/4 root         16.00 K   1872.00 K  0.00 %  0.00 % [kworker/u16:1-events_unbound]'
b'02:55:47  1429 be/4 root        484.00 K      0.00 B  0.00 %  0.00 % accounts-daemon'
b'02:55:47 15820 be/4 valdikss    312.00 K      0.00 B  0.00 %  0.00 % firefox -contentproc -childID 6 -isForBrowser -prefsLen 7894 -prefMapSize 223880 -parentBuildID 20191022164834 -greomni /usr/lib64/firefox/omni.ja -appomni /usr/lib64/firefox/browser/omni.ja -appdir /usr/lib64/firefox/browser 15057 tab'
b'02:55:47  2125 ?dif valdikss      0.00 B     92.00 K  0.00 %  0.00 % plasmashell'
b'02:55:47  1268 be/3 root          0.00 B      4.00 K  0.00 %  0.00 % auditd'
b'02:55:47  1414 be/4 root          0.00 B      4.00 K  0.00 %  0.00 % sssd_nss --uid 0 --gid 0 --logger=files'
b'02:55:47 15238 be/4 valdikss      0.00 B      4.00 K  0.00 %  0.00 % thunderbird'
b'02:55:47 18605 be/4 root          0.00 B      3.19 M  0.00 %  0.00 % [kworker/u16:0-btrfs-endio-write]'
b'02:55:47 18867 be/4 root          0.00 B     96.00 K  0.00 %  0.00 % [kworker/u16:5-btrfs-endio-meta]'
b'02:55:47 19070 be/4 root          0.00 B    160.00 K  0.00 %  0.00 % [kworker/u16:2-btrfs-freespace-write]'
b'02:55:47 19645 be/4 root          0.00 B      2.17 M  0.00 %  0.00 % [kworker/u16:3-events_unbound]'
b'02:55:47 19982 be/4 root          0.00 B    496.00 K  0.00 %  0.00 % [kworker/u16:6-btrfs-endio-write]'

Firefox๋Š” iotop ์‹คํ–‰ ๋ช‡ ๋ถ„ ๋งŒ์— 283MB๋ฅผ ๊ธฐ๋กํ•˜์—ฌ ๋ˆˆ๊ธธ์„ ์‚ฌ๋กœ์žก์Šต๋‹ˆ๋‹ค.

๊ธฐ๋กํ•  ํŒŒ์ผ ๊ฒฐ์ •

๋””์Šคํฌ๋ฅผ ๊ฐ•๊ฐ„ํ•˜๋Š” ๊ณผ์ •์— ๋Œ€ํ•œ ์ •๋ณด๋„ ์ข‹์ง€๋งŒ ๋…น์Œ์ด ์ด๋ฃจ์–ด์ง€๋Š” ๊ฒฝ๋กœ๋Š” ๋”์šฑ ์ข‹์Šต๋‹ˆ๋‹ค.

ํ”„๋กœ๊ทธ๋žจ์„ ํ™œ์šฉํ•ด๋ณด์ž fatrace, ํŒŒ์ผ ์‹œ์Šคํ…œ์˜ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์ถ”์ ํ•ฉ๋‹ˆ๋‹ค.

# fatrace -f W

์ƒ˜ํ”Œ ํ”„๋กœ๊ทธ๋žจ ์ถœ๋ ฅ

firefox(15057): CW /home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/moz-extension+++e5c304fb-af40-498a-9ba8-47eb0416e933^userContextId=4294967295/idb/3647222921wleabcEoxlt-eengsairo.sqlite-wal
firefox(15057): CW /home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/moz-extension+++e5c304fb-af40-498a-9ba8-47eb0416e933^userContextId=4294967295/idb/3647222921wleabcEoxlt-eengsairo.sqlite
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/https+++habr.com/ls/data.sqlite-journal
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/https+++habr.com/ls/data.sqlite-journal
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/https+++habr.com/ls/data.sqlite-journal
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/https+++habr.com/ls/data.sqlite-journal
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/https+++habr.com/ls/data.sqlite-journal
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/https+++habr.com/ls/data.sqlite-journal
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/https+++habr.com/ls/data.sqlite-journal
firefox(15057): CW /home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/https+++habr.com/ls/usage-journal
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/https+++habr.com/ls/usage
firefox(15057): CW /home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/https+++habr.com/ls/usage
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/https+++habr.com/ls/data.sqlite-journal
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/https+++habr.com/ls/data.sqlite
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/https+++habr.com/ls/data.sqlite
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/https+++habr.com/ls/data.sqlite
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/webappsstore.sqlite-wal
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/webappsstore.sqlite-wal
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/webappsstore.sqlite-wal
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/webappsstore.sqlite-wal
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/webappsstore.sqlite-wal
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/webappsstore.sqlite-wal
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/webappsstore.sqlite-wal
firefox(15057): CW /home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/https+++habr.com/ls/data.sqlite-journal
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/webappsstore.sqlite
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/webappsstore.sqlite
firefox(15057): W /home/valdikss/.mozilla/firefox/xyf4vqh2.default/webappsstore.sqlite

Fatrace๋Š” inotify๋ฅผ ํ†ตํ•ด ํŒŒ์ผ์— ์•ก์„ธ์Šคํ•œ๋‹ค๋Š” ์‚ฌ์‹ค์„ ๋งค์šฐ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ถ”์ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ธฐ๋ก๋œ ๋ฐ์ดํ„ฐ์˜ ์–‘์„ ํ‘œ์‹œํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์ถœ๋ ฅ์—์„œ Habr์ด ๊ธ€์„ ์“ฐ๋Š” ๋™์•ˆ ๋ธŒ๋ผ์šฐ์ €์˜ ๋กœ์ปฌ ์ €์žฅ์†Œ์— ๋‚ด ๊ธ€์„ ์ €์žฅํ•˜๋Š” ๋ฐฉ๋ฒ•๊ณผ ๊ทธ๋ฃน ๋‹จ์ถ• ๋‹ค์ด์–ผ ํ™•์žฅ ํ”„๋กœ๊ทธ๋žจ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฃน ๋‹จ์ถ• ๋‹ค์ด์–ผ ํ™•์žฅ ํ”„๋กœ๊ทธ๋žจ์€ fatrace๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐœ๊ฒฌํ•  ์ˆ˜ ์žˆ๋“ฏ์ด ๋งค๋ฒˆ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์Šต๋‹ˆ๋‹ค. 30 ์ดˆ. ์“ฐ๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์ฝ๋Š”๋‹ค: CW ํŒŒ์ผ์ด ์ฝ๊ธฐ ๋ฐ ์“ฐ๊ธฐ๋ฅผ ์œ„ํ•ด ์—ด๋ ค ์žˆ๋‹ค๊ณ  ํ‘œ์‹œํ•˜๊ธฐ ์ „์— ํŒŒ์ผ์ด ๋ˆ„๋ฝ๋œ ๊ฒฝ์šฐ ํŒŒ์ผ์„ ๋™์‹œ์— ์ƒ์„ฑํ•˜์ง€๋งŒ(O_RDWR|O_CREAT ํ”Œ๋ž˜๊ทธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ openat์ด๋ผ๊ณ  ํ•จ) ์‹ค์ œ๋กœ ํŒŒ์ผ์— ์ •๋ณด๊ฐ€ ๊ธฐ๋ก๋˜์—ˆ์Œ์„ ๋‚˜ํƒ€๋‚ด์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค.

๋งŒ์ผ์„ ๋Œ€๋น„ํ•ด ์ด๋ฅผ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ํŒŒ์ผ ์‹œ์Šคํ…œ ํ˜ธ์ถœ์— ๋Œ€ํ•œ ํ•„ํ„ฐ์™€ ํ•จ๊ป˜ strace๋ฅผ ์‚ฌ์šฉํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

strace -yy -e trace=open,openat,close,write -f -p 15057 2>&1 | grep extension

๋ช…๋ น ์ถœ๋ ฅ

[pid 20352] openat(AT_FDCWD, "/home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/moz-extension+++e5c304fb-af40-498a-9ba8-47eb0416e933^userContextId=4294967295/idb/3647222921wleabcEoxlt-eengsairo.sqlite", O_RDWR|O_CREAT|O_CLOEXEC, 0644) = 153</home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/moz-extension+++e5c304fb-af40-498a-9ba8-47eb0416e933^userContextId=4294967295/idb/3647222921wleabcEoxlt-eengsairo.sqlite>
[pid 20352] read(153</home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/moz-extension+++e5c304fb-af40-498a-9ba8-47eb0416e933^userContextId=4294967295/idb/3647222921wleabcEoxlt-eengsairo.sqlite>, "SQLite format 3 20 22 @   d 23"..., 100) = 100
[pid 20352] read(153</home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/moz-extension+++e5c304fb-af40-498a-9ba8-47eb0416e933^userContextId=4294967295/idb/3647222921wleabcEoxlt-eengsairo.sqlite>, "SQLite format 3 20 22 @   d 23"..., 4096) = 4096
[pid 20352] openat(AT_FDCWD, "/home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/moz-extension+++e5c304fb-af40-498a-9ba8-47eb0416e933^userContextId=4294967295/idb/3647222921wleabcEoxlt-eengsairo.sqlite-wal", O_RDWR|O_CREAT|O_CLOEXEC, 0644) = 166</home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/moz-extension+++e5c304fb-af40-498a-9ba8-47eb0416e933^userContextId=4294967295/idb/3647222921wleabcEoxlt-eengsairo.sqlite-wal>
โ€ฆ
[pid 20352] read(54</home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/moz-extension+++e5c304fb-af40-498a-9ba8-47eb0416e933^userContextId=4294967295/idb/3647222921wleabcEoxlt-eengsairo.sqlite>, " r4304364354354364-  4204!4'414" 250 &"..., 4096) = 4096
[pid 20352] read(54</home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/moz-extension+++e5c304fb-af40-498a-9ba8-47eb0416e933^userContextId=4294967295/idb/3647222921wleabcEoxlt-eengsairo.sqlite>, " 136Pt2262504 O24532016:"16.27 r245306>2461t1q370"..., 4096) = 4096
[pid 20352] close(77</home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/moz-extension+++e5c304fb-af40-498a-9ba8-47eb0416e933^userContextId=4294967295/idb/3647222921wleabcEoxlt-eengsairo.sqlite-wal>) = 0
[pid 20352] close(54</home/valdikss/.mozilla/firefox/xyf4vqh2.default/storage/default/moz-extension+++e5c304fb-af40-498a-9ba8-47eb0416e933^userContextId=4294967295/idb/3647222921wleabcEoxlt-eengsairo.sqlite>) = 0

์ „ํ™”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค write(), ์ด๋Š” ํŒŒ์ผ์— ํ•ญ๋ชฉ์ด ์—†์Œ์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

ํŒŒ์ผ ์‹œ์Šคํ…œ ์˜ค๋ฒ„ํ—ค๋“œ ๊ฒฐ์ •

ํŒ๋…๊ฐ’์˜ ํฐ ์ฐจ์ด iotop ะธ btrace ์ˆ˜๋™์œผ๋กœ ํŒŒ์ผ์— ๋ฐ์ดํ„ฐ๋ฅผ ์“ฐ๊ณ  btrace ํŒ๋…๊ฐ’์„ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜์—ฌ ํŒŒ์ผ ์‹œ์Šคํ…œ์„ ํ…Œ์ŠคํŠธํ•˜๋Š” ์•„์ด๋””์–ด๋ฅผ ์–ป์—ˆ์Šต๋‹ˆ๋‹ค.

์‹œ์Šคํ…œ ๋น„์ƒ ๋ชจ๋“œ๋กœ ๋ถ€ํŒ…ํ•˜์—ฌ ๋””์Šคํฌ ์“ฐ๊ธฐ๋ฅผ ์™„์ „ํžˆ ์ œ์™ธํ•˜๊ณ  ์ˆ˜๋™์œผ๋กœ ์“ฐ๋Š” ๊ฒฝ์šฐ ๋ช‡ ๋ฐ”์ดํŠธ ๋ฐ์ดํ„ฐ๋ฅผ ๊ธฐ์กด ํŒŒ์ผ๋กœ, btrace๋ฅผ SSD๋กœ btrfs ๋ณด๊ณ ์„œ ๋…น์Œ 3 ๋ฉ”๊ฐ€ ๋ฐ”์ดํŠธ ์‹ค์ œ ๋ฐ์ดํ„ฐ. 8GB ํ”Œ๋ž˜์‹œ ๋“œ๋ผ์ด๋ธŒ์— ์ƒˆ๋กœ ์ƒ์„ฑ๋œ ํŒŒ์ผ ์‹œ์Šคํ…œ์€ 264๋ฐ”์ดํŠธ๋ฅผ ์“ธ ๋•Œ ์ตœ์†Œ XNUMXKiB๋ฅผ ์”๋‹ˆ๋‹ค.
๋น„๊ตํ•˜์ž๋ฉด, ext4์˜ ํŒŒ์ผ์— ๋ช‡ ๋ฐ”์ดํŠธ๋ฅผ ์“ฐ๋ฉด ๊ฒฐ๊ตญ 24KB์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ๋””์Šคํฌ์— ์“ฐ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

2017๋…„, Jayashree Mohan, Rohan Kadekodi, Vijay Chidambaram ๋‹ค์–‘ํ•œ ํŒŒ์ผ ์‹œ์Šคํ…œ์˜ ์“ฐ๊ธฐ ์ฆํญ์— ๋Œ€ํ•œ ์—ฐ๊ตฌ ์ˆ˜ํ–‰4KB ์“ฐ๊ธฐ์—์„œ btrfs ๋ฐ ext4์— ๋Œ€ํ•œ ๊ฒฐ๊ณผ๋Š” ๋‚ด ๊ฒฐ๊ณผ์™€ ์ผ์น˜ํ•ฉ๋‹ˆ๋‹ค.

Linux์—์„œ ๋””์Šคํฌ ํ™œ๋™์ด ์žˆ๋Š” ํ”„๋กœ์„ธ์Šค ์‹๋ณ„

๊ฒฐ๋ก  ๋ฐ ๊ฒฐ๋ก 

์„ค๋ช…๋œ ์กฐ์ž‘์„ ํ†ตํ•ด ๋‹ค์Œ์ด ๋ฐœ๊ฒฌ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

  1. CUPS ์ธ์‡„ ๋ฐ๋ชฌ์ด ํ”„๋ฆฐํ„ฐ ์ž‘์—… ์ƒํƒœ๋ฅผ /var/์— ์ž์ฃผ ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค.์บ์‹œ/cups ๋งค๋ถ„. /var/๋ฅผ ์ง€์›Œ์„œ ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.์Šคํ’€/cups (์ธ์‡„ ์ž‘์—…์€ ์—†์—ˆ์ง€๋งŒ);
  2. Firefox์šฉ ๊ทธ๋ฃน ๋‹จ์ถ• ๋‹ค์ด์–ผ ํ™•์žฅ ํ”„๋กœ๊ทธ๋žจ์ด 30์ดˆ๋งˆ๋‹ค ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์ฝ๋Š”๋‹ค๋Š” ์‚ฌ์‹ค;
  3. Fedora์˜ ๋‹ค์–‘ํ•œ ์„ฑ๋Šฅ ์ถ”์  ์„œ๋น„์Šค์— ์˜ํ•œ ์ •๊ธฐ์ ์ธ ๋กœ๊น…์œผ๋กœ ์ธํ•ด ์ˆ˜ ๋ฉ”๊ฐ€๋ฐ”์ดํŠธ์˜ ๋ฐ์ดํ„ฐ๊ฐ€ btrfs์— ๊ธฐ๋ก๋ฉ๋‹ˆ๋‹ค: pmcd.service, pmie.service, pmlogger.service;
  4. btrfs๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์†Œ๋Ÿ‰์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์“ธ ๋•Œ ์—„์ฒญ๋‚œ ์ฆํญ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

๊ฒฐ๋ก : ํ”„๋กœ๊ทธ๋žจ์ด ์†Œ๋Ÿ‰์˜ ๋ฐ์ดํ„ฐ(๋ช‡ ํ‚ฌ๋กœ๋ฐ”์ดํŠธ)๋ฅผ ์ž์ฃผ ์“ฐ๋Š” ๊ฒฝ์šฐ btrfs๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ๋ฉ”๊ฐ€๋ฐ”์ดํŠธ์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ๊ธฐ๋ก๋ฉ๋‹ˆ๋‹ค. ์ด๋Š” ํŠนํžˆ MicroSD ๊ธฐ๋ฐ˜ OS๋ฅผ ๊ฐ–์ถ˜ ๋‹จ์ผ ๋ณด๋“œ ์ปดํ“จํ„ฐ์— ํ•ด๋‹น๋ฉ๋‹ˆ๋‹ค.

์ถœ์ฒ˜ : habr.com

์ฝ”๋ฉ˜ํŠธ๋ฅผ ์ถ”๊ฐ€