100만개의 post가 있으면 렌더링하는데 얼마나 걸릴까 궁금했습니다. 원래 100만파일까지 블로그를 쓸 일은 없지만, 사전데이터를 이용하여 빌드하는 때에는 100만개 가까운 static html이 생성될 수도 있게다고 생각해서 시도했던 것입니다. 그래서 10만개의 markdown을 만들고 실험해 보았습니다.
10만번 loop
목적하는 파일의 수는 100만이지만, 시험상으로 10만개의 파일을 테스트 해 보았습니다.
10만번 loop를 하는 코드를 다음과 같이 준비했습니다.
1
2
3
4
5
| [int]$Number = 100000
foreach($i in (1..$Number)){
Write-Host ("{0,6:d6}" -f $i)
}
|
시간이 얼마나 걸리나요? 한 번 알아보았습니다. 함수로 정의하고 measure-command
로 호출해 보았습니다.
1
2
3
4
5
6
7
8
9
10
11
| Function Make-DummyMD {
Param(
[int]$Number = 100000
)
foreach($i in (1..$Number)){
Write-Host ("{0,6:d6}" -f $i)
}
}
measure-command {Make-DummyMD}
|
결과
1
2
3
4
5
6
7
8
9
10
11
| Days : 0
Hours : 0
Minutes : 1
Seconds : 46
Milliseconds : 117
Ticks : 1061175564
TotalDays : 0.00122821245833333
TotalHours : 0.029477099
TotalMinutes : 1.76862594
TotalSeconds : 106.1175564
TotalMilliseconds : 106117.5564
|
1분 46초가 걸렸네요. powershell을 사용할 때는 runtime 퍼포먼스보다는 작성하는 사람의 퍼포먼스를 중시해서 사용합시다.
markdown의 본문을 만들려고 합니다.
git clone https://gitlab.com/pages/nfhugo
순서
git clone https://gitlab.com/pages/nfhugo
여기에 나와있는 다음의 순서대로 실행할 것입니다.
1. Install go and Hugo
2. Fork, clone or download this project
3. Preview your project: hugo server
4. Add content
5. Generate the website: hugo (optional)
1. Install go and Hugo
1번은 p047 문서를 참조하시면 실행을 빨리 하실 수 있습니다. 환경은 goormide를 이용합니다.
2. 사이트 생성
2번, site를 만들고 post를 추가합니다.
site를 만드는 방법은 공식적인 방법과 템플릿을 다운로드하는 방법이 있습니다.
- hugo new site [sitename]
- git clone https://gitlab.com/pages/nfhugo
여기에서는 첫 번째, 공식적인 방법을 이용하였습니다.
다음의 커맨드로 사이트를 만들고 테마를 설치했습니다. 아마도 블로그를 구성하고 테스트하면서 여러번 실행해본 커맨드일 것입니다.
1
2
3
4
5
6
| hugo new site indigo_testsite
cd indigo_testsite
git init
git submodule add "https://github.com/AngeloStavrow/indigo.git" themes/indigo
git submodule update --recursive --init
# hugo server -D
|
두 번째 방법은 gitlab에서 제공하는 템플릿을 이용하여 만드는 방법입니다. nfhugo는 hugo와 netlify와 결합된 템플릿을 미리 만들어 둔 것입니다.
1
2
3
4
5
| cd /workspace/test
#hugo new site blog && cd
git clone https://gitlab.com/pages/nfhugo
cd nfhugo
|
파일 생성
파일 생성은 hugo 명령어 hugo new $title
를 이용하여 다음과 같이 합니다.
타이틀에 확장자 .md를 붙일 수도 있고 안붙일 수도 있습니다만, vscode로 편집을 한다면 있는 쪽이 좋습니다.
1
2
3
4
5
6
| $Number = 100000
foreach($i in (1..$Number)){
$title = ("t{0,6:d6} dummy title.md" -f $i)
Write-Host $title
hugo new $title
}
|
위의 코드는 매번 hugo new $title
을 실행하는 것이므로 효율이 좋지 않습니다. 매우 오래 걸립니다. go언어의 설치와 hugo의 빌드시간을 합한 것보다도 훨씬 더 오래 걸립니다. 빠르지 않은 머신에서 프로그램을 실행하면 퍼포먼스를 확실하게 확인할 수 있는 장점(?)이 있습니다.
아예 지우고 다시 만들었습니다.
1
2
| $files = Get-ChildItem -Recurse -Include *.md
remove-item $files.FullName
|
Powershell로 파일 다루기 기본편
파일을 만들고 내용을 읽고 지우는 것은 powershell에서는 어렵지 않습니다. 예를 들면 다음과 같습니다. 다음 예제는 만들고 지우기를 합니다.
1
2
3
4
5
6
7
| "" > hello1.md
"" > hello2.md
"" > hello3.md
"" > hello4.md
"" > hello5.md
$files = Get-ChildItem -Recurse -Include *.md
remove-item $files.FullName
|
내용 구하기
무의미한 문자열 Lorem Ipsum 문자열을 https://www.lipsum.com/feed/html 에서 구했습니다. 이 문자열은 호출할 때마다 바뀝니다.
1
2
3
4
5
6
7
8
9
10
| [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 <# using TLS 1.2 is vitally important #>
$req = Invoke-Webrequest -URI "www.lipsum.com/feed/html"
$loremIpsum = $req.ParsedHtml.getElementById('lipsum').textContent
$content = @"
---
subtitle: ""
tags: []
---
$loremIpsum
"@
|
아쉽게도 윈도우즈의 powershell 5.1 에서는 ParseHtml 이 존재합니다만, powershell core 6 부터는 존재하지 않습니다. linux에서도 사용해야 했기 때문에 iexplorer의 COM 객체를 넘기는 것이 불가능해졌기 때문입니다.
Pwsh Core에서는 PowerHTML
linux에서는 PowerHTML
과 같은 thrid party를 이용해야 합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
PS /root> Install-Module -Name PowerHTML
Untrusted repository
You are installing the modules from an untrusted repository. If you trust this repository, change its InstallationPolicy value by running the
Set-PSRepository cmdlet. Are you sure you want to install the modules from 'PSGallery'?
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "N"): Y
PS /root> Import-Module PowerHTML
PS /root> Get-Module PowerHTML
ModuleType Version PreRelease Name ExportedCommands
---------- ------- ---------- ---- ----------------
Script 0.1.7 PowerHTML ConvertFrom-Html
|
명령어는 ConvertFrom-Html
하나밖에 없군요.
ConvertFrom-Html -URI “https://www.lipsum.com/feed/html"
$req.ParsedHtml.getElementById(‘lipsum’).textContent
이제 준비된 문자열을 파일에 전부 입력합니다.
예제 파일 만들기 코드
1
2
3
4
5
| $Number = 100000 # 10만
foreach($i in (1..$Number)){
$title = ("t{0,7:d7} dummy title.md" -f $i)
$content >> $title
}
|
결과1 100만파일 만들기 - 40분
파일을 만들기까지는 40분 걸렸습니다. 이 디렉토리는 가능하면 탐색기 같은 GUI 프로그램으로는 살펴보지 않는 쪽이 좋습니다. GUI Object를 너무 다량으로 만들어 시스템에 무리를 만들 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
| PS C:\temp\nowhereblog1\content\posts> Get-Date
>> $Number = 1000000 # 100만
>> foreach($i in (1..$Number)) {
>> $filename = ("t{0,6:d6} dummy title.md" -f $i)
>> $content >> $filename
>> }
>> Get-Date
>>
2020年8月13日 12:05:40
2020年8月13日 12:45:46
|
결과2 100만파일 빌드 - 중도포기
hugo
커맨드로 build해 보았습니다.
1
2
3
4
| PS C:\temp\nowhereblog1> Get-Date; hugo; Get-Date
2020年8月13日 12:52:51
Building sites …
|
빌드하는 것은 Single 코어만 사용하고 있는 듯 했는데, 멀티 코어를 사용하고 있는 시스템이어서 15% 정도의 CPU 사용률을 보였습니다.
그런데 메모리가 문제네요.
결국 빌드 시작한 후로 35분쯤 경과하여 중단할 수 밖에 없었습니다.
50만파일로 build 재시도
절반정도의 50만 파일을 지웠습니다. 지우는 것도 꽤 시간이 걸립니다. 혹시나 해서 pwsh이 아닌 cmd에서 삭제를 해봤는데 역시 오래걸립니다. 지울 때 시간을 재보지 않았는데 10분은 더 걸렸던 것 같습니다.
1
2
3
| PS C:\temp\nowhereblog1\content\posts> 5..9 | % {del "t$($_)*.*"}
PS C:\temp\nowhereblog1\content\posts> (dir).count
500000
|
일단 안정적으로 보여서 잠시 다른 작업을 하고 나중에 와봤습니다.
그랬더니 로그인도 잘 되지 않아 어렵게 로그인을 한 뒤의 상태를 보니, 메모리가 이런 상태가 되어 있었습니다.
빌드는 완성되지 않았습니다. 이미 2시간도 지난 뒤였기 때문에, 일단 빌드를 중단했습니다.
10만파일로 build 재시도
10만 파일로 다시 시도를 해보니, 2시간이상 지나도 끝나지 않고, 메모리 사용률이 올라가는 속도는 더디었지만 9기가 이상으로 사용중이어서, 아슬아슬했습니다. 하지만 결과는 성공.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| C:\temp\nowhereblog1>hugo
Building sites …
| EN
-------------------+---------
Pages | 100008
Paginator pages | 19998
Non-page files | 0
Static files | 64
Processed images | 0
Aliases | 2
Sitemaps | 1
Cleaned | 0
Total in 8610330 ms
|
143분, 즉 2시간 40분만에 성공하였습니다.
단순히 선형계산이면, 1만파일이면 14분 걸리릴까 하고 예상합니다.
간단히 build된 /public/ 디렉토리를 serve해 브라우저에서 확인해 보았습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
| @'
package main
import (
"net/http"
)
func main() {
http.Handle("/", http.StripPrefix("/", http.FileServer(http.Dir("./public"))))
http.ListenAndServe(":80", nil)
}
'@ > test.go
go run ./test.go
|
결과화면
결과화면입니다.
포스트 10개씩 1만개의 Page를 가진 CMS가 생성되었습니다.
레퍼런스