memcached是什么呢?memcached是一个优秀的、高性能的内存缓存工具。
memcached具有以下的特点:
协议简单:memcached的服务器客户端通信并不使用复杂的MXL等格式,而是使用简单的基于文本的协议。
基于libevent的事件处理:libevent是个程序库,他将Linux 的epoll、BSD类操作系统的kqueue等时间处理功能封装成统一的接口。memcached使用这个libevent库,因此能在Linux、BSD、Solaris等操作系统上发挥其高性能。(libevent是什么)
内置内存存储方式:为了提高性能,memcached中保存的数据都存储在memcached内置的内存存储空间中。由于数据仅存在于内存中,因此重启memcached,重启操作系统会导致全部数据消失。另外,内容容量达到指定的值之后memcached回自动删除不适用的缓存。
Memcached不互通信的分布式:memcached尽管是“分布式”缓存服务器,但服务器端并没有分布式功能。各个memcached不会互相通信以共享信息。他的分布式主要是通过客户端实现的。
本文主要讲解memcached的连接模型,memcached由一条主线程(连接线程)监听连接,然后把成功的连接交给子线程(工作线程)处理读写操作。N条【启动memcached通过-t命令指定】子线程(工作线程)负责读写数据,一条子线程(工作线程)维护着多个连接。一个conn结构体对象对应着一个连接,主线程(连接线程)成功连接后,会把连接的内容赋值到一个conn结构体对象,并把这个conn结构体对象传递给一条子线程(工作线程)处理。
conn结构体:
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
![复制代码](https://i-blog.csdnimg.cn/blog_migrate/69c5a8ac3fa60e0848d784a6dd461da6.gif)
1 //memcached.c
2 int main{
3
4 // ......
5
6 // 第一步:初始化主线程的事件机制
7 /* initialize main thread libevent instance */
8 // libevent 事件机制初始化
9 main_base = event_init();
10
11 // ......
12
13 // 第二步:初始化 N 个 (初始值200,当连接超过200个的时候会往上递增) conn结构体对象
14 // 空闲连接数组初始化
15 conn_init();
16
17 // ......
18
19
20 // 第三步:启动工作线程
21 /* start up worker threads if MT mode */
22 thread_init(settings.num_threads, main_base);
23
24 // ......
25
26 // 第四步:初始化socket,绑定监听端口,为主线程的事件机制设置连接监听事件(event_set、event_add)
27 /**
28 memcached 有可配置的两种模式: unix 域套接字和 TCP/UDP, 允许客户端以两种方式向 memcached 发起请求. 客户端和服务器在同一个主机上的情况下可以用 unix 域套接字, 否则可以采用 TCP/UDP 的模式. 两种模式是不兼容的.
29 以下的代码便是根据 settings.socketpath 的值来决定启用哪种方式.
30 */
31 /**
32 第一种, unix 域套接字.
33 */
34 /* create unix mode sockets after dropping privileges */
35 if (settings.socketpath != NULL) {
36 errno = 0;
37 if (server_socket_unix(settings.socketpath,settings.access)) {
38 vperror("failed to listen on UNIX socket: %s", settings.socketpath);
39 exit(EX_OSERR);
40 }
41 }
42
43 /**
44 第二种, TCP/UDP.
45 */
46 /* create the listening socket, bind it, and init */
47 if (settings.socketpath == NULL) {
48 const char *portnumber_filename = getenv("MEMCACHED_PORT_FILENAME");
49 char temp_portnumber_filename[PATH_MAX];
50 FILE *portnumber_file = NULL;
51
52 // 读取端口号文件
53 if (portnumber_filename != NULL) {
54 snprintf(temp_portnumber_filename,
55 sizeof(temp_portnumber_filename),
56 "%s.lck", portnumber_filename);
57</