Originality is not easy. , Please share 、 Ask for one key and three links
Caching is generally used to speed up the efficiency of data access , Using cache can effectively improve the efficiency of data acquisition in scenarios where data acquisition is time-consuming .
such as , First from memcached Get data in , If not, query mysql The data in gets the result and writes it to memcached Middle and back , The next request can be made from memcached Get the data in and return it directly .
Cache databases that are widely used in the industry include Redis and Memcached.
Use today go Realization Memcached Driver program , Deepen understanding Memcached The protocol and principle of how to conduct data interaction with the business code we usually write .
What is? memcached
Memcached yes LiveJournal its Danga Interactive The company's Brad Fitzpatric Led by the development of a free and open source 、 High performance key-value Cache database software .
Mecached agreement
Mecached Services and applications are different processes on different machines , The data interactive communication between the two parties involves tcp And communication protocols , stay memcache There are two types of protocols in. One is text line , The other is unstructured data .
We choose text line protocol to realize , majority Mecached The client is also developed using text line protocol because it is relatively simple , A specific format text string to agree on data interaction , The following is an example of sending commands from the client :
<command name> <key> <flags> <exptime> <bytes>\r\n
<data block>\r\n
<command name>
It is the order of the agreement , Roughly divided into three categories :
- Storage command :set、 add、replace、append、prepend、cas.
- Get orders :get、gets.
- Other commands :version、stats
<key>
Require keywords to store data ; because memached Limitations of the underlying implementation ,key The length of is limited to 250 Within a character , also key Cannot contain control characters or spaces .
<flags>
It's a 16 Bit unsigned integer .
<exptime>
Is the storage timeout . If the value is 0 Indicates that the data item will never time out ;
Expiration time limits , The expiration time is either Unix Time ( from 1970-1-1 The number of seconds to start counting ), Or the number of seconds calculated from the current time .
The value cannot exceed 30 God , Otherwise, the server treats this parameter as a real Unix Time, not an offset of the current time .
<bytes>
Is the number of bytes of subsequent data , Excluding terminators \r\n.<bytes>
It could be 0, It will be followed by an empty data block .
<data block>
Store data streams .
The client sends the content of the text line to the server in the form of string, and the server will return the corresponding execution result data , There are also cases of returning errors ,memcache It also defines three different error types for the wrong data format, which makes the return of errors simple :
- ERROR\r\n
It indicates that the client sent a nonexistent command
- CLIENT_ERROR\r\n
Indicates that there is some type of client error in the input line , For example, the input information does not follow memcached The agreement
- SERVER_ERROR\r\n
It indicates that there is some kind of error on the server, which makes the fatal command unable to execute .
<error>
Is a readable error string .
When the server error occurs , The server will no longer provide services , The server will close the link after sending the error message line . Only in this scenario , The server will close the link with the client .
The following is a specific list memcached A list of commonly used command formats that contain the client sends and responds :
It should be noted that command It's case sensitive , Client side usage tcp Connect the server and send the client text line command , Wait for the server to return data after sending successfully , Get the required return value according to the format parsing, which is a simple protocol command execution process .
Golang Implement client driver
Yes, yes memache Understanding the protocol is now relatively simple to realize communication , First, we need to define Client Structure , Save some basic configuration information and link information of the client :
type Client struct {
Timeout time.Duration
MaxIdleConns int
lock sync.Mutex
addr net.Addr
conns []*conn
}
- Timeout tcp Link read / write timeout
- conns yes memcache The array stored in the link pool
- MaxIdleConns yes Idle The number of links
- lock Is the operation conns Time lock
- addr Is linked memcache The address of
memcached A separate one conn Connection structure definition
type conn struct {
nc net.Conn
rw *bufio.ReadWriter
addr net.Addr
c *Client
}
- nc Is established tcp Network link
- rw To facilitate data sending and reading settings bufio Of ReadWriter
- addr Storage memcached Address
- c Store client references
The following is how to get links and how to put links back into the link pool after use
// obtain memcached Link to
func (c *Client) getFreeConn() (cn *conn, ok bool) {
c.lock.Lock()
defer c.lock.Unlock()
if c.conns == nil {
return nil, false
}
freelist := c.conns
if len(freelist) == 0 {
return nil, false
}
cn = freelist[len(freelist)-1]
c.conns = freelist[:len(freelist)-1]
return cn, true
}
// Put the used link back to conns in
func (c *Client) putFreeConn(cn *conn) {
c.lock.Lock()
defer c.lock.Unlock()
if c.conns == nil {
c.conns = make([]*conn, 0)
}
freelist := c.conns
if len(freelist) >= c.maxIdleConns() {
cn.nc.Close()
return
}
c.conns = append(freelist, cn)
}
Next, let's say GET Command as an example , Let's see in detail how to implement network transmission and protocol parsing
func (c *Client) Get(key string) (item *Item, err error) {
//check key len verification key Whether it is longer than 250 character
if !legalKey(key) {
err = ErrMalformedKey
return
}
keys := []string{key}
cn, err := c.getConn() // obtain memcached link
defer cn.condRelease(&err) // After the method is executed, it will link release, Return to the link pool
if err != nil {
return
}
rw := cn.rw
// take gets The command is written in text line protocol to rw in
if _, err = fmt.Fprintf(rw, "gets %s\r\n", strings.Join(keys, " ")); err != nil {
return
}
if err = rw.Flush(); err != nil {
return
}
// obtain GET Wait and get the returned response data after the command is sent
if err = parseGetResponse(rw.Reader, func(it *Item) { item = it }); err != nil {
return
}
if item == nil {
err = ErrCacheMiss
}
return
}
func parseGetResponse(r *bufio.Reader, cb func(*Item)) error {
for {
line, err := r.ReadSlice('\n')
if err != nil {
return err
}
if bytes.Equal(line, resultEnd) { // If the acquisition is END\r\n Then the data is returned , Then return to
return nil
}
it := new(Item)
size, err := scanGetResponseLine(line, it)// First, get the first row of data and <data> Size of section
if err != nil {
return err
}
// according to bytes get data
it.Value = make([]byte, size+2)
_, err = io.ReadFull(r, it.Value)
if err != nil {
it.Value = nil
return err
}
if !bytes.HasSuffix(it.Value, crlf) {
it.Value = nil
return fmt.Errorf("memcache: corrupt get result read")
}
it.Value = it.Value[:size]
cb(it)
}
}
// Get the return value according to the return data format and set it to Item In structure .
func scanGetResponseLine(line []byte, it *Item) (size int, err error) {
// The format of the data returned VALUE <key> <falgs> <bytes> <casid>
pattern := "VALUE %s %d %d %d\r\n"
dest := []interface{}{&it.Key, &it.Flags, &size, &it.casid}
if bytes.Count(line, space) == 3 {
pattern = "VALUE %s %d %d\r\n"
dest = dest[:3]
}
n, err := fmt.Sscanf(string(line), pattern, dest...)
if err != nil || n != len(dest) {
return -1, fmt.Errorf("memcache: unexpected line in get response: %q", line)
}
return size, nil
}
// Judge key Whether it meets the requirements
func legalKey(key string) bool {
if len(key) > 250 {
return false
}
for i := 0; i < len(key); i++ {
if key[i] <= ' ' || key[i] == 0x7f {
return false
}
}
return true
}
Other commands are not described in detail , The complete code is as follows :
1 package memcache
2
3 import (
4 "bufio"
5 "bytes"
6 "errors"
7 "fmt"
8 "io"
9 "net"
10 "strconv"
11 "strings"
12 "sync"
13 "time"
14 )
15
16 //memcached -m 1024 -u root -l 127.0.0.1 -p 12001 -c 55535
17 //# memcached -d -m 10 -u root -l 127.0.0.1 -p 12001 -c 256 -P /tmp/memcached.pid
18 //-d The option is to start a daemons
19 //-m Is assigned to Memcache The amount of memory used , The unit is MB, I am here 10MB
20 //-u Is to run Memcache Users of
21 //-l It's a listening server IP Address , If there are multiple addresses , I've specified the name of the server here IP Address 127.0.0.1
22 //-p It's settings Memcache Listening port , I set up here 12001, It is best to 1024 Ports above
23 //-c Option is the maximum number of concurrent connections to run , The default is 1024, I set up here 256, Set it according to the load of your server
24 //-P It's setting save Memcache Of pid file , I'm keeping it here /tmp/memcached.pid
25 // Stop the process :# kill `cat /tmp/memcached.pid`
26
27 const (
28 DefaultTimeout = 100 * time.Millisecond
29 DefaultMaxIdleConns = 40
30 )
31
32 var (
33 resultClientErrorPrefix = []byte("CLIENT_ERROR")
34 resultErrPrefix = []byte("ERROR")
35 resultServerErrPrefix = []byte("SERVER_ERROR")
36
37 crlf = []byte("\r\n")
38 space = []byte(" ")
39 resultOK = []byte("OK\r\n")
40 resultStored = []byte("STORED\r\n")
41 resultNotStored = []byte("NOT_STORED\r\n")
42 resultExists = []byte("EXISTS\r\n")
43 resultNotFound = []byte("NOT_FOUND\r\n")
44 resultDeleted = []byte("DELETED\r\n")
45 resultEnd = []byte("END\r\n")
46 resultTouched = []byte("TOUCHED\r\n")
47 versionPrefix = []byte("VERSION")
48
49 ErrMalformedKey = errors.New("malformed: key is too long or contains invalid characters")
50 ErrCacheMiss = errors.New("memcache: cache miss")
51 ErrCASConflict = errors.New("memcache: compare-and-swap conflict")
52 ErrNotStored = errors.New("memcache: item not stored")
53 )
54
55 type Client struct {
56 Timeout time.Duration
57 MaxIdleConns int
58 lock sync.Mutex
59 addr net.Addr
60 conns []*conn
61 }
62
63 func NewClient(timeout time.Duration, maxIdleConns int, addr net.Addr) *Client {
64 return &Client{
65 Timeout: timeout,
66 MaxIdleConns: maxIdleConns,
67 lock: sync.Mutex{},
68 addr: addr,
69 conns: nil,
70 }
71 }
72
73 type Item struct {
74 // Key is the Item's key (250 bytes maximum).
75 Key string
76 // Value is the Item's value.
77 Value []byte
78 // Flags are server-opaque flags whose semantics are entirely
79 // up to the app.
80 Flags uint32
81 // Expiration is the cache expiration time, in seconds: either a relative
82 // time from now (up to 1 month), or an absolute Unix epoch time.
83 // Zero means the Item has no expiration time.
84 Expiration int32
85 // Compare and swap ID.
86 casid uint64
87 }
88
89 func (c *Client) maxIdleConns() int {
90 if c.MaxIdleConns > 0 {
91 return c.MaxIdleConns
92 }
93 return DefaultMaxIdleConns
94 }
95
96 func (c *Client) netTimeout() time.Duration {
97 if c.Timeout != 0 {
98 return c.Timeout
99 }
100 return DefaultTimeout
101 }
102
103 type conn struct {
104 nc net.Conn
105 rw *bufio.ReadWriter
106 addr net.Addr
107 c *Client
108 }
109
110 // Set timeout
111 func (cn *conn) extendDeadline() {
112 cn.nc.SetDeadline(time.Now().Add(cn.c.netTimeout()))
113 }
114
115 // Release If it's normal err Then put it back conns in , If it's not this direct close fall conn
116 func (cn *conn) condRelease(err *error) {
117 if *err == nil || resumableError(*err) {
118 cn.release()
119 } else {
120 fmt.Println("xxx", fmt.Sprintf("%s", (*err).Error()))
121 cn.nc.Close()
122 }
123 }
124
125 // release returns this connection back to the client's free pool
126 func (cn *conn) release() {
127 cn.c.putFreeConn(cn)
128 }
129
130 func (c *Client) putFreeConn(cn *conn) {
131 c.lock.Lock()
132 defer c.lock.Unlock()
133 if c.conns == nil {
134 c.conns = make([]*conn, 0)
135 }
136 freelist := c.conns
137 if len(freelist) >= c.maxIdleConns() {
138 cn.nc.Close()
139 return
140 }
141 c.conns = append(freelist, cn)
142 }
143
144 func (c *Client) getFreeConn() (cn *conn, ok bool) {
145 c.lock.Lock()
146 defer c.lock.Unlock()
147 if c.conns == nil {
148 return nil, false
149 }
150 freelist := c.conns
151 if len(freelist) == 0 {
152 return nil, false
153 }
154 cn = freelist[len(freelist)-1]
155 c.conns = freelist[:len(freelist)-1]
156 return cn, true
157 }
158
159 type ConnectTimeoutError struct {
160 Addr net.Addr
161 }
162
163 func (cte *ConnectTimeoutError) Error() string {
164 return "memcache: connect timeout to " + cte.Addr.String()
165 }
166
167 // obtain memcached Connect
168 func (c *Client) getConn() (*conn, error) {
169 cn, ok := c.getFreeConn()
170 if ok {
171 cn.extendDeadline()
172 return cn, nil
173 }
174 nc, err := c.dial(c.addr)
175 if err != nil {
176 return nil, err
177 }
178 cn = &conn{
179 nc: nc,
180 addr: c.addr,
181 rw: bufio.NewReadWriter(bufio.NewReader(nc), bufio.NewWriter(nc)),
182 c: c,
183 }
184 cn.extendDeadline()
185 return cn, nil
186 }
187
188 func (c *Client) dial(addr net.Addr) (net.Conn, error) {
189 nc, err := net.DialTimeout(addr.Network(), addr.String(), c.netTimeout())
190 if err == nil {
191 return nc, nil
192 }
193 if ne, ok := err.(net.Error); ok && ne.Timeout() {
194 return nil, &ConnectTimeoutError{Addr: addr}
195 }
196 return nil, err
197 }
198
199 func (c *Client) Get(key string) (item *Item, err error) {
200 //check key len
201 if !legalKey(key) {
202 err = ErrMalformedKey
203 return
204 }
205 keys := []string{key}
206 cn, err := c.getConn()
207 defer cn.condRelease(&err)
208 if err != nil {
209 return
210 }
211 rw := cn.rw
212 if _, err = fmt.Fprintf(rw, "gets %s\r\n", strings.Join(keys, " ")); err != nil {
213 return
214 }
215 if err = rw.Flush(); err != nil {
216 return
217 }
218 if err = parseGetResponse(rw.Reader, func(it *Item) { item = it }); err != nil {
219 return
220 }
221 if item == nil {
222 err = ErrCacheMiss
223 }
224 return
225 }
226
227 func (c *Client) GetMulti(keys []string) (map[string]*Item, error) {
228 var lk sync.Mutex
229 m := make(map[string]*Item)
230 addItemToMap := func(it *Item) {
231 lk.Lock()
232 defer lk.Unlock()
233 m[it.Key] = it
234 }
235 for _, key := range keys {
236 if !legalKey(key) {
237 return nil, ErrMalformedKey
238 }
239 }
240 cn, err := c.getConn()
241 defer cn.condRelease(&err)
242 if err != nil {
243 return nil, err
244 }
245 if _, err = fmt.Fprintf(cn.rw, "gets %s\r\n", strings.Join(keys, " ")); err != nil {
246 return nil, err
247 }
248 if err = cn.rw.Flush(); err != nil {
249 return nil, err
250 }
251 if err = parseGetResponse(cn.rw.Reader, addItemToMap); err != nil {
252 return nil, err
253 }
254 return m, err
255
256 }
257
258 func (c *Client) Touch(key string, seconds int32) (err error) {
259
260 cn, err := c.getConn()
261 if err != nil {
262 return
263 }
264 defer cn.condRelease(&err)
265
266 if _, err = fmt.Fprintf(cn.rw, "touch %s %d\r\n", key, seconds); err != nil {
267 return
268 }
269 if err = cn.rw.Flush(); err != nil {
270 return
271 }
272 line, err := cn.rw.ReadSlice('\n')
273 if err != nil {
274 return
275 }
276 switch {
277 case bytes.Equal(line, resultTouched):
278 break
279 case bytes.Equal(line, resultNotFound):
280 return ErrCacheMiss
281 default:
282 return fmt.Errorf("memcache: unexpected response line from touch: %q", string(line))
283 }
284 return nil
285 }
286
287 func (c *Client) Add(item *Item) error {
288 return c.onItem(item, func(client *Client, rw *bufio.ReadWriter, item *Item) error {
289 return client.populateOne(rw, "add", item)
290 })
291 }
292
293 func (c *Client) Set(item *Item) error {
294 return c.onItem(item, func(client *Client, rw *bufio.ReadWriter, item *Item) error {
295 return client.populateOne(rw, "set", item)
296 })
297 }
298
299 func (c *Client) CompareAndSwap(item *Item) error {
300 return c.onItem(item, func(client *Client, rw *bufio.ReadWriter, item *Item) error {
301 return client.populateOne(rw, "cas", item)
302 })
303 }
304
305 func (c *Client) Replace(item *Item) error {
306 return c.onItem(item, func(client *Client, rw *bufio.ReadWriter, item *Item) error {
307 return client.populateOne(rw, "replace", item)
308 })
309 }
310
311 func (c *Client) Delete(key string) error {
312 if !legalKey(key) {
313 return ErrMalformedKey
314 }
315 cn, err := c.getConn()
316 if err != nil {
317 return err
318 }
319 defer cn.condRelease(&err)
320 return writeExpectf(cn.rw, resultDeleted, "delete %s\r\n", key)
321 }
322
323 func (c *Client) FlushAll() error {
324 cn, err := c.getConn()
325 if err != nil {
326 return err
327 }
328 defer cn.condRelease(&err)
329 return writeExpectf(cn.rw, resultDeleted, "flush_all\r\n")
330 }
331
332 func (c *Client) Version() error {
333 cn, err := c.getConn()
334 defer cn.condRelease(&err)
335 if err != nil {
336 return err
337 }
338 return func(rw *bufio.ReadWriter) error {
339 if _, e := fmt.Fprintf(rw, "version\r\n"); e != nil {
340 return err
341 }
342 if e := rw.Flush(); e != nil {
343 return e
344 }
345 line, e := rw.ReadSlice('\n')
346 if e != nil {
347 return e
348 }
349 switch {
350 case bytes.HasPrefix(line, versionPrefix):
351 break
352 default:
353 return fmt.Errorf("memcache: unexpected response line from ping: %q", string(line))
354 }
355 return nil
356 }(cn.rw)
357
358 }
359
360 func (c *Client) Increment(key string, delta uint64) (newValue uint64, err error) {
361 return c.incrDecr("incr", key, delta)
362
363 }
364
365 func (c *Client) Decrement(key string, delta uint64) (newValue uint64, err error) {
366 return c.incrDecr("decr", key, delta)
367 }
368
369 func (c *Client) onItem(item *Item, fn func(*Client, *bufio.ReadWriter, *Item) error) error {
370 cn, err := c.getConn()
371 defer cn.condRelease(&err)
372 if err != nil {
373 return err
374 }
375 if err = fn(c, cn.rw, item); err != nil {
376 return err
377 }
378 return nil
379 }
380
381 func parseGetResponse(r *bufio.Reader, cb func(*Item)) error {
382 for {
383 line, err := r.ReadSlice('\n')
384 if err != nil {
385 return err
386 }
387 if bytes.Equal(line, resultEnd) {
388 return nil
389 }
390 it := new(Item)
391 size, err := scanGetResponseLine(line, it)
392 if err != nil {
393 return err
394 }
395 it.Value = make([]byte, size+2)
396 _, err = io.ReadFull(r, it.Value)
397 if err != nil {
398 it.Value = nil
399 return err
400 }
401 if !bytes.HasSuffix(it.Value, crlf) {
402 it.Value = nil
403 return fmt.Errorf("memcache: corrupt get result read")
404 }
405 it.Value = it.Value[:size]
406 cb(it)
407 }
408 }
409
410 func scanGetResponseLine(line []byte, it *Item) (size int, err error) {
411 pattern := "VALUE %s %d %d %d\r\n"
412 dest := []interface{}{&it.Key, &it.Flags, &size, &it.casid}
413 if bytes.Count(line, space) == 3 {
414 pattern = "VALUE %s %d %d\r\n"
415 dest = dest[:3]
416 }
417 n, err := fmt.Sscanf(string(line), pattern, dest...)
418 if err != nil || n != len(dest) {
419 return -1, fmt.Errorf("memcache: unexpected line in get response: %q", line)
420 }
421 return size, nil
422 }
423
424 func legalKey(key string) bool {
425 if len(key) > 250 {
426 return false
427 }
428 for i := 0; i < len(key); i++ {
429 if key[i] <= ' ' || key[i] == 0x7f {
430 return false
431 }
432 }
433 return true
434 }
435
436 func resumableError(err error) bool {
437 switch err {
438 case ErrCacheMiss, ErrCASConflict, ErrNotStored, ErrMalformedKey:
439 return true
440 }
441 return false
442 }
443
444 func (c *Client) populateOne(rw *bufio.ReadWriter, verb string, item *Item) error {
445 if !legalKey(item.Key) {
446 return ErrMalformedKey
447 }
448 var err error
449 if verb == "cas" {
450 _, err = fmt.Fprintf(rw, "%s %s %d %d %d %d\r\n",
451 verb, item.Key, item.Flags, item.Expiration, len(item.Value), item.casid)
452 } else {
453 _, err = fmt.Fprintf(rw, "%s %s %d %d %d\r\n",
454 verb, item.Key, item.Flags, item.Expiration, len(item.Value))
455 }
456 if err != nil {
457 return err
458 }
459 if _, err = rw.Write(item.Value); err != nil {
460 return err
461 }
462 if _, err = rw.Write(crlf); err != nil {
463 return err
464 }
465 if err = rw.Flush(); err != nil {
466 return err
467 }
468 line, err := rw.ReadSlice('\n')
469 if err != nil {
470 return err
471 }
472 switch {
473 case bytes.Equal(line, resultStored):
474 return nil
475 case bytes.Equal(line, resultNotStored):
476 return ErrNotStored
477 case bytes.Equal(line, resultExists):
478 return ErrCASConflict
479 case bytes.Equal(line, resultNotFound):
480 return ErrCacheMiss
481 }
482 return fmt.Errorf("memcache: unexpected response line from %q: %q", verb, string(line))
483 }
484
485 func writeExpectf(rw *bufio.ReadWriter, expect []byte, format string, args ...interface{}) error {
486 line, err := writeReadLine(rw, format, args...)
487 if err != nil {
488 return err
489 }
490 switch {
491 case bytes.Equal(line, resultOK):
492 return nil
493 case bytes.Equal(line, expect):
494 return nil
495 case bytes.Equal(line, resultNotStored):
496 return ErrNotStored
497 case bytes.Equal(line, resultExists):
498 return ErrCASConflict
499 case bytes.Equal(line, resultNotFound):
500 return ErrCacheMiss
501 }
502 return fmt.Errorf("memcache: unexpected response line: %q", string(line))
503 }
504
505 func writeReadLine(rw *bufio.ReadWriter, format string, args ...interface{}) ([]byte, error) {
506 _, err := fmt.Fprintf(rw, format, args...)
507 if err != nil {
508 return nil, err
509 }
510 if e := rw.Flush(); e != nil {
511 return nil, e
512 }
513 line, err := rw.ReadSlice('\n')
514 return line, err
515 }
516
517 func (c *Client) incrDecr(verb, key string, delta uint64) (uint64, error) {
518 var val uint64
519 cn, err := c.getConn()
520 defer cn.condRelease(&err)
521 if err != nil {
522 return 0, err
523 }
524 func(rw *bufio.ReadWriter) error {
525 line, e := writeReadLine(rw, "%s %s %d\r\n", verb, key, delta)
526 if e != nil {
527 return e
528 }
529 switch {
530 case bytes.Equal(line, resultNotFound):
531 return ErrCacheMiss
532 case bytes.HasPrefix(line, resultClientErrorPrefix):
533 errMsg := line[len(resultClientErrorPrefix) : len(line)-2]
534 return errors.New("memcache: client error: " + string(errMsg))
535 }
536 val, e = strconv.ParseUint(string(line[:len(line)-2]), 10, 64)
537 if e != nil {
538 return e
539 }
540 return nil
541 }(cn.rw)
542 return val, err
543 }
Test code , Start a http Set the server to memcached in , adopt /hello Interface from memcached Get the corresponding value
package main
import (
"fmt"
"memcache_go/memcache"
"net"
"net/http"
"time"
)
var client *memcache.Client
func IndexHandler(w http.ResponseWriter, r *http.Request) {
ret, err := client.Get("tcp_key")
if err != nil {
fmt.Fprintln(w, "err ")
}
str := ""
if ret != nil {
str = string(ret.Value)
fmt.Fprintln(w, "hello world", str)
} else {
fmt.Fprintln(w, "nil")
}
}
func touchHandler(w http.ResponseWriter, r *http.Request) {
err := client.Touch("tcp_key", 1000)
if err != nil {
fmt.Fprintln(w, "err ")
return
}
fmt.Fprintln(w, "succ")
}
func main() {
addr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:12001")
if err != nil {
fmt.Println(fmt.Sprintf("get err %v", err))
return
}
client = memcache.NewClient(30*time.Second, 30, addr)
err = client.Add(&memcache.Item{
Key: "tcp_key",
Value: []byte(fmt.Sprintf("tcp_key_value_%d", time.Now().UnixNano())),
Flags: 0,
Expiration: 0,
})
if err != nil {
fmt.Println(" Execution failure ")
//return
}
http.HandleFunc("/get", IndexHandler)
http.HandleFunc("/touch", touchHandler)
http.ListenAndServe("127.0.0.1:8000", nil)
//fmt.Println("memcache_test...")
for {
time.Sleep(1000 * 30)
}
}
start-up memcached Service to test
memcached -m 1024 -u root -l 127.0.0.1 -p 12001 -c 55535
//-d The option is to start a daemons
//-m Is assigned to Memcache The amount of memory used , The unit is MB, I am here 10MB
//-u Is to run Memcache Users of
//-l It's a listening server IP Address , If there are multiple addresses , I've specified the name of the server here IP Address 127.0.0.1
//-p It's settings Memcache Listening port , I set up here 12001, It is best to 1024 Ports above
//-c Option is the maximum number of concurrent connections to run , The default is 1024, I set up here 256, Set it according to the load of your server
//-P It's setting save Memcache Of pid file , I'm keeping it here /tmp/memcached.pid
// Stop the process :# kill `cat /tmp/memcached.pid`
So far, we have used hundreds of lines of code to realize a simple memcached Link driven subset , For applications and memcached Have a general understanding of how to communicate .
Okay , Today's sharing is here , I hope it will be useful to you . 「 Originality is not easy. , Share more 」
If you want more communication, you can add groups :
You can also join the knowledge planet to ask questions for free :
500 Line code to understand Mecached More related articles on the principle of caching client driver
- [500lines]500 Line code write web server
Project address :https://github.com/aosabook/500lines/tree/master/web-server. The author is from Mozilla Of Greg Wilson. The project uses py2 It's written in . ...
- Step by step handwriting GIS Open source project -(1)500 Line code implementation basis GIS Display function
1. The opening It has been two years since I graduated from university , When I went to school, I wanted to study open source GIS Source code , Suffer from limited knowledge and understanding , And there's nothing in the market that explains open source from the simple to the deep gis Books on principles , Most of them are introduction of open source projects and simple applications of projects . For beginners ...
- 500 Line code , Teach you how to use python Write a wechat aircraft war
These days, I'm going to revisit the plane battle of wechat games , Playing is thinking about life , How can this airplane fight be done so well , It's easy to operate , Simple to fit . Help squatters .YP family . A girl in the rice circle can have something to cheer them up when they are bored ! Let their left hand / Right ...
- Very good open source C project tinyhttpd(500 Line code )
Compile command gcc -W -Wall -lpthread -o httpd httpd.c Source code #include <stdio.h> #include <sys/socket.h&g ...
- BaseHttpListActivity, A few lines of code Android Http List request 、 Load and cache
Android In development , It is a very common requirement to request a list from the server and display it , But it's troublesome to implement , The code is complicated . As the application updates, iterations , This demand is increasing , I've come to see what the code that implements this requirement has in common . So I will Activit ...
- 50 Line of code for caching ,JAVA Memory model principle
How to meet such an expert ?? Here's a simple cache implementation , It's pretty good ! See for yourself , Only 50 Line code . Excerpt from :http://www.oschina.net/code/snippet_55577_3887 import ...
- SpringBoot, use 200 Line of code to complete a level one or two distributed cache
Cache system is used instead of direct access to the database , Used to improve system performance , Reduce the complexity of database . The early cache was in the same virtual machine as the system , So memory access , The fastest . Later, the application system expanded horizontally , Caching exists as an independent system , Such as redis, But every time from the cache ...
- c# Instantiate inheritance class , You must make a reference to the assembly of the inherited class .net core Redis Logic analysis and examples of distributed cache client implementation demo Index and transaction of database notes centos 7 Lower installation python 3.6 note You big brother ~ C# Open source framework ( Reprint ) JSON C# Class Generator --- from json String generation C# Entity class tools
c# Instantiate inheritance class , You must make a reference to the assembly of the inherited class 0x00 problem type “Model.NewModel” Define... In an unreferenced assembly . Must add to assembly “Model, Version=1.0.0.0, Cu ...
- 30 Line code WCF Concurrent performance testing
[ Here's just a personal view , Welcome to exchange ] 30 Line code WCF Concurrent performance Lightweight testing . 1. Call concurrent test interface static void Main() { List< ...
- 20172327 2018-2019-1 《 First line of code Android》 The first chapter is learning summary
Student number 2018-2019-1 < First line of code Android> The first chapter is learning summary Summary of the learning content of the textbook - Android System architecture : 1.Linux Kernel layer Android The system is based on Linux Kernel , this ...
Random recommendation
- Lethal thunder dog --- WeChat development 58---- Micro website jquery_mobile Control introduction
We introduced the basic jqm How to use it , So in this class, we will start to play with his controls 1... Layout grid <!DOCTYPE html> <html> <head> & ...
- Perfect solution Informix The problem of garbled Chinese
Perfect solution Informix The problem of garbled Chinese Informix yes IBM One of its databases , If it wasn't for this project , I don't know that there is such a database in my life . The company's projects are all over the country , Various deployment environments, various application scenarios ...
- Completely reinstall without knowing the account password Mac Min Of OS X10.7 System
present situation : 1. Original system OS X 10.7 2. The old account doesn't know the password 3.Mac Small box Purpose : 1. Delete the old account 2. Update the system to 10.9 above Try the process 1: 1. Hold down option key + Turn it on 2. choice “ Disk tools ” ...
- vijosP1319 The sequence
vijosP1319 The sequence link :https://vijos.org/p/1319 [ Ideas ] mathematics . Equivalent to commutative base 2 by k. [ Code ] #include<iostream> using n ...
- POJ 2251 Dungeon Master( Dungeon Master )
p.MsoNormal { margin-bottom: 10.0000pt; font-family: Tahoma; font-size: 11.0000pt } h1 { margin-top: ...
- MySQL Ingenious construction sum The index helps us improve at least 100% The efficiency of
There are two tables. , surface a CREATE TABLE `a` ( `id` mediumint() unsigned NOT NULL AUTO_INCREMENT, `fid` ) unsigned ', `c ...
- 20145118 《Java Programming 》 The first 5 Weekly learning summary Summary of the learning content of the textbook
20145118 <Java Programming > The first 5 Weekly learning summary Summary of the learning content of the textbook 1.Java All errors in will be packaged as objects , Can pass try.catch Syntax handles wrong objects , Execute first try, If there is an error, jump out ...
- *2_3_5_ Join in reference model
Excerpt from :http://book.2cto.com/201408/46009.html stay 2.1 When describing the block diagram of the verification platform in this section ,reference model Used to complete and DUT Same function . referen ...
- mahout Related introduction
https://blog.csdn.net/xiaopihaierletian/article/details/72674592 https://www.cnblogs.com/zlslch/p/67 ...
- Windows10: How to install whl file
whl Format is essentially a compressed package , It contains py file , And compiled pyd file . It makes it possible to , Choose your own python Environment for installation . The installation method is very simple , Enter command line input pip instal ...