memcache 1.2.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +568 -2
- package/dist/index.cjs +1646 -490
- package/dist/index.d.cts +490 -4
- package/dist/index.d.ts +490 -4
- package/dist/index.js +1640 -489
- package/package.json +36 -19
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
[<img src="https://jaredwray.com/images/memcache.svg" alt="Memcache Logo" align="center">](https://memcachejs.org)
|
|
1
|
+
[<img src="https://jaredwray.com/images/memcache.svg" width="80%" height="80%" align="center" alt="Memcache Logo" align="center">](https://memcachejs.org)
|
|
2
2
|
|
|
3
3
|
[](https://codecov.io/gh/jaredwray/memcache)
|
|
4
4
|
[](https://github.com/jaredwray/memcache/actions/workflows/tests.yaml)
|
|
@@ -44,6 +44,27 @@ Nodejs Memcache Client
|
|
|
44
44
|
- [decr(key, value?)](#decrkey-value)
|
|
45
45
|
- [touch(key, exptime)](#touchkey-exptime)
|
|
46
46
|
- [Hook Examples](#hook-examples)
|
|
47
|
+
- [Distribution Algorithms](#distribution-algorithms)
|
|
48
|
+
- [KetamaHash (Default)](#ketamahash-default)
|
|
49
|
+
- [ModulaHash](#modulahash)
|
|
50
|
+
- [Choosing an Algorithm](#choosing-an-algorithm)
|
|
51
|
+
- [Retry Configuration](#retry-configuration)
|
|
52
|
+
- [Basic Retry Setup](#basic-retry-setup)
|
|
53
|
+
- [Backoff Strategies](#backoff-strategies)
|
|
54
|
+
- [Idempotent Safety](#idempotent-safety)
|
|
55
|
+
- [Methods Without Retry Support](#methods-without-retry-support)
|
|
56
|
+
- [SASL Authentication](#sasl-authentication)
|
|
57
|
+
- [Enabling SASL Authentication](#enabling-sasl-authentication)
|
|
58
|
+
- [SASL Options](#sasl-options)
|
|
59
|
+
- [Per-Node SASL Configuration](#per-node-sasl-configuration)
|
|
60
|
+
- [Authentication Events](#authentication-events)
|
|
61
|
+
- [Server Configuration](#server-configuration)
|
|
62
|
+
- [Auto Discovery](#auto-discovery)
|
|
63
|
+
- [Enabling Auto Discovery](#enabling-auto-discovery)
|
|
64
|
+
- [Auto Discovery Options](#auto-discovery-options)
|
|
65
|
+
- [Auto Discovery Events](#auto-discovery-events)
|
|
66
|
+
- [Legacy Command Support](#legacy-command-support)
|
|
67
|
+
- [IPv6 Support](#ipv6-support)
|
|
47
68
|
- [Contributing](#contributing)
|
|
48
69
|
- [License and Copyright](#license-and-copyright)
|
|
49
70
|
|
|
@@ -179,6 +200,11 @@ const client = new Memcache({
|
|
|
179
200
|
- `keepAlive?: boolean` - Keep connection alive (default: true)
|
|
180
201
|
- `keepAliveDelay?: number` - Keep alive delay in milliseconds (default: 1000)
|
|
181
202
|
- `hash?: HashProvider` - Hash provider for consistent hashing (default: KetamaHash)
|
|
203
|
+
- `retries?: number` - Number of retry attempts for failed commands (default: 0)
|
|
204
|
+
- `retryDelay?: number` - Base delay in milliseconds between retries (default: 100)
|
|
205
|
+
- `retryBackoff?: RetryBackoffFunction` - Function to calculate backoff delay (default: fixed delay)
|
|
206
|
+
- `retryOnlyIdempotent?: boolean` - Only retry commands marked as idempotent (default: true)
|
|
207
|
+
- `autoDiscover?: AutoDiscoverOptions` - AWS ElastiCache Auto Discovery configuration (see [Auto Discovery](#auto-discovery))
|
|
182
208
|
|
|
183
209
|
## Properties
|
|
184
210
|
|
|
@@ -200,6 +226,18 @@ Get or set the keepAlive setting. Updates all existing nodes. Requires `reconnec
|
|
|
200
226
|
### `keepAliveDelay: number`
|
|
201
227
|
Get or set the keep alive delay in milliseconds. Updates all existing nodes. Requires `reconnect()` to apply changes.
|
|
202
228
|
|
|
229
|
+
### `retries: number`
|
|
230
|
+
Get or set the number of retry attempts for failed commands (default: 0).
|
|
231
|
+
|
|
232
|
+
### `retryDelay: number`
|
|
233
|
+
Get or set the base delay in milliseconds between retry attempts (default: 100).
|
|
234
|
+
|
|
235
|
+
### `retryBackoff: RetryBackoffFunction`
|
|
236
|
+
Get or set the backoff function for calculating retry delays.
|
|
237
|
+
|
|
238
|
+
### `retryOnlyIdempotent: boolean`
|
|
239
|
+
Get or set whether retries are restricted to idempotent commands only (default: true).
|
|
240
|
+
|
|
203
241
|
## Connection Management
|
|
204
242
|
|
|
205
243
|
### `connect(nodeId?: string): Promise<void>`
|
|
@@ -373,6 +411,9 @@ client.on('miss', (key) => {
|
|
|
373
411
|
- `quit` - Emitted when quit command is sent
|
|
374
412
|
- `warn` - Emitted for warning messages
|
|
375
413
|
- `info` - Emitted for informational messages
|
|
414
|
+
- `autoDiscover` - Emitted on initial auto discovery with the cluster config
|
|
415
|
+
- `autoDiscoverUpdate` - Emitted when auto discovery detects a topology change
|
|
416
|
+
- `autoDiscoverError` - Emitted when auto discovery encounters an error
|
|
376
417
|
|
|
377
418
|
## Hooks
|
|
378
419
|
|
|
@@ -473,9 +514,534 @@ client.onHook('after:set', async (context) => {
|
|
|
473
514
|
});
|
|
474
515
|
```
|
|
475
516
|
|
|
517
|
+
# Distribution Algorithms
|
|
518
|
+
|
|
519
|
+
Memcache supports pluggable distribution algorithms to determine how keys are distributed across nodes. You can configure the algorithm using the `hash` option.
|
|
520
|
+
|
|
521
|
+
## KetamaHash (Default)
|
|
522
|
+
|
|
523
|
+
KetamaHash uses the Ketama consistent hashing algorithm, which minimizes key redistribution when nodes are added or removed. This is the default and recommended algorithm for production environments with dynamic scaling.
|
|
524
|
+
|
|
525
|
+
```javascript
|
|
526
|
+
import { Memcache } from 'memcache';
|
|
527
|
+
|
|
528
|
+
// KetamaHash is used by default
|
|
529
|
+
const client = new Memcache({
|
|
530
|
+
nodes: ['server1:11211', 'server2:11211', 'server3:11211']
|
|
531
|
+
});
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
**Characteristics:**
|
|
535
|
+
- Minimal key redistribution (~1/n keys move when adding/removing nodes)
|
|
536
|
+
- Uses virtual nodes for better distribution
|
|
537
|
+
- Supports weighted nodes
|
|
538
|
+
- Best for production environments with dynamic scaling
|
|
539
|
+
|
|
540
|
+
## ModulaHash
|
|
541
|
+
|
|
542
|
+
ModulaHash uses a simple modulo-based hashing algorithm (`hash(key) % nodeCount`). This is a simpler algorithm that may redistribute all keys when nodes change.
|
|
543
|
+
|
|
544
|
+
```javascript
|
|
545
|
+
import { Memcache, ModulaHash } from 'memcache';
|
|
546
|
+
|
|
547
|
+
// Use ModulaHash for distribution
|
|
548
|
+
const client = new Memcache({
|
|
549
|
+
nodes: ['server1:11211', 'server2:11211', 'server3:11211'],
|
|
550
|
+
hash: new ModulaHash()
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
// With a custom hash algorithm (default is sha1)
|
|
554
|
+
const client2 = new Memcache({
|
|
555
|
+
nodes: ['server1:11211', 'server2:11211'],
|
|
556
|
+
hash: new ModulaHash('md5')
|
|
557
|
+
});
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
**Characteristics:**
|
|
561
|
+
- Simple and fast algorithm
|
|
562
|
+
- All keys may be redistributed when nodes are added or removed
|
|
563
|
+
- Supports weighted nodes (nodes with higher weight appear more in the distribution)
|
|
564
|
+
- Best for fixed-size clusters or testing environments
|
|
565
|
+
|
|
566
|
+
### Weighted Nodes with ModulaHash
|
|
567
|
+
|
|
568
|
+
ModulaHash supports weighted nodes, where nodes with higher weights receive proportionally more keys:
|
|
569
|
+
|
|
570
|
+
```javascript
|
|
571
|
+
import { Memcache, ModulaHash, createNode } from 'memcache';
|
|
572
|
+
|
|
573
|
+
// Create nodes with different weights
|
|
574
|
+
const node1 = createNode('server1', 11211, { weight: 3 }); // 3x traffic
|
|
575
|
+
const node2 = createNode('server2', 11211, { weight: 1 }); // 1x traffic
|
|
576
|
+
|
|
577
|
+
const client = new Memcache({
|
|
578
|
+
nodes: [node1, node2],
|
|
579
|
+
hash: new ModulaHash()
|
|
580
|
+
});
|
|
581
|
+
|
|
582
|
+
// server1 will receive approximately 75% of keys
|
|
583
|
+
// server2 will receive approximately 25% of keys
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
## Choosing an Algorithm
|
|
587
|
+
|
|
588
|
+
| Feature | KetamaHash | ModulaHash |
|
|
589
|
+
|---------|------------|------------|
|
|
590
|
+
| Key redistribution on node change | Minimal (~1/n keys) | All keys may move |
|
|
591
|
+
| Complexity | Higher (virtual nodes) | Lower (simple modulo) |
|
|
592
|
+
| Performance | Slightly slower | Faster |
|
|
593
|
+
| Best for | Dynamic scaling | Fixed clusters |
|
|
594
|
+
| Weighted nodes | Yes | Yes |
|
|
595
|
+
|
|
596
|
+
**Use KetamaHash (default) when:**
|
|
597
|
+
- Your cluster size may change dynamically
|
|
598
|
+
- You want to minimize cache invalidation during scaling
|
|
599
|
+
- You're running in production
|
|
600
|
+
|
|
601
|
+
**Use ModulaHash when:**
|
|
602
|
+
- Your cluster size is fixed
|
|
603
|
+
- You prefer simplicity over minimal redistribution
|
|
604
|
+
- You're in a testing or development environment
|
|
605
|
+
|
|
606
|
+
# Retry Configuration
|
|
607
|
+
|
|
608
|
+
The Memcache client supports automatic retry of failed commands with configurable backoff strategies.
|
|
609
|
+
|
|
610
|
+
## Basic Retry Setup
|
|
611
|
+
|
|
612
|
+
Enable retries by setting the `retries` option:
|
|
613
|
+
|
|
614
|
+
```javascript
|
|
615
|
+
import { Memcache } from 'memcache';
|
|
616
|
+
|
|
617
|
+
const client = new Memcache({
|
|
618
|
+
nodes: ['localhost:11211'],
|
|
619
|
+
retries: 3, // Retry up to 3 times
|
|
620
|
+
retryDelay: 100 // 100ms between retries
|
|
621
|
+
});
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
You can also modify retry settings at runtime:
|
|
625
|
+
|
|
626
|
+
```javascript
|
|
627
|
+
client.retries = 5;
|
|
628
|
+
client.retryDelay = 200;
|
|
629
|
+
```
|
|
630
|
+
|
|
631
|
+
## Backoff Strategies
|
|
632
|
+
|
|
633
|
+
The client includes two built-in backoff functions:
|
|
634
|
+
|
|
635
|
+
### Fixed Delay (Default)
|
|
636
|
+
|
|
637
|
+
```javascript
|
|
638
|
+
import { Memcache, defaultRetryBackoff } from 'memcache';
|
|
639
|
+
|
|
640
|
+
const client = new Memcache({
|
|
641
|
+
retries: 3,
|
|
642
|
+
retryDelay: 100,
|
|
643
|
+
retryBackoff: defaultRetryBackoff // 100ms, 100ms, 100ms
|
|
644
|
+
});
|
|
645
|
+
```
|
|
646
|
+
|
|
647
|
+
### Exponential Backoff
|
|
648
|
+
|
|
649
|
+
```javascript
|
|
650
|
+
import { Memcache, exponentialRetryBackoff } from 'memcache';
|
|
651
|
+
|
|
652
|
+
const client = new Memcache({
|
|
653
|
+
retries: 3,
|
|
654
|
+
retryDelay: 100,
|
|
655
|
+
retryBackoff: exponentialRetryBackoff // 100ms, 200ms, 400ms
|
|
656
|
+
});
|
|
657
|
+
```
|
|
658
|
+
|
|
659
|
+
### Custom Backoff Function
|
|
660
|
+
|
|
661
|
+
You can provide your own backoff function:
|
|
662
|
+
|
|
663
|
+
```javascript
|
|
664
|
+
const client = new Memcache({
|
|
665
|
+
retries: 3,
|
|
666
|
+
retryDelay: 100,
|
|
667
|
+
retryBackoff: (attempt, baseDelay) => {
|
|
668
|
+
// Exponential backoff with jitter
|
|
669
|
+
const delay = baseDelay * Math.pow(2, attempt);
|
|
670
|
+
return delay + Math.random() * delay * 0.1;
|
|
671
|
+
}
|
|
672
|
+
});
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
The backoff function receives:
|
|
676
|
+
- `attempt` - The current attempt number (0-indexed)
|
|
677
|
+
- `baseDelay` - The configured `retryDelay` value
|
|
678
|
+
|
|
679
|
+
## Idempotent Safety
|
|
680
|
+
|
|
681
|
+
**Important:** By default, retries are only performed for commands explicitly marked as idempotent. This prevents accidental double-execution of non-idempotent operations like `incr`, `decr`, `append`, and `prepend`.
|
|
682
|
+
|
|
683
|
+
### Why This Matters
|
|
684
|
+
|
|
685
|
+
If a network timeout occurs after the server applies a mutation but before the client receives the response, retrying would apply the mutation twice:
|
|
686
|
+
- Counter incremented twice instead of once
|
|
687
|
+
- Data appended twice instead of once
|
|
688
|
+
|
|
689
|
+
### Safe Usage Patterns
|
|
690
|
+
|
|
691
|
+
**For read operations (always safe to retry):**
|
|
692
|
+
|
|
693
|
+
```javascript
|
|
694
|
+
// Mark read operations as idempotent
|
|
695
|
+
await client.execute('get mykey', nodes, { idempotent: true });
|
|
696
|
+
```
|
|
697
|
+
|
|
698
|
+
**For idempotent writes (safe to retry):**
|
|
699
|
+
|
|
700
|
+
```javascript
|
|
701
|
+
// SET with the same value is idempotent
|
|
702
|
+
await client.execute('set mykey 0 0 5\r\nhello', nodes, { idempotent: true });
|
|
703
|
+
```
|
|
704
|
+
|
|
705
|
+
**Disable safety for all commands (use with caution):**
|
|
706
|
+
|
|
707
|
+
```javascript
|
|
708
|
+
const client = new Memcache({
|
|
709
|
+
retries: 3,
|
|
710
|
+
retryOnlyIdempotent: false // Allow retries for ALL commands
|
|
711
|
+
});
|
|
712
|
+
```
|
|
713
|
+
|
|
714
|
+
### Behavior Summary
|
|
715
|
+
|
|
716
|
+
| `retryOnlyIdempotent` | `idempotent` flag | Retries enabled? |
|
|
717
|
+
|-----------------------|-------------------|------------------|
|
|
718
|
+
| `true` (default) | `false` (default) | No |
|
|
719
|
+
| `true` (default) | `true` | Yes |
|
|
720
|
+
| `false` | (any) | Yes |
|
|
721
|
+
|
|
722
|
+
### Methods Without Retry Support
|
|
723
|
+
|
|
724
|
+
The following methods do not use the retry mechanism and have their own error handling:
|
|
725
|
+
|
|
726
|
+
- `get()` - Returns `undefined` on failure
|
|
727
|
+
- `gets()` - Returns partial results on node failure
|
|
728
|
+
- `flush()` - Operates directly on nodes
|
|
729
|
+
- `stats()` - Operates directly on nodes
|
|
730
|
+
- `version()` - Operates directly on nodes
|
|
731
|
+
|
|
732
|
+
To use retries with read operations, use the `execute()` method directly:
|
|
733
|
+
|
|
734
|
+
```javascript
|
|
735
|
+
const nodes = await client.getNodesByKey('mykey');
|
|
736
|
+
const results = await client.execute('get mykey', nodes, { idempotent: true });
|
|
737
|
+
```
|
|
738
|
+
|
|
739
|
+
# SASL Authentication
|
|
740
|
+
|
|
741
|
+
The Memcache client supports SASL (Simple Authentication and Security Layer) authentication using the PLAIN mechanism. This allows you to connect to memcached servers that require authentication.
|
|
742
|
+
|
|
743
|
+
## Enabling SASL Authentication
|
|
744
|
+
|
|
745
|
+
```javascript
|
|
746
|
+
import { Memcache } from 'memcache';
|
|
747
|
+
|
|
748
|
+
const client = new Memcache({
|
|
749
|
+
nodes: ['localhost:11211'],
|
|
750
|
+
sasl: {
|
|
751
|
+
username: 'myuser',
|
|
752
|
+
password: 'mypassword',
|
|
753
|
+
},
|
|
754
|
+
});
|
|
755
|
+
|
|
756
|
+
await client.connect();
|
|
757
|
+
// Client is now authenticated and ready to use
|
|
758
|
+
```
|
|
759
|
+
|
|
760
|
+
## SASL Options
|
|
761
|
+
|
|
762
|
+
The `sasl` option accepts an object with the following properties:
|
|
763
|
+
|
|
764
|
+
- `username: string` - The username for authentication (required)
|
|
765
|
+
- `password: string` - The password for authentication (required)
|
|
766
|
+
- `mechanism?: 'PLAIN'` - The SASL mechanism to use (default: 'PLAIN')
|
|
767
|
+
|
|
768
|
+
Currently, only the PLAIN mechanism is supported.
|
|
769
|
+
|
|
770
|
+
## Binary Protocol Methods
|
|
771
|
+
|
|
772
|
+
**Important:** Memcached servers with SASL enabled (`-S` flag) require the binary protocol for all operations after authentication. The standard text-based methods (`client.get()`, `client.set()`, etc.) will not work on SASL-enabled servers.
|
|
773
|
+
|
|
774
|
+
Use the `binary*` methods on nodes for SASL-enabled servers:
|
|
775
|
+
|
|
776
|
+
```javascript
|
|
777
|
+
import { Memcache } from 'memcache';
|
|
778
|
+
|
|
779
|
+
const client = new Memcache({
|
|
780
|
+
nodes: ['localhost:11211'],
|
|
781
|
+
sasl: { username: 'user', password: 'pass' },
|
|
782
|
+
});
|
|
783
|
+
|
|
784
|
+
await client.connect();
|
|
785
|
+
|
|
786
|
+
// Access the node directly for binary operations
|
|
787
|
+
const node = client.nodes[0];
|
|
788
|
+
|
|
789
|
+
// Binary protocol operations
|
|
790
|
+
await node.binarySet('mykey', 'myvalue', 3600); // Set with 1 hour expiry
|
|
791
|
+
const value = await node.binaryGet('mykey'); // Get value
|
|
792
|
+
await node.binaryDelete('mykey'); // Delete key
|
|
793
|
+
|
|
794
|
+
// Other binary operations
|
|
795
|
+
await node.binaryAdd('newkey', 'value'); // Add (only if not exists)
|
|
796
|
+
await node.binaryReplace('existingkey', 'newvalue'); // Replace (only if exists)
|
|
797
|
+
await node.binaryIncr('counter', 1); // Increment
|
|
798
|
+
await node.binaryDecr('counter', 1); // Decrement
|
|
799
|
+
await node.binaryAppend('mykey', '-suffix'); // Append to value
|
|
800
|
+
await node.binaryPrepend('mykey', 'prefix-'); // Prepend to value
|
|
801
|
+
await node.binaryTouch('mykey', 7200); // Update expiration
|
|
802
|
+
await node.binaryFlush(); // Flush all
|
|
803
|
+
const version = await node.binaryVersion(); // Get server version
|
|
804
|
+
const stats = await node.binaryStats(); // Get server stats
|
|
805
|
+
```
|
|
806
|
+
|
|
807
|
+
## Per-Node SASL Configuration
|
|
808
|
+
|
|
809
|
+
You can also configure SASL credentials when creating individual nodes:
|
|
810
|
+
|
|
811
|
+
```javascript
|
|
812
|
+
import { createNode } from 'memcache';
|
|
813
|
+
|
|
814
|
+
// Create a node with SASL credentials
|
|
815
|
+
const node = createNode('localhost', 11211, {
|
|
816
|
+
sasl: { username: 'user', password: 'pass' },
|
|
817
|
+
});
|
|
818
|
+
|
|
819
|
+
// Connect and use binary methods
|
|
820
|
+
await node.connect();
|
|
821
|
+
await node.binarySet('mykey', 'hello');
|
|
822
|
+
const value = await node.binaryGet('mykey');
|
|
823
|
+
```
|
|
824
|
+
|
|
825
|
+
## Authentication Events
|
|
826
|
+
|
|
827
|
+
You can listen for authentication events on both nodes and the client:
|
|
828
|
+
|
|
829
|
+
```javascript
|
|
830
|
+
import { Memcache, MemcacheNode } from 'memcache';
|
|
831
|
+
|
|
832
|
+
// Node-level events
|
|
833
|
+
const node = new MemcacheNode('localhost', 11211, {
|
|
834
|
+
sasl: { username: 'user', password: 'pass' },
|
|
835
|
+
});
|
|
836
|
+
|
|
837
|
+
node.on('authenticated', () => {
|
|
838
|
+
console.log('Node authenticated successfully');
|
|
839
|
+
});
|
|
840
|
+
|
|
841
|
+
node.on('error', (error) => {
|
|
842
|
+
if (error.message.includes('SASL authentication failed')) {
|
|
843
|
+
console.error('Authentication failed:', error.message);
|
|
844
|
+
}
|
|
845
|
+
});
|
|
846
|
+
|
|
847
|
+
await node.connect();
|
|
848
|
+
|
|
849
|
+
// Client-level events (forwarded from nodes)
|
|
850
|
+
const client = new Memcache({
|
|
851
|
+
nodes: ['localhost:11211'],
|
|
852
|
+
sasl: { username: 'user', password: 'pass' },
|
|
853
|
+
});
|
|
854
|
+
|
|
855
|
+
client.on('authenticated', () => {
|
|
856
|
+
console.log('Client authenticated');
|
|
857
|
+
});
|
|
858
|
+
|
|
859
|
+
await client.connect();
|
|
860
|
+
```
|
|
861
|
+
|
|
862
|
+
### Node Properties
|
|
863
|
+
|
|
864
|
+
- `node.hasSaslCredentials` - Returns `true` if SASL credentials are configured
|
|
865
|
+
- `node.isAuthenticated` - Returns `true` if the node has successfully authenticated
|
|
866
|
+
|
|
867
|
+
## Server Configuration
|
|
868
|
+
|
|
869
|
+
To use SASL authentication, your memcached server must be configured with SASL support:
|
|
870
|
+
|
|
871
|
+
1. **Build memcached with SASL support** - Ensure memcached was compiled with `--enable-sasl`
|
|
872
|
+
|
|
873
|
+
2. **Create SASL users** - Use `saslpasswd2` to create users:
|
|
874
|
+
```bash
|
|
875
|
+
saslpasswd2 -a memcached -c username
|
|
876
|
+
```
|
|
877
|
+
|
|
878
|
+
3. **Configure SASL mechanism** - Create `/etc/sasl2/memcached.conf`:
|
|
879
|
+
```
|
|
880
|
+
mech_list: plain
|
|
881
|
+
```
|
|
882
|
+
|
|
883
|
+
4. **Start memcached with SASL** - Use the `-S` flag:
|
|
884
|
+
```bash
|
|
885
|
+
memcached -S -m 64 -p 11211
|
|
886
|
+
```
|
|
887
|
+
|
|
888
|
+
For more details, see the [memcached SASL documentation](https://github.com/memcached/memcached/wiki/SASLHowto).
|
|
889
|
+
|
|
890
|
+
# Auto Discovery
|
|
891
|
+
|
|
892
|
+
The Memcache client supports AWS ElastiCache Auto Discovery, which automatically detects cluster topology changes and adds or removes nodes as needed. When enabled, the client connects to a configuration endpoint, retrieves the current list of cache nodes, and periodically polls for changes.
|
|
893
|
+
|
|
894
|
+
## Enabling Auto Discovery
|
|
895
|
+
|
|
896
|
+
```javascript
|
|
897
|
+
import { Memcache } from 'memcache';
|
|
898
|
+
|
|
899
|
+
const client = new Memcache({
|
|
900
|
+
nodes: [],
|
|
901
|
+
autoDiscover: {
|
|
902
|
+
enabled: true,
|
|
903
|
+
configEndpoint: 'my-cluster.cfg.use1.cache.amazonaws.com:11211',
|
|
904
|
+
},
|
|
905
|
+
});
|
|
906
|
+
|
|
907
|
+
await client.connect();
|
|
908
|
+
// The client automatically discovers and connects to all cluster nodes
|
|
909
|
+
```
|
|
910
|
+
|
|
911
|
+
If you omit `configEndpoint`, the first node in the `nodes` array is used as the configuration endpoint:
|
|
912
|
+
|
|
913
|
+
```javascript
|
|
914
|
+
const client = new Memcache({
|
|
915
|
+
nodes: ['my-cluster.cfg.use1.cache.amazonaws.com:11211'],
|
|
916
|
+
autoDiscover: {
|
|
917
|
+
enabled: true,
|
|
918
|
+
},
|
|
919
|
+
});
|
|
920
|
+
```
|
|
921
|
+
|
|
922
|
+
## Auto Discovery Options
|
|
923
|
+
|
|
924
|
+
The `autoDiscover` option accepts an object with the following properties:
|
|
925
|
+
|
|
926
|
+
- `enabled: boolean` - Enable auto discovery of cluster nodes (required)
|
|
927
|
+
- `pollingInterval?: number` - How often to poll for topology changes, in milliseconds (default: 60000)
|
|
928
|
+
- `configEndpoint?: string` - The configuration endpoint to use for discovery. This is typically the `.cfg` endpoint from ElastiCache. If not specified, the first node in the `nodes` array will be used
|
|
929
|
+
- `useLegacyCommand?: boolean` - Use the legacy `get AmazonElastiCache:cluster` command instead of `config get cluster` (default: false)
|
|
930
|
+
|
|
931
|
+
## Auto Discovery Events
|
|
932
|
+
|
|
933
|
+
The client emits events during the auto discovery lifecycle:
|
|
934
|
+
|
|
935
|
+
```javascript
|
|
936
|
+
const client = new Memcache({
|
|
937
|
+
nodes: [],
|
|
938
|
+
autoDiscover: {
|
|
939
|
+
enabled: true,
|
|
940
|
+
configEndpoint: 'my-cluster.cfg.use1.cache.amazonaws.com:11211',
|
|
941
|
+
},
|
|
942
|
+
});
|
|
943
|
+
|
|
944
|
+
// Emitted on initial discovery with the full cluster config
|
|
945
|
+
client.on('autoDiscover', (config) => {
|
|
946
|
+
console.log('Discovered nodes:', config.nodes);
|
|
947
|
+
console.log('Config version:', config.version);
|
|
948
|
+
});
|
|
949
|
+
|
|
950
|
+
// Emitted when polling detects a topology change
|
|
951
|
+
client.on('autoDiscoverUpdate', (config) => {
|
|
952
|
+
console.log('Cluster topology changed:', config.nodes);
|
|
953
|
+
});
|
|
954
|
+
|
|
955
|
+
// Emitted when discovery encounters an error (non-fatal, retries on next poll)
|
|
956
|
+
client.on('autoDiscoverError', (error) => {
|
|
957
|
+
console.error('Discovery error:', error.message);
|
|
958
|
+
});
|
|
959
|
+
|
|
960
|
+
await client.connect();
|
|
961
|
+
```
|
|
962
|
+
|
|
963
|
+
## Legacy Command Support
|
|
964
|
+
|
|
965
|
+
For ElastiCache engine versions older than 1.4.14, use the legacy discovery command:
|
|
966
|
+
|
|
967
|
+
```javascript
|
|
968
|
+
const client = new Memcache({
|
|
969
|
+
nodes: [],
|
|
970
|
+
autoDiscover: {
|
|
971
|
+
enabled: true,
|
|
972
|
+
configEndpoint: 'my-cluster.cfg.use1.cache.amazonaws.com:11211',
|
|
973
|
+
useLegacyCommand: true, // Uses 'get AmazonElastiCache:cluster' instead of 'config get cluster'
|
|
974
|
+
},
|
|
975
|
+
});
|
|
976
|
+
```
|
|
977
|
+
|
|
978
|
+
# IPv6 Support
|
|
979
|
+
|
|
980
|
+
The Memcache client fully supports IPv6 addresses using standard bracket notation in URIs.
|
|
981
|
+
|
|
982
|
+
## Connecting to IPv6 Nodes
|
|
983
|
+
|
|
984
|
+
```javascript
|
|
985
|
+
import { Memcache } from 'memcache';
|
|
986
|
+
|
|
987
|
+
// IPv6 loopback
|
|
988
|
+
const client = new Memcache('[::1]:11211');
|
|
989
|
+
|
|
990
|
+
// Multiple IPv6 nodes
|
|
991
|
+
const client = new Memcache({
|
|
992
|
+
nodes: [
|
|
993
|
+
'[::1]:11211',
|
|
994
|
+
'[2001:db8::1]:11211',
|
|
995
|
+
'memcache://[2001:db8::2]:11212',
|
|
996
|
+
],
|
|
997
|
+
});
|
|
998
|
+
|
|
999
|
+
await client.connect();
|
|
1000
|
+
```
|
|
1001
|
+
|
|
1002
|
+
## IPv6 in Auto Discovery
|
|
1003
|
+
|
|
1004
|
+
When auto discovery returns IPv6 node addresses, the client automatically brackets them for correct URI handling:
|
|
1005
|
+
|
|
1006
|
+
```javascript
|
|
1007
|
+
const client = new Memcache({
|
|
1008
|
+
nodes: [],
|
|
1009
|
+
autoDiscover: {
|
|
1010
|
+
enabled: true,
|
|
1011
|
+
configEndpoint: '[2001:db8::1]:11211',
|
|
1012
|
+
},
|
|
1013
|
+
});
|
|
1014
|
+
|
|
1015
|
+
await client.connect();
|
|
1016
|
+
// Discovered IPv6 nodes are added as [host]:port automatically
|
|
1017
|
+
```
|
|
1018
|
+
|
|
1019
|
+
## IPv6 Node IDs
|
|
1020
|
+
|
|
1021
|
+
Node IDs for IPv6 addresses use bracket notation to avoid ambiguity:
|
|
1022
|
+
|
|
1023
|
+
```javascript
|
|
1024
|
+
const client = new Memcache({
|
|
1025
|
+
nodes: ['[::1]:11211', '[2001:db8::1]:11212'],
|
|
1026
|
+
});
|
|
1027
|
+
|
|
1028
|
+
console.log(client.nodeIds);
|
|
1029
|
+
// ['[::1]:11211', '[2001:db8::1]:11212']
|
|
1030
|
+
```
|
|
1031
|
+
|
|
1032
|
+
# Benchmarks
|
|
1033
|
+
|
|
1034
|
+
These are provided to show a simple benchmark against current libraries. This is not robust but it is something we update regularly to make sure we are keeping performant.
|
|
1035
|
+
|
|
1036
|
+
| name | summary | ops/sec | time/op | margin | samples |
|
|
1037
|
+
|------------------------------|:---------:|----------:|----------:|:--------:|----------:|
|
|
1038
|
+
| memcache set/get (v1.4.0) | 🥇 | 3K | 350µs | ±0.19% | 10K |
|
|
1039
|
+
| memcached set/get (v2.2.2) | -2.9% | 3K | 361µs | ±0.16% | 10K |
|
|
1040
|
+
| memjs set/get (v1.3.2) | -12% | 3K | 398µs | ±0.17% | 10K |
|
|
1041
|
+
|
|
476
1042
|
# Contributing
|
|
477
1043
|
|
|
478
|
-
Please read our [Contributing Guidelines](./CONTRIBUTING.md) and also our [Code of Conduct](./CODE_OF_CONDUCT.md).
|
|
1044
|
+
Please read our [Contributing Guidelines](./CONTRIBUTING.md) and also our [Code of Conduct](./CODE_OF_CONDUCT.md).
|
|
479
1045
|
|
|
480
1046
|
# License and Copyright
|
|
481
1047
|
|