Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Imagemagickを抹殺 #2143

Merged
merged 41 commits into from
Dec 11, 2023
Merged

Imagemagickを抹殺 #2143

merged 41 commits into from
Dec 11, 2023

Conversation

logica0419
Copy link
Member

@logica0419 logica0419 commented Dec 7, 2023

背景

  • PNGへの変換がPure Goで動いており、アニメーションGIFのリサイズだけがImagemagickに依存していた
  • 実行ファイルに依存があるの、アンチパターンっぽい気がするのでやめたかった
  • 容量も機能もでかいソフトなので、現在の使い方はあまりにもったいない
  • 以前挑戦したdistrolessイメージへの載せ替えがImagemagickのせいで頓挫したため、ひっぺがしたかった

実装

  • 軽く調べて、Pure GoでアニメーションGIFのリサイズをしている人を参考にして実装した
  • 元の比率を保つというImagemagickのresizeの仕様を引き継ぐようにした
  • 他のファイル形式同様、mks2013Filterを使ってリサイズする
  • Timeoutは無くなったが、1685KBのファイルのアイコン変換が5秒弱で終わっているので、そこまで気にしなくても良い

@logica0419 logica0419 requested a review from motoki317 December 7, 2023 23:16
@logica0419 logica0419 enabled auto-merge December 8, 2023 15:20
@logica0419 logica0419 disabled auto-merge December 8, 2023 15:21
@logica0419 logica0419 force-pushed the eliminate-imagemagick branch from c3873b0 to 4b6339b Compare December 8, 2023 17:04
@logica0419 logica0419 removed the request for review from motoki317 December 8, 2023 17:05
Copy link
Member

@motoki317 motoki317 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

細かいライブラリの使い方までは見てないですが、動作確認が取れてれば良いと思います
(実際に目で確認して、画像サイズ・ファイルサイズが縮小できてるか、縦横比があってるかどうか それをテストでコード化できれば最高)

確認してほしいコメントをいくつかしました

gif周りのテストが変更後は存在しなくなってるように見えるので、できればPRに上げてくれた画像などで追加したいですね

service/imaging/processor_default.go Outdated Show resolved Hide resolved
service/imaging/processor_default.go Outdated Show resolved Hide resolved
@motoki317
Copy link
Member

1685KBのファイルのアイコン変換が5秒弱で

そんなに掛かるんだ... PRの検証を見たところ、imagemagickとそう大差は無いようですが、気に留めておきたいかもですね

Co-authored-by: motoki317 <motoki317@gmail.com>
@logica0419
Copy link
Member Author

1685KBのファイルのアイコン変換が5秒弱で

そんなに掛かるんだ... PRの検証を見たところ、imagemagickとそう大差は無いようですが、気に留めておきたいかもですね

フレーム数だけリサイズをしなければいけないので、それだけかかるのは仕方なそうな感じがあります
たぶん並列化すれば少しマシになるかな〜と思いますが、それだけ瞬間的にリソースを食うのでsemaphoreとかでバランス取るのが難しそう

Co-authored-by: motoki317 <motoki317@gmail.com>
pikachu0310
pikachu0310 previously approved these changes Dec 9, 2023
service/imaging/processor_default.go Outdated Show resolved Hide resolved
service/imaging/processor_default_test.go Show resolved Hide resolved
@sapphi-red
Copy link
Contributor

メモリ使用量はチェックしておくと良さそうです

@logica0419
Copy link
Member Author

cube
上記の画像(883KB、375 x 375)の変換を使用し、性能比較

cube_resized
これが変換後(690KB、256 x 256)

時間

PUT /users/me/iconのRTTを計測
Chrome DevtoolsのNetworkタブより、Timingを使って測定
それぞれ5回計測

Imagemagick

1.85 秒
1.74 秒
1.82 秒
1.79 秒
1.75 秒

Pure Go

2.13 秒
2.12 秒
2.12 秒
2.13 秒
2.10 秒

わずかに遅くなっている

CPU / メモリ使用量測定 (top)

top -b -d 0.1 -n 30 | grep --line-buffered -e traQ -e %MEM -e convert
0.1秒間隔で3秒プロファイリングし、変化があったところを記録

Imagemagick

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1911720 root      20   0 1274408  46616  26100 S   0.0   0.5   0:00.30 traQ

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1917716 root      20   0   77952  68476   5944 R  70.0   0.7   0:00.07 convert
1911720 root      20   0 1274408  46616  26100 S  10.0   0.5   0:00.31 traQ

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1917716 root      20   0  163716 156560   5804 R 154.5   1.5   0:00.24 convert
1911720 root      20   0 1274408  46616  26100 S   0.0   0.5   0:00.31 traQ

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1917716 root      20   0   78596  70344   5804 R 400.0   0.7   0:00.71 convert
1911720 root      20   0 1274408  46616  26100 S   0.0   0.5   0:00.31 traQ

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1917716 root      20   0   88732  81572   5804 R 400.0   0.8   0:01.11 convert
1911720 root      20   0 1274408  46616  26100 S   0.0   0.5   0:00.31 traQ

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1917716 root      20   0   52480  45688   5804 R 272.7   0.4   0:01.41 convert
1911720 root      20   0 1274408  46616  26100 S   0.0   0.5   0:00.31 traQ

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1917716 root      20   0   52508  45816   5804 R 340.0   0.4   0:01.75 convert
1911720 root      20   0 1274408  46616  26100 S   0.0   0.5   0:00.31 traQ

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1917716 root      20   0   52540  45840   5804 R 390.0   0.5   0:02.14 convert
1911720 root      20   0 1274408  46616  26100 S   0.0   0.5   0:00.31 traQ

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1917716 root      20   0   53600  46896   5804 R 345.5   0.5   0:02.52 convert
1911720 root      20   0 1274408  46616  26100 S   0.0   0.5   0:00.31 traQ

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1917716 root      20   0   52604  45900   5804 R 400.0   0.5   0:02.93 convert
1911720 root      20   0 1274408  46616  26100 S   0.0   0.5   0:00.31 traQ

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1917716 root      20   0   43088  35836   5804 R 200.0   0.4   0:03.25 convert
1911720 root      20   0 1274408  46616  26100 S   0.0   0.5   0:00.31 traQ

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1917716 root      20   0  177884 170608   5804 R 210.0   1.7   0:03.46 convert
1911720 root      20   0 1274408  46616  26100 S   0.0   0.5   0:00.31 traQ

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1917716 root      20   0  178276 170872   5804 R 100.0   1.7   0:03.56 convert
1911720 root      20   0 1274408  46616  26100 S   0.0   0.5   0:00.31 traQ

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1917716 root      20   0  179088 172076   5804 R 181.8   1.7   0:03.76 convert
1911720 root      20   0 1274408  46616  26100 S   0.0   0.5   0:00.31 traQ

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1917716 root      20   0  180596 173680   5804 R 200.0   1.7   0:03.97 convert
1911720 root      20   0 1274408  46616  26100 S   0.0   0.5   0:00.31 traQ

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1917716 root      20   0  182460 175404   5804 R 250.0   1.7   0:04.22 convert
1911720 root      20   0 1274408  46616  26100 S   0.0   0.5   0:00.31 traQ

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1917716 root      20   0  184080 177024   5804 R 263.6   1.7   0:04.51 convert
1911720 root      20   0 1274408  46616  26100 S   0.0   0.5   0:00.31 traQ

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1911720 root      20   0 1274408  46616  26100 S  20.0   0.5   0:00.33 traQ

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1911720 root      20   0 1274408  46876  26136 S   0.0   0.5   0:00.33 traQ

Pure Go

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1921912 root      20   0 1273660  34568  25316 S   0.0   0.3   0:00.11 traQ

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1921912 root      20   0 1273660  37360  25320 S  10.0   0.4   0:00.12 traQ

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1921912 root      20   0 1273660  44276  25836 S  54.5   0.4   0:00.18 traQ

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1921912 root      20   0 1273916  45968  26172 S 120.0   0.5   0:00.30 traQ

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1921912 root      20   0 1273916  48816  26176 S 118.2   0.5   0:00.43 traQ

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1921912 root      20   0 1274428  49784  26176 S 110.0   0.5   0:00.54 traQ

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1921912 root      20   0 1274428  49784  26176 S 109.1   0.5   0:00.66 traQ

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1921912 root      20   0 1274428  50424  26176 S 120.0   0.5   0:00.78 traQ

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1921912 root      20   0 1274428  51600  26176 S 110.0   0.5   0:00.89 traQ

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1921912 root      20   0 1274428  53336  26176 S 118.2   0.5   0:01.02 traQ

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1921912 root      20   0 1274428  56300  26176 S 120.0   0.6   0:01.14 traQ

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1921912 root      20   0 1274940  57460  26236 S 120.0   0.6   0:01.26 traQ

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1921912 root      20   0 1274940  57460  26236 S 109.1   0.6   0:01.38 traQ

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1921912 root      20   0 1274940  57636  26236 S 110.0   0.6   0:01.49 traQ

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1921912 root      20   0 1274940  57636  26236 S 130.0   0.6   0:01.62 traQ

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1921912 root      20   0 1274940  58768  26236 S 100.0   0.6   0:01.73 traQ

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1921912 root      20   0 1274940  59524  26236 S 120.0   0.6   0:01.85 traQ

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1921912 root      20   0 1274940  60048  26236 S 109.1   0.6   0:01.97 traQ

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1921912 root      20   0 1274940  60048  26236 S 110.0   0.6   0:02.08 traQ

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1921912 root      20   0 1274940  60048  26236 S 120.0   0.6   0:02.20 traQ

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1921912 root      20   0 1274940  60048  26236 S 109.1   0.6   0:02.32 traQ

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1921912 root      20   0 1274940  60048  26236 S 110.0   0.6   0:02.43 traQ

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1921912 root      20   0 1274940  56104  26360 S  50.0   0.6   0:02.48 traQ

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
1921912 root      20   0 1274940  56104  26360 S   0.0   0.6   0:02.48 traQ

最大CPU使用率が1/3程度になっているため、並列化による高速化は可能そう

メモリ使用量測定 (pprof)

main.goを以下に書き換えプロファイリング

package main

import (
	"image"
	"log"
	"os"
	"time"

	"github.com/pkg/profile"
	"github.com/traPtitech/traQ/service/imaging"
)

func main() {
	defer profile.Start(profile.MemProfile, profile.ProfilePath(".")).Stop()

	t := time.Now()

	f, _ := os.Open("cube.gif")

	_, _ = imaging.NewProcessor(imaging.Config{
		MaxPixels:        2560 * 1600,
		Concurrency:      1,
		ThumbnailMaxSize: image.Pt(360, 480),
		ImageMagickPath:  {Imagemagickのパス (Pure Goの時は設定していない)},
	}).FitAnimationGIF(f, 256, 256)

	log.Printf("done: %v", time.Since(t))
}

Imagemagick

logica@TakutoPC-Sequent:~/prj/traP/SysAd/traQ$ go run main.go
2023/12/11 03:24:55 profile: memory profiling enabled (rate 4096), mem.pprof
2023/12/11 03:24:56 done: 1.06636952s
2023/12/11 03:24:56 profile: memory profiling disabled, mem.pprof
logica@TakutoPC-Sequent:~/prj/traP/SysAd/traQ$ go tool pprof mem.pprof
File: main
Type: inuse_space
Time: Dec 11, 2023 at 3:24am (JST)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) top
Showing nodes accounting for 1.98MB, 100% of 1.98MB total
      flat  flat%   sum%        cum   cum%
    1.98MB   100%   100%     1.98MB   100%  bytes.growSlice
         0     0%   100%     1.98MB   100%  bytes.(*Buffer).ReadFrom
         0     0%   100%     1.98MB   100%  bytes.(*Buffer).grow
         0     0%   100%     1.98MB   100%  github.com/traPtitech/traQ/service/imaging.(*defaultProcessor).FitAnimationGIF
         0     0%   100%     1.98MB   100%  github.com/traPtitech/traQ/utils/imaging.ResizeAnimationGIF
         0     0%   100%     1.98MB   100%  github.com/traPtitech/traQ/utils/imaging.cmdPipe
         0     0%   100%     1.98MB   100%  io.Copy (inline)
         0     0%   100%     1.98MB   100%  io.copyBuffer
         0     0%   100%     1.98MB   100%  main.main
         0     0%   100%     1.98MB   100%  runtime.main

Pure Go

logica@TakutoPC-Sequent:~/prj/traP/SysAd/traQ$ go run main.go
2023/12/11 03:28:01 profile: memory profiling enabled (rate 4096), mem.pprof
2023/12/11 03:28:03 done: 2.031658606s
2023/12/11 03:28:03 profile: memory profiling disabled, mem.pprof
logica@TakutoPC-Sequent:~/prj/traP/SysAd/traQ$ go tool pprof mem.pprof
File: main
Type: inuse_space
Time: Dec 11, 2023 at 3:28am (JST)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) top
Showing nodes accounting for 8.98MB, 99.80% of 9MB total
Dropped 12 nodes (cum <= 0.05MB)
Showing top 10 nodes out of 20
      flat  flat%   sum%        cum   cum%
    7.59MB 84.37% 84.37%     7.59MB 84.37%  image.NewPaletted
    0.91MB 10.07% 94.44%     0.91MB 10.07%  image.NewNRGBA
    0.23MB  2.51% 96.95%     0.23MB  2.51%  image/gif.(*decoder).readColorTable
    0.14MB  1.55% 98.50%     0.14MB  1.55%  runtime.malg
    0.07MB  0.78% 99.28%     0.07MB  0.78%  github.com/hajimehoshi/go-mp3/internal/frame.init
    0.05MB  0.52% 99.80%     0.05MB  0.52%  github.com/disintegration/imaging.precomputeWeights
         0     0% 99.80%     0.42MB  4.66%  github.com/disintegration/imaging.Resize
         0     0% 99.80%     0.42MB  4.66%  github.com/disintegration/imaging.resizeHorizontal
         0     0% 99.80%     8.78MB 97.53%  github.com/traPtitech/traQ/service/imaging.(*defaultProcessor).FitAnimationGIF
         0     0% 99.80%     6.13MB 68.13%  image/gif.(*decoder).decode

Copy link
Member

@motoki317 motoki317 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

頑張って並列化してくれたのは面白いけど、本番で必ずしもコア数が多いマシンや多くのCPUが許可されたコンテナで動くとは限らないので、計測時ほど差は出ないかもしれないです

service/imaging/processor_default.go Outdated Show resolved Hide resolved
service/imaging/processor_default.go Outdated Show resolved Hide resolved
service/imaging/processor_default_test.go Outdated Show resolved Hide resolved
@logica0419 logica0419 requested a review from motoki317 December 11, 2023 06:02
circular pointer reference
@logica0419 logica0419 requested a review from motoki317 December 11, 2023 06:26
motoki317
motoki317 previously approved these changes Dec 11, 2023
Copy link
Member

@motoki317 motoki317 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

テスト書いてあるしまあ良いかな...(複雑なのはちょっと気になるけど)

あとこれは別PRにしてほしいけど、ファイルアップロードとアイコンアップロード周りでごちゃっとしてたり重複する処理が書かれてたりするから、リファクタリングしたさがある

utils/utils.go Outdated
func Map[T, R any](s []T, mapper func(item T) R) []R {
ret := make([]R, len(s))
for i := range s {
ret[i] = mapper(s[i])
}
return ret
}

func IoReaderToBytes(r io.Reader) ([]byte, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

io.ReadAllが同値かも

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ReadAllって使って良かったっけってなっちゃったけど、よく考えたらそれioutilの話か…ってなりました
書き換えます

utils/utils.go Outdated
return buf.Bytes(), nil
}

func MustIoReaderToBytes(r io.Reader) []byte {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lo.Mustが便利かも

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

初耳だった
見ます

@logica0419
Copy link
Member Author

ファイルアップロードとアイコンアップロード周りでごちゃっとしてたり重複する処理が書かれてたりするから、リファクタリングしたさがある

これやると #1875 とかもやりやすくなるのかなって少し思いました

@motoki317
Copy link
Member

それはアップロード処理とは関係無いような

@logica0419
Copy link
Member Author

なるほど、何も見ずとりあえず言ってみただけなので多分そっちが正しい
ちょっと後で見てみますね

@logica0419 logica0419 merged commit 72e9bba into master Dec 11, 2023
5 checks passed
@logica0419 logica0419 deleted the eliminate-imagemagick branch December 11, 2023 10:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants