This is a golang package for Memcached. It is a simple and easy to use package.
- Completed Memcached text protocol, includes meta text protocol.
- Protocol-level value compression with MC-COMPRESS-compatible MC-FLAGS encoding.
- Integrated serialization and deserialization function
- Cluster support, multiple hash algorithm support, include: crc32, murmur3, redezvous and also custom hash algorithm.
- Fully connection pool features support.
- CLI tool support.
-
SASL support. - support TCP、UDP and Unix domain socket transport.
go get github.com/yeqown/memcached@latestOr you can install the CLI binary by running:
go install github.com/yeqown/memcached/cmd/memcached-cli@latestMore memcached-cli usage could be found in CLI.
There is a simple example to show how to use this package. More examples could be found in the example directory.
package main
import (
"context"
"time"
"github.com/yeqown/memcached"
)
func main() {
// 1. build client
// addrs is a string, if you have multiple memcached servers, you can use comma to separate them.
// e.g. "localhost:11211,localhost:11212,localhost:11213"
addrs := "localhost:11211"
// client support options, you can set the options to client.
// e.g. memcached.New(addrs, memcached.WithDialTimeout(5*time.Second))
client, err := memcached.New(addrs)
if err != nil {
panic(err)
}
// 2. use client
// now, you can use the client API to finish your work.
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
version, err := client.Version(ctx)
if err != nil {
panic(err)
}
println("Version: ", version)
if err = client.Set(ctx, "key", []byte("value"), 0, 0); err != nil {
panic(err)
}
if err = client.Set(ctx, "key2", []byte("value2"), 0, 0); err != nil {
panic(err)
}
items, err := client.Gets(ctx, "key", "key2")
if err != nil {
panic(err)
}
for _, item := range items {
println("key: ", item.Key, " value: ", string(item.Value))
}
}The client can encode protocol-level compression metadata in the Memcached flags field using the MC-COMPRESS layout documented in docs/MC-COMPRESS-SPEC-v1.0.md.
- Reads automatically detect compliant MC-FLAGS values, transparently decompress supported payloads, and return caller-facing flags after decode.
- Writes can opt into the built-in MC-COMPRESS behavior by installing
codec.NewCompressCodec(...)throughWithCodec(...). - You can replace the built-in behavior with your own
WithCodec(...)implementation to customize howvalueandflagsare encoded and decoded, usingkeyonly as context. APP-FLAGSare preserved in the 16-bit application-visible portion of the encoded flags word while stored on the wire.MetaGetautomatically requests server flags when a codec is configured so decode always has the metadata it needs.- Values smaller than the threshold, or payloads that do not shrink after compression, are stored as plain values.
AppendandPrependare rejected when the built-in compression codec is enabled.
import (
"github.com/yeqown/memcached"
memcodec "github.com/yeqown/memcached/codec"
)
compressionCodec, err := memcodec.NewCompressCodec(memcodec.CompressionAlgorithmDeflate, 1024, 6)
if err != nil {
panic(err)
}
client, err := memcached.New(
"localhost:11211",
memcached.WithCodec(compressionCodec),
)
if err != nil {
panic(err)
}
if err = client.Set(ctx, "article:1", payload, 7, time.Hour); err != nil {
panic(err)
}
item, err := client.Get(ctx, "article:1")
if err != nil {
panic(err)
}
println("flags:", item.Flags)
println("value size:", len(item.Value))Currently supported algorithms:
memcodec.CompressionAlgorithmNonememcodec.CompressionAlgorithmDeflatememcodec.CompressionAlgorithmLZ4memcodec.CompressionAlgorithmSnappymemcodec.CompressionAlgorithmZstd
A custom codec can be installed like this:
client, err := memcached.New(
"localhost:11211",
memcached.WithCodec(myCodec),
)The codec receives key as context, but can only return transformed value and flags. Other memcached metadata such as CAS, TTL, size, opaque values, and meta protocol tokens remain under the client's control.
Now, we have implemented some commands, and we will implement more commands in the future.
| Command | Status | API Usage | Description |
|---|---|---|---|
| ---- | ----- | STORAGE COMMANDS | --- |
| Set | ✅ | Set(ctx context.Context, key string, value []byte, flag uint32, expiry time.Duration) error |
Set a key-value pair to memcached |
| Add | ✅ | Add(ctx context.Context, key string, value []byte, flag uint32, expiry time.Duration) error |
Add a key-value pair to memcached |
| Replace | ✅ | Replace(ctx context.Context, key string, value []byte, flag uint32, expiry time.Duration) error |
Replace a key-value pair to memcached |
| Append | ✅ | Append(ctx context.Context, key string, value []byte, flag uint32, expiry time.Duration) error |
Append a value to the key |
| Prepend | ✅ | Prepend(ctx context.Context, key string, value []byte, flag uint32, expiry time.Duration) error |
Prepend a value to the key |
| Cas | ✅ | Cas(ctx context.Context, key string, value []byte, flag uint32, expiry time.Duration, cas uint64) error |
Compare and set a key-value pair to memcached |
| ---- | ----- | RETRIEVAL COMMANDS | --- |
| Gets | ✅ | Gets(ctx context.Context, keys ...string) ([]*Item, error) |
Get a value by key from memcached with cas value |
| Get | ✅ | Get(ctx context.Context, key string) (*Item, error) |
Get a value by key from memcached |
| GetAndTouch | ✅ | GetAndTouch(ctx context.Context, expiry time.Duration, key string) (*Item, error) |
Get a value by key from memcached and touch the key's expire time |
| GetAndTouches | ✅ | GetAndTouches(ctx context.Context, expiry time.Duration, keys ...string) ([]*Item, error) |
Get a value by key from memcached and touch the key's expire time |
| ----- | ----- | OTHER COMMANDS | --- |
| Delete | ✅ | Delete(ctx context.Context, key string) error |
Delete a key-value pair from memcached |
| Incr | ✅ | Incr(ctx context.Context, key string, delta uint64) (uint64, error) |
Increment a key's value |
| Decr | ✅ | Decr(ctx context.Context, key string, delta uint64) (uint64, error) |
Decrement a key's value |
| Touch | ✅ | Touch(ctx context.Context, key string, expiry uint32) error |
Touch a key's expire time |
| MetaGet | ✅ | MetaGet(ctx context.Context, key []byte, options ...MetaGetOption) (*MetaItem, error) |
Get a key's meta information |
| MetaSet | ✅ | MetaSet(ctx context.Context, key, value []byte, options ...MetaSetOption) (*MetaItem, error) |
Set a key's meta information |
| MetaDelete | ✅ | MetaDelete(ctx context.Context, key []byte, options ...MetaDeleteOption) (*MetaItem, error) |
Delete a key's meta information |
| MetaArithmetic | ✅ | MetaArithmetic(ctx context.Context, key []byte, delta uint64, options ...MetaArithmeticOption) (*MetaItem, error) |
Arithmetic a key's meta information |
| MetaDebug | ✅ | MetaDebug(ctx context.Context, key []byte, options ...MetaDebugOption) (*MetaItemDebug, error) |
Debug a key's meta information |
| MetaNoop | ✅ | MetaNoop(ctx context.Context) error |
Noop a key's meta information |
| Version | ✅ | Version(ctx context.Context) (string, error) |
Get memcached server version |
| FlushAll | ✅ | FlushAll(ctx context.Context) error |
Flush all keys in memcached server |
- Go 1.26 or higher
- Python (for pre-commit hooks) or just
brew install pre-commiton MacOS - Docker (for running memcached in tests)
- Clone the repository:
git clone https://github.com/yeqown/memcached.git cd memcached - Install pre-commit hooks:
pip install pre-commit # or MacOS # brew install pre-commit pre-commit install
- Install golangci-lint:
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
go test -v -race -coverprofile=coverage.txt -covermode=atomic ./...This project follows the standard Go code style guidelines and uses golangci-lint for additional checks. The configuration can be found in .golangci.yml.
Key points:
- Follow Go standard formatting (enforced by gofmt )
- Ensure all code is properly tested
- Write clear commit messages
- Document public APIs