MessagePack for Go
高速で効率的なMessagePackシリアライゼーションライブラリ。標準のencoding/jsonパッケージと同様のAPIを提供し、最大5倍の性能向上を実現。
MessagePack for Go
概要
vmihailenco/msgpackは、Go言語向けの高速で効率的なMessagePackシリアライゼーションライブラリです。標準のencoding/jsonパッケージと同様のAPIを提供しながら、最大5倍の性能向上を実現します。オブジェクトプーリングやコンパクトエンコーディングなどの最適化により、メモリ効率と処理速度の両方で優れた性能を発揮します。
主な特徴
- 高性能: オブジェクトプーリングとメモリ管理の最適化により、JSONと比較して約5倍の高速化を実現
- 使いやすいAPI:
encoding/jsonと同様のインターフェースで、既存コードからの移行が容易 - 拡張性: カスタムタイプのエンコード/デコード、MessagePack拡張機能のサポート
- 柔軟な設定: 構造体タグによるフィールド制御、配列エンコーディング、キーのソートなど
- 部分的デコード: クエリシステムによる特定データの効率的な抽出
インストール
go get github.com/vmihailenco/msgpack/v5
基本的な使い方
シンプルなエンコード/デコード
package main
import (
"fmt"
"github.com/vmihailenco/msgpack/v5"
)
type Item struct {
ID int `msgpack:"id"`
Name string `msgpack:"name"`
Tags []string `msgpack:"tags,omitempty"`
}
func main() {
// エンコード
item := &Item{
ID: 1,
Name: "サンプルアイテム",
Tags: []string{"タグ1", "タグ2"},
}
data, err := msgpack.Marshal(item)
if err != nil {
panic(err)
}
// デコード
var decoded Item
err = msgpack.Unmarshal(data, &decoded)
if err != nil {
panic(err)
}
fmt.Printf("デコード結果: %+v\n", decoded)
}
ストリーミングAPI
package main
import (
"bytes"
"github.com/vmihailenco/msgpack/v5"
)
func streamingExample() {
buf := new(bytes.Buffer)
// エンコーダーの作成
enc := msgpack.NewEncoder(buf)
enc.SetSortMapKeys(true) // マップキーをソート
enc.UseCompactInts(true) // コンパクトな整数エンコーディング
// 複数のオブジェクトをエンコード
data := []interface{}{
map[string]interface{}{"id": 1, "name": "item1"},
map[string]interface{}{"id": 2, "name": "item2"},
}
for _, item := range data {
if err := enc.Encode(item); err != nil {
panic(err)
}
}
// デコーダーの作成
dec := msgpack.NewDecoder(buf)
// ストリーミングデコード
for {
var item interface{}
err := dec.Decode(&item)
if err != nil {
break
}
fmt.Printf("デコード: %v\n", item)
}
}
高度な機能
カスタムエンコーディング
type CustomTime struct {
time.Time
}
// カスタムエンコーダーの実装
func (ct CustomTime) EncodeMsgpack(enc *msgpack.Encoder) error {
return enc.EncodeInt64(ct.Unix())
}
// カスタムデコーダーの実装
func (ct *CustomTime) DecodeMsgpack(dec *msgpack.Decoder) error {
unix, err := dec.DecodeInt64()
if err != nil {
return err
}
ct.Time = time.Unix(unix, 0)
return nil
}
MessagePack拡張機能
// カスタムタイプの拡張登録
func init() {
msgpack.RegisterExt(1, (*CustomType)(nil))
}
type CustomType struct {
Data string
}
func (ct *CustomType) MarshalMsgpack() ([]byte, error) {
return []byte(ct.Data), nil
}
func (ct *CustomType) UnmarshalMsgpack(data []byte) error {
ct.Data = string(data)
return nil
}
クエリシステム
// 特定のフィールドのみを抽出
func queryExample(data []byte) {
dec := msgpack.NewDecoder(bytes.NewReader(data))
// "users.*.name"パスでユーザー名のみを抽出
values, err := dec.Query("users.*.name")
if err != nil {
panic(err)
}
for _, name := range values {
fmt.Printf("ユーザー名: %v\n", name)
}
}
構造体の配列エンコーディング
type CompactUser struct {
_msgpack struct{} `msgpack:",as_array"` // 配列としてエンコード
ID int
Name string
Email string
}
// または、エンコーダー全体で設定
enc := msgpack.NewEncoder(buf)
enc.UseArrayEncodedStructs(true)
設定オプション
構造体タグ
type User struct {
ID int `msgpack:"id"` // フィールド名の指定
Name string `msgpack:"name,alias:username"` // エイリアスの設定
Email string `msgpack:"email,omitempty"` // 空の場合は省略
Password string `msgpack:"-"` // エンコード対象外
Tags []string `msgpack:"tags,omitempty"` // 空配列の場合は省略
Metadata map[string]interface{} `msgpack:",inline"` // インライン展開
}
エンコーダー設定
enc := msgpack.NewEncoder(writer)
// コンパクトな整数エンコーディング
enc.UseCompactInts(true)
// マップキーのソート
enc.SetSortMapKeys(true)
// 構造体を配列としてエンコード
enc.UseArrayEncodedStructs(true)
// カスタムタグの使用
enc.SetCustomStructTag("json")
// time.Timeの文字列エンコーディング
enc.SetOmitEmpty(true)
パフォーマンスベンチマーク
BenchmarkStructVmihailencoMsgpack-4 200000 12814 ns/op 2128 B/op 26 allocs/op
BenchmarkStructJSON-4 20000 69438 ns/op 7864 B/op 26 allocs/op
BenchmarkStructGOB-4 10000 104331 ns/op 14664 B/op 278 allocs/op
主な性能特性:
- JSONと比較して約5.4倍高速
- GOBと比較して約8.1倍高速
- メモリ使用量が少ない(2128バイト vs JSONの7864バイト)
- アロケーション回数が同等(26回)
実践的な使用例
APIレスポンスのシリアライゼーション
type APIResponse struct {
Status string `msgpack:"status"`
Code int `msgpack:"code"`
Data interface{} `msgpack:"data"`
Message string `msgpack:"message,omitempty"`
}
func handleRequest(w http.ResponseWriter, r *http.Request) {
response := &APIResponse{
Status: "success",
Code: 200,
Data: getUserData(),
}
data, err := msgpack.Marshal(response)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/x-msgpack")
w.Write(data)
}
メッセージキューでの使用
type Message struct {
ID string `msgpack:"id"`
Type string `msgpack:"type"`
Timestamp time.Time `msgpack:"timestamp"`
Payload []byte `msgpack:"payload"`
}
func publishMessage(queue MessageQueue, msg *Message) error {
data, err := msgpack.Marshal(msg)
if err != nil {
return err
}
return queue.Publish(data)
}
func consumeMessage(data []byte) (*Message, error) {
var msg Message
err := msgpack.Unmarshal(data, &msg)
return &msg, err
}
データストレージ
type CacheEntry struct {
Key string `msgpack:"k"`
Value interface{} `msgpack:"v"`
ExpiresAt time.Time `msgpack:"e"`
}
func (c *Cache) Set(key string, value interface{}, ttl time.Duration) error {
entry := &CacheEntry{
Key: key,
Value: value,
ExpiresAt: time.Now().Add(ttl),
}
data, err := msgpack.Marshal(entry)
if err != nil {
return err
}
return c.store.Put(key, data)
}
他のシリアライゼーション形式との比較
JSON vs MessagePack
| 特性 | JSON | MessagePack |
|---|---|---|
| 可読性 | 高い(テキスト形式) | 低い(バイナリ形式) |
| サイズ | 大きい | コンパクト(20-50%削減) |
| 速度 | 標準的 | 高速(約5倍) |
| 型情報 | 限定的 | 豊富(整数型の区別など) |
| ブラウザサポート | ネイティブ | ライブラリ必要 |
Protocol Buffers vs MessagePack
| 特性 | Protocol Buffers | MessagePack |
|---|---|---|
| スキーマ | 必須(.proto) | 不要(スキーマレス) |
| 型安全性 | 高い | 中程度 |
| 柔軟性 | 低い | 高い |
| サイズ | 最小 | 小さい |
| 開発速度 | 遅い(スキーマ定義必要) | 速い |
まとめ
vmihailenco/msgpackは、Go言語で高性能なシリアライゼーションが必要な場合の優れた選択肢です。標準的なAPIと豊富な機能により、JSONからの移行も容易で、マイクロサービス、リアルタイム通信、データストレージなど幅広い用途に適用できます。特に性能が重要なアプリケーションでは、その効率性が大きな利点となります。