pool

package module
v0.0.0-...-86b9011 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 5, 2021 License: MIT Imports: 13 Imported by: 0

README

go-redis-pool

Build Status Go Report Card Coverage Status GitHub release GitHub release date LICENSE GoDoc

go-redis-pool was designed to implement the read/write split in Redis master-slave mode, and easy way to sharding the data.

Installation

go-redis-pool requires a Go version with Modules support and uses import versioning. So please make sure to initialize a Go module before installing go-redis-pool:

go mod init github.com/my/repo
go get github.com/bitleak/go-redis-pool

Quick Start

API documentation and examples are available via godoc

Setup The Master-Slave Pool
pool, err := pool.NewHA(&pool.HAConfig{
        Master: "127.0.0.1:6379",
        Slaves: []string{
            "127.0.0.1:6380",
            "127.0.0.1:6381",
        },
        Password: "", // set master password
        ReadonlyPassword: "", // use password if no set
})

pool.Set("foo", "bar", 0)

The read-only commands would go throught slaves and write commands would into the master instance. We use the Round-Robin as default when determing which slave to serve the readonly request, and currently supports:

  • RoundRobin (default)
  • Random
  • Weight

For example, we change the distribution type to Weight:

pool, err := pool.NewHA(&pool.HAConfig{
        Master: "127.0.0.1:6379",
        Slaves: []string{
            "127.0.0.1:6380",  // default weight is 100 if missing
            "127.0.0.1:6381:200", // weight is 200
            "127.0.0.1:6382:300", // weigght is 300
        },
        PollType: pool.PollByWeight,
})

The first slave would serve 1/6 reqeusts, and second slave would serve 2/6, last one would serve 3/6.

Auto Eject The Failure Host
pool, err := pool.NewHA(&pool.HAConfig{
        Master: "127.0.0.1:6379",
        Slaves: []string{
            "127.0.0.1:6380",  // default weight is 100 if missing
            "127.0.0.1:6381:200", // weight is 200
            "127.0.0.1:6382:300", // weigght is 300
        },

        AutoEjectHost: true,
        ServerFailureLimit: 3,
        ServerRetryTimeout: 5 * time.Second,
        MinServerNum: 2,
})

The pool would evict the host if reached ServerFailureLimit times of failure and retry the host after ServerRetryTimeout. The MinServerNum was used to avoid evicting too many and would overrun other alive servers.

Setup The Sharding Pool
pool, err := pool.NewShard(&pool.ShardConfig{
    Shards: []*HAConfig {

        // shard 1
        &pool.HAConfig{
            Master: "127.0.0.1:6379",
            Slaves: []string{
                "127.0.0.1:6380",
                "127.0.0.1:6381",
            },
            Password: "", // set master password
            ReadonlyPassword: "", // use password if no set
        },

        // shard 2
        &pool.HAConfig{
            Master: "127.0.0.1:6382",
            Slaves: []string{
                "127.0.0.1:6383",
            },
            Password: "", // set master password
            ReadonlyPassword: "", // use password if no set
        },
    },
})

pool.Set("foo", "bar", 0)

Shard pool use the CRC32 as default hash function when sharding the key, you can overwrite the HashFn in config if wants to use other sharding hash function. The distribution type supports ketama and modular, default is modular.

Test

$ make test

See Also

https://github.com/go-redis/redis

Documentation

Index

Constants

View Source
const (
	// PollByRandom selects the slave factory by random index
	PollByRandom = iota + 1
	// PollByWeight selects the slave factory by weight
	PollByWeight
	// PollByRoundRobin selects the slave with round-robin order
	PollByRoundRobin
)
View Source
const (
	// DistributeByModular selects the sharding factory by modular
	DistributeByModular = iota + 1
	// DistributeByKetama selects the sharding factory by ketama consistent algorithm
	DistributeByKetama
)

Variables

This section is empty.

Functions

This section is empty.

Types

type ConnFactory

type ConnFactory interface {
	// contains filtered or unexported methods
}

type HAConfig

type HAConfig struct {
	Master           string         // the address of the master, e.g. "127.0.0.1:6379"
	Slaves           []string       // list of slaves, e.g. ["127.0.0.1:6379", "127.0.0.1:6380"]
	Password         string         // the password of the master
	ReadonlyPassword string         // the passsword of slaves
	Options          *redis.Options // redis options
	PollType         int            // the slave polling type

	AutoEjectHost      bool          // eject the failure host or not
	ServerFailureLimit int32         // eject if reached `ServerFailureLimit` times of failure
	ServerRetryTimeout time.Duration // retry the ejected host after `ServerRetryTimeout`
	MinServerNum       int           // reserved the min server
	// contains filtered or unexported fields
}

type HAConnFactory

type HAConnFactory struct {
	// contains filtered or unexported fields
}

HAConnFactory impls the read/write splits between master and slaves

func NewHAConnFactory

func NewHAConnFactory(cfg *HAConfig) (*HAConnFactory, error)

type Pool

type Pool struct {
	// contains filtered or unexported fields
}

func NewHA

func NewHA(cfg *HAConfig) (*Pool, error)

func NewShard

func NewShard(cfg *ShardConfig) (*Pool, error)

func (*Pool) Append

func (p *Pool) Append(key, value string) *redis.IntCmd

func (*Pool) BLPop

func (p *Pool) BLPop(timeout time.Duration, keys ...string) *redis.StringSliceCmd

func (*Pool) BRPop

func (p *Pool) BRPop(timeout time.Duration, keys ...string) *redis.StringSliceCmd

func (*Pool) BRPopLPush

func (p *Pool) BRPopLPush(source, destination string, timeout time.Duration) *redis.StringCmd

func (*Pool) BitCount

func (p *Pool) BitCount(key string, bitCount *redis.BitCount) *redis.IntCmd

func (*Pool) BitField

func (p *Pool) BitField(key string, args ...interface{}) *redis.IntSliceCmd

func (*Pool) BitOp

func (p *Pool) BitOp(op int, destKey string, keys ...string) *redis.IntCmd

func (*Pool) BitOpAnd

func (p *Pool) BitOpAnd(destKey string, keys ...string) *redis.IntCmd

func (*Pool) BitOpNot

func (p *Pool) BitOpNot(destKey string, key string) *redis.IntCmd

func (*Pool) BitOpOr

func (p *Pool) BitOpOr(destKey string, keys ...string) *redis.IntCmd

func (*Pool) BitOpXor

func (p *Pool) BitOpXor(destKey string, keys ...string) *redis.IntCmd

func (*Pool) BitPos

func (p *Pool) BitPos(key string, bit int64, pos ...int64) *redis.IntCmd

func (*Pool) Close

func (p *Pool) Close()

func (*Pool) DebugObject

func (p *Pool) DebugObject(key string) *redis.StringCmd

func (*Pool) Decr

func (p *Pool) Decr(key string) *redis.IntCmd

func (*Pool) DecrBy

func (p *Pool) DecrBy(key string, decrement int64) *redis.IntCmd

func (*Pool) Del

func (p *Pool) Del(keys ...string) (int64, error)

func (*Pool) Dump

func (p *Pool) Dump(key string) *redis.StringCmd

func (*Pool) Echo

func (p *Pool) Echo(message interface{}) *redis.StringCmd

func (*Pool) Eval

func (p *Pool) Eval(script string, keys []string, args ...interface{}) *redis.Cmd

func (*Pool) EvalSha

func (p *Pool) EvalSha(sha1 string, keys []string, args ...interface{}) *redis.Cmd

func (*Pool) Exists

func (p *Pool) Exists(keys ...string) (int64, error)

func (*Pool) Expire

func (p *Pool) Expire(key string, expiration time.Duration) *redis.BoolCmd

func (*Pool) ExpireAt

func (p *Pool) ExpireAt(key string, tm time.Time) *redis.BoolCmd

func (*Pool) GeoAdd

func (p *Pool) GeoAdd(key string, geoLocation ...*redis.GeoLocation) *redis.IntCmd

func (*Pool) GeoDist

func (p *Pool) GeoDist(key string, member1, member2, unit string) *redis.FloatCmd

func (*Pool) GeoHash

func (p *Pool) GeoHash(key string, members ...string) *redis.StringSliceCmd

func (*Pool) GeoPos

func (p *Pool) GeoPos(key string, members ...string) *redis.GeoPosCmd

func (*Pool) GeoRadius

func (p *Pool) GeoRadius(key string, longitude, latitude float64, query *redis.GeoRadiusQuery) *redis.GeoLocationCmd

func (*Pool) GeoRadiusByMember

func (p *Pool) GeoRadiusByMember(key, member string, query *redis.GeoRadiusQuery) *redis.GeoLocationCmd

func (*Pool) GeoRadiusByMemberStore

func (p *Pool) GeoRadiusByMemberStore(key, member string, query *redis.GeoRadiusQuery) *redis.IntCmd

func (*Pool) GeoRadiusStore

func (p *Pool) GeoRadiusStore(key string, longitude, latitude float64, query *redis.GeoRadiusQuery) *redis.IntCmd

func (*Pool) Get

func (p *Pool) Get(key string) *redis.StringCmd

func (*Pool) GetBit

func (p *Pool) GetBit(key string, offset int64) *redis.IntCmd

func (*Pool) GetRange

func (p *Pool) GetRange(key string, start, end int64) *redis.StringCmd

func (*Pool) GetSet

func (p *Pool) GetSet(key string, value interface{}) *redis.StringCmd

func (*Pool) HDel

func (p *Pool) HDel(key string, fields ...string) *redis.IntCmd

func (*Pool) HExists

func (p *Pool) HExists(key, field string) *redis.BoolCmd

func (*Pool) HGet

func (p *Pool) HGet(key, field string) *redis.StringCmd

func (*Pool) HGetAll

func (p *Pool) HGetAll(key string) *redis.StringStringMapCmd

func (*Pool) HIncrBy

func (p *Pool) HIncrBy(key, field string, incr int64) *redis.IntCmd

func (*Pool) HIncrByFloat

func (p *Pool) HIncrByFloat(key, field string, incr float64) *redis.FloatCmd

func (*Pool) HKeys

func (p *Pool) HKeys(key string) *redis.StringSliceCmd

func (*Pool) HLen

func (p *Pool) HLen(key string) *redis.IntCmd

func (*Pool) HMGet

func (p *Pool) HMGet(key string, fields ...string) *redis.SliceCmd

func (*Pool) HMSet

func (p *Pool) HMSet(key string, values ...interface{}) *redis.BoolCmd

func (*Pool) HScan

func (p *Pool) HScan(key string, cursor uint64, match string, count int64) *redis.ScanCmd

func (*Pool) HSet

func (p *Pool) HSet(key, field string, value interface{}) *redis.IntCmd

func (*Pool) HSetNX

func (p *Pool) HSetNX(key, field string, value interface{}) *redis.BoolCmd

func (*Pool) HVals

func (p *Pool) HVals(key string) *redis.StringSliceCmd

func (*Pool) Incr

func (p *Pool) Incr(key string) *redis.IntCmd

func (*Pool) IncrBy

func (p *Pool) IncrBy(key string, increment int64) *redis.IntCmd

func (*Pool) IncrByFloat

func (p *Pool) IncrByFloat(key string, value float64) *redis.FloatCmd

func (*Pool) LIndex

func (p *Pool) LIndex(key string, index int64) *redis.StringCmd

func (*Pool) LInsert

func (p *Pool) LInsert(key, op string, pivot, value interface{}) *redis.IntCmd

func (*Pool) LInsertAfter

func (p *Pool) LInsertAfter(key string, pivot, value interface{}) *redis.IntCmd

func (*Pool) LInsertBefore

func (p *Pool) LInsertBefore(key string, pivot, value interface{}) *redis.IntCmd

func (*Pool) LLen

func (p *Pool) LLen(key string) *redis.IntCmd

func (*Pool) LPop

func (p *Pool) LPop(key string) *redis.StringCmd

func (*Pool) LPush

func (p *Pool) LPush(key string, values ...interface{}) *redis.IntCmd

func (*Pool) LPushX

func (p *Pool) LPushX(key string, values ...interface{}) *redis.IntCmd

func (*Pool) LRange

func (p *Pool) LRange(key string, start, stop int64) *redis.StringSliceCmd

func (*Pool) LRem

func (p *Pool) LRem(key string, count int64, value interface{}) *redis.IntCmd

func (*Pool) LSet

func (p *Pool) LSet(key string, index int64, value interface{}) *redis.StatusCmd

func (*Pool) LTrim

func (p *Pool) LTrim(key string, start, stop int64) *redis.StatusCmd

func (*Pool) MGet

func (p *Pool) MGet(keys ...string) ([]interface{}, error)

func (*Pool) MSet

func (p *Pool) MSet(values ...interface{}) *redis.StatusCmd

MSet is like Set but accepts multiple values:

  • MSet("key1", "value1", "key2", "value2")
  • MSet([]string{"key1", "value1", "key2", "value2"})
  • MSet(map[string]interface{}{"key1": "value1", "key2": "value2"})

func (*Pool) MSetNX

func (p *Pool) MSetNX(values ...interface{}) *redis.BoolCmd

MSetNX is like SetNX but accepts multiple values:

  • MSetNX("key1", "value1", "key2", "value2")
  • MSetNX([]string{"key1", "value1", "key2", "value2"})
  • MSetNX(map[string]interface{}{"key1": "value1", "key2": "value2"})

func (*Pool) MemoryUsage

func (p *Pool) MemoryUsage(key string, samples ...int) *redis.IntCmd

func (*Pool) ObjectEncoding

func (p *Pool) ObjectEncoding(key string) *redis.StringCmd

func (*Pool) ObjectIdleTime

func (p *Pool) ObjectIdleTime(key string) *redis.DurationCmd

func (*Pool) ObjectRefCount

func (p *Pool) ObjectRefCount(key string) *redis.IntCmd

func (*Pool) PFAdd

func (p *Pool) PFAdd(key string, els ...interface{}) *redis.IntCmd

func (*Pool) PFCount

func (p *Pool) PFCount(keys ...string) *redis.IntCmd

func (*Pool) PFMerge

func (p *Pool) PFMerge(dest string, keys ...string) *redis.StatusCmd

func (*Pool) Ping

func (p *Pool) Ping() *redis.StatusCmd

func (*Pool) Pipeline

func (p *Pool) Pipeline() (redis.Pipeliner, error)

func (*Pool) Pipelined

func (p *Pool) Pipelined(fn func(redis.Pipeliner) error) ([]redis.Cmder, error)

func (*Pool) PubSubChannels

func (p *Pool) PubSubChannels(pattern string) *redis.StringSliceCmd

func (*Pool) PubSubNumPat

func (p *Pool) PubSubNumPat() *redis.IntCmd

func (*Pool) PubSubNumSub

func (p *Pool) PubSubNumSub(channels ...string) *redis.StringIntMapCmd

func (*Pool) Publish

func (p *Pool) Publish(channel string, message interface{}) *(redis.IntCmd)

func (*Pool) RPop

func (p *Pool) RPop(key string) *redis.StringCmd

func (*Pool) RPopLPush

func (p *Pool) RPopLPush(source, destination string) *redis.StringCmd

func (*Pool) RPush

func (p *Pool) RPush(key string, values ...interface{}) *redis.IntCmd

func (*Pool) RPushX

func (p *Pool) RPushX(key string, values ...interface{}) *redis.IntCmd

func (*Pool) Rename

func (p *Pool) Rename(key, newkey string) *redis.StatusCmd

func (*Pool) RenameNX

func (p *Pool) RenameNX(key, newkey string) *redis.BoolCmd

func (*Pool) SAdd

func (p *Pool) SAdd(key string, members ...interface{}) *redis.IntCmd

func (*Pool) SCard

func (p *Pool) SCard(key string) *redis.IntCmd

func (*Pool) SDiff

func (p *Pool) SDiff(keys ...string) *redis.StringSliceCmd

func (*Pool) SDiffStore

func (p *Pool) SDiffStore(destination string, keys ...string) *redis.IntCmd

func (*Pool) SInter

func (p *Pool) SInter(keys ...string) *redis.StringSliceCmd

func (*Pool) SInterStore

func (p *Pool) SInterStore(destination string, keys ...string) *redis.IntCmd

func (*Pool) SIsMember

func (p *Pool) SIsMember(key string, member interface{}) *redis.BoolCmd

func (*Pool) SMembers

func (p *Pool) SMembers(key string) *redis.StringSliceCmd

func (*Pool) SMembersMap

func (p *Pool) SMembersMap(key string) *redis.StringStructMapCmd

func (*Pool) SMove

func (p *Pool) SMove(source, destination string, member interface{}) *redis.BoolCmd

func (*Pool) SPop

func (p *Pool) SPop(key string) *redis.StringCmd

func (*Pool) SPopN

func (p *Pool) SPopN(key string, count int64) *redis.StringSliceCmd

func (*Pool) SRandMember

func (p *Pool) SRandMember(key string) *redis.StringCmd

func (*Pool) SRandMemberN

func (p *Pool) SRandMemberN(key string, count int64) *redis.StringSliceCmd

func (*Pool) SRem

func (p *Pool) SRem(key string, members ...interface{}) *redis.IntCmd

func (*Pool) SScan

func (p *Pool) SScan(key string, cursor uint64, match string, count int64) *redis.ScanCmd

func (*Pool) SUnion

func (p *Pool) SUnion(keys ...string) *redis.StringSliceCmd

func (*Pool) SUnionStore

func (p *Pool) SUnionStore(destination string, keys ...string) *redis.IntCmd

func (*Pool) Scan

func (p *Pool) Scan(cursor uint64, match string, count int64) *redis.ScanCmd

func (*Pool) ScriptExists

func (p *Pool) ScriptExists(hashes ...string) *redis.BoolSliceCmd

func (*Pool) ScriptFlush

func (p *Pool) ScriptFlush() *redis.StatusCmd

func (*Pool) ScriptKill

func (p *Pool) ScriptKill() *redis.StatusCmd

func (*Pool) ScriptLoad

func (p *Pool) ScriptLoad(script string) *redis.StringCmd

func (*Pool) Set

func (p *Pool) Set(key string, value interface{}, expiration time.Duration) *redis.StatusCmd

func (*Pool) SetBit

func (p *Pool) SetBit(key string, offset int64, value int) *redis.IntCmd

func (*Pool) SetNX

func (p *Pool) SetNX(key string, value interface{}, expiration time.Duration) *redis.BoolCmd

func (*Pool) SetRange

func (p *Pool) SetRange(key string, offset int64, value string) *redis.IntCmd

func (*Pool) SetXX

func (p *Pool) SetXX(key string, value interface{}, expiration time.Duration) *redis.BoolCmd

func (*Pool) Sort

func (p *Pool) Sort(key string, sort *redis.Sort) *redis.StringSliceCmd

func (*Pool) SortInterfaces

func (p *Pool) SortInterfaces(key string, sort *redis.Sort) *redis.SliceCmd

func (*Pool) SortStore

func (p *Pool) SortStore(key, store string, sort *redis.Sort) *redis.IntCmd

func (*Pool) StrLen

func (p *Pool) StrLen(key string) *redis.IntCmd

func (*Pool) TTL

func (p *Pool) TTL(key string) *redis.DurationCmd

func (*Pool) Touch

func (p *Pool) Touch(keys ...string) (int64, error)

func (*Pool) TxPipeline

func (p *Pool) TxPipeline() (redis.Pipeliner, error)

func (*Pool) TxPipelined

func (p *Pool) TxPipelined(fn func(redis.Pipeliner) error) ([]redis.Cmder, error)

func (*Pool) Type

func (p *Pool) Type(key string) *redis.StatusCmd
func (p *Pool) Unlink(keys ...string) (int64, error)

func (*Pool) WithMaster

func (p *Pool) WithMaster(key ...string) (*redis.Client, error)

func (*Pool) ZAdd

func (p *Pool) ZAdd(key string, members ...*redis.Z) *redis.IntCmd

func (*Pool) ZAddCh

func (p *Pool) ZAddCh(key string, members ...*redis.Z) *redis.IntCmd

func (*Pool) ZAddNX

func (p *Pool) ZAddNX(key string, members ...*redis.Z) *redis.IntCmd

func (*Pool) ZAddNXCh

func (p *Pool) ZAddNXCh(key string, members ...*redis.Z) *redis.IntCmd

func (*Pool) ZAddXX

func (p *Pool) ZAddXX(key string, members ...*redis.Z) *redis.IntCmd

func (*Pool) ZAddXXCh

func (p *Pool) ZAddXXCh(key string, members ...*redis.Z) *redis.IntCmd

func (*Pool) ZCard

func (p *Pool) ZCard(key string) *redis.IntCmd

func (*Pool) ZCount

func (p *Pool) ZCount(key, min, max string) *redis.IntCmd

func (*Pool) ZIncr

func (p *Pool) ZIncr(key string, member *redis.Z) *redis.FloatCmd

func (*Pool) ZIncrBy

func (p *Pool) ZIncrBy(key string, increment float64, member string) *redis.FloatCmd

func (*Pool) ZIncrNX

func (p *Pool) ZIncrNX(key string, member *redis.Z) *redis.FloatCmd

func (*Pool) ZIncrXX

func (p *Pool) ZIncrXX(key string, member *redis.Z) *redis.FloatCmd

func (*Pool) ZInterStore

func (p *Pool) ZInterStore(destination string, store *redis.ZStore) *redis.IntCmd

func (*Pool) ZLexCount

func (p *Pool) ZLexCount(key, min, max string) *redis.IntCmd

func (*Pool) ZPopMax

func (p *Pool) ZPopMax(key string, count ...int64) *redis.ZSliceCmd

func (*Pool) ZPopMin

func (p *Pool) ZPopMin(key string, count ...int64) *redis.ZSliceCmd

func (*Pool) ZRange

func (p *Pool) ZRange(key string, start, stop int64) *redis.StringSliceCmd

func (*Pool) ZRangeByLex

func (p *Pool) ZRangeByLex(key string, opt *redis.ZRangeBy) *redis.StringSliceCmd

func (*Pool) ZRangeByScore

func (p *Pool) ZRangeByScore(key string, opt *redis.ZRangeBy) *redis.StringSliceCmd

func (*Pool) ZRangeByScoreWithScores

func (p *Pool) ZRangeByScoreWithScores(key string, opt *redis.ZRangeBy) *redis.ZSliceCmd

func (*Pool) ZRangeWithScores

func (p *Pool) ZRangeWithScores(key string, start, stop int64) *redis.ZSliceCmd

func (*Pool) ZRank

func (p *Pool) ZRank(key, member string) *redis.IntCmd

func (*Pool) ZRem

func (p *Pool) ZRem(key string, members ...interface{}) *redis.IntCmd

func (*Pool) ZRemRangeByLex

func (p *Pool) ZRemRangeByLex(key, min, max string) *redis.IntCmd

func (*Pool) ZRemRangeByRank

func (p *Pool) ZRemRangeByRank(key string, start, stop int64) *redis.IntCmd

func (*Pool) ZRemRangeByScore

func (p *Pool) ZRemRangeByScore(key, min, max string) *redis.IntCmd

func (*Pool) ZRevRange

func (p *Pool) ZRevRange(key string, start, stop int64) *redis.StringSliceCmd

func (*Pool) ZRevRangeByLex

func (p *Pool) ZRevRangeByLex(key string, opt *redis.ZRangeBy) *redis.StringSliceCmd

func (*Pool) ZRevRangeByScore

func (p *Pool) ZRevRangeByScore(key string, opt *redis.ZRangeBy) *redis.StringSliceCmd

func (*Pool) ZRevRangeByScoreWithScores

func (p *Pool) ZRevRangeByScoreWithScores(key string, opt *redis.ZRangeBy) *redis.ZSliceCmd

func (*Pool) ZRevRangeWithScores

func (p *Pool) ZRevRangeWithScores(key string, start, stop int64) *redis.ZSliceCmd

func (*Pool) ZRevRank

func (p *Pool) ZRevRank(key, member string) *redis.IntCmd

func (*Pool) ZScan

func (p *Pool) ZScan(key string, cursor uint64, match string, count int64) *redis.ScanCmd

func (*Pool) ZScore

func (p *Pool) ZScore(key, member string) *redis.FloatCmd

func (*Pool) ZUnionStore

func (p *Pool) ZUnionStore(dest string, store *redis.ZStore) *redis.IntCmd

type ShardConfig

type ShardConfig struct {
	Shards         []*HAConfig
	DistributeType int // distribution type of the shards, supports `DistributeByModular` or `DistributeByKetama`
	HashFn         func(key []byte) uint32
}

type ShardConnFactory

type ShardConnFactory struct {
	// contains filtered or unexported fields
}

func NewShardConnFactory

func NewShardConnFactory(cfg *ShardConfig) (*ShardConnFactory, error)

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL