博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
memcached(五)--源码分析,启动
阅读量:7129 次
发布时间:2019-06-28

本文共 5022 字,大约阅读时间需要 16 分钟。

  源码memcached.c中,main入口函数。

 

第一步,根据memcached的启动参数做校验参数、配置

main函数中,几乎600行代码都是这些参数校验。吐槽一个。

 

第二步,初始化

  2.1:初始化主线程的libevent。

main_base = event_init();

 

  2.2:初始化memcached的stats信息。

  在文本协议的memcached中,我们nc/telent后输入stats命令,会很快地输出一些当前memcached的信息的。这些就是stats信息。并不是输入stats的时候才遍历统计出来的。而是已经保存好了这份信息。代码调用在main函数中的:

stats_init();

  具体的统计信息,可以在memcached.h这个文件中找到:

/** * Global stats. */struct stats {    pthread_mutex_t mutex;    unsigned int  curr_items;    unsigned int  total_items;    uint64_t      curr_bytes;    unsigned int  curr_conns;    unsigned int  total_conns;    uint64_t      rejected_conns;    uint64_t      malloc_fails;    unsigned int  reserved_fds;    unsigned int  conn_structs;    uint64_t      get_cmds;    uint64_t      set_cmds;    uint64_t      touch_cmds;    uint64_t      get_hits;    uint64_t      get_misses;    uint64_t      touch_hits;    uint64_t      touch_misses;    uint64_t      evictions;    uint64_t      reclaimed;    time_t        started;          /* when the process was started */    bool          accepting_conns;  /* whether we are currently accepting */    uint64_t      listen_disabled_num;    unsigned int  hash_power_level; /* Better hope it's not over 9000 */    uint64_t      hash_bytes;       /* size used for hash tables */    bool          hash_is_expanding; /* If the hash table is being expanded */    uint64_t      expired_unfetched; /* items reclaimed but never touched */    uint64_t      evicted_unfetched; /* items evicted but never touched */    bool          slab_reassign_running; /* slab reassign in progress */    uint64_t      slabs_moved;       /* times slabs were moved around */    uint64_t      lru_crawler_starts; /* Number of item crawlers kicked off */    bool          lru_crawler_running; /* crawl in progress */    uint64_t      lru_maintainer_juggles; /* number of LRU bg pokes */};

 

  2.3:hash桶初始化

  代码main函数中的:

assoc_init(settings.hashpower_init);

  在memcached中,保存着一份hash表用来存放memcached key。默认这个hash表是2^16(65536)个key。后续会根据规则动态扩容这个hash表的。如果希望启动的时候,这个hash表更大,可以-o 参数调节。

  hash表中, memcached key作为key,value是item指针,并不是item value。

 

  2.4:初始化connection。

conn_init()

   也就是 memcached启动参数中的-c参数,默认1024。

  为了更快地找到connection的fd(文件描述符),实际上申请的connection会比配置的更大一点。

/* * Initializes the connections array. We don't actually allocate connection * structures until they're needed, so as to avoid wasting memory when the * maximum connection count is much higher than the actual number of * connections. * * This does end up wasting a few pointers' worth of memory for FDs that are * used for things other than connections, but that's worth it in exchange for * being able to directly index the conns array by FD. */static void conn_init(void) {    /* We're unlikely to see an FD much higher than maxconns. */    int next_fd = dup(1);    int headroom = 10;      /* account for extra unexpected open FDs */    struct rlimit rl;    max_fds = settings.maxconns + headroom + next_fd;    /* But if possible, get the actual highest FD we can possibly ever see. */    if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {        max_fds = rl.rlim_max;    } else {        fprintf(stderr, "Failed to query maximum file descriptor; "                        "falling back to maxconns\n");    }    close(next_fd);    if ((conns = calloc(max_fds, sizeof(conn *))) == NULL) {        fprintf(stderr, "Failed to allocate connection structures\n");        /* This is unrecoverable so bail out early. */        exit(1);    }}

 

  2.5:初始化slabs。

  在2.3的hash桶中初始化的是key。slabs初始化的是这些key对应的value。下面摘录关键代码:

while (++i < MAX_NUMBER_OF_SLAB_CLASSES-1 && size <= settings.item_size_max / factor) {        /* Make sure items are always n-byte aligned */        if (size % CHUNK_ALIGN_BYTES)            size += CHUNK_ALIGN_BYTES - (size % CHUNK_ALIGN_BYTES);        slabclass[i].size = size;        slabclass[i].perslab = settings.item_size_max / slabclass[i].size;        size *= factor;        if (settings.verbose > 1) {            fprintf(stderr, "slab class %3d: chunk size %9u perslab %7u\n",                    i, slabclass[i].size, slabclass[i].perslab);        }    }

  在初始化slab的时候,下一个slab的size(chunk size)总是大于等于当前slab的size的

 

  2.6:初始化worker线程。

memcached_thread_init(settings.num_threads, main_base);

  worker线程和main线程,组成了libevent的reactor模式。

 

  2.7:定时器

clock_handler(0, 0, 0);

  用于对比对象是否过期。

 

第三步、libevent主线程监听事件

/* enter the event loop */    if (event_base_loop(main_base, 0) != 0) {        retval = EXIT_FAILURE;    }

 

  主线程启动堆栈:

server_sockets——>server_socket——>conn_new——>event_handler——>drive_machine——>try_read_command(这里会判定,是文本协议还是二进制协议)

 

第四步、关闭hash桶线程

  在2.3的初始化步骤中,有线程操作。这里明确关闭这个线程。

void stop_assoc_maintenance_thread() {    mutex_lock(&maintenance_lock);    do_run_maintenance_thread = 0;    pthread_cond_signal(&maintenance_cond);    mutex_unlock(&maintenance_lock);    /* Wait for the maintenance thread to stop */    pthread_join(maintenance_tid, NULL);}

 

  memcached启动的主要流程就是这些了。

 

  最后来个图片,描述一下启动后的memcached结构。

 

  源码github上有,见:  文件有点大,可能浏览器卡顿一下。这里肯定就不贴出来了^_^ 

 

转载于:https://www.cnblogs.com/ELMND/p/4581729.html

你可能感兴趣的文章
Swoole入门到实战(二):进程,内存和协程、Swoole完美支持ThinkPHP5、分发Task异步任务机制实现...
查看>>
WebSocket系列之JavaScript中数字数据如何转换为二进制数据
查看>>
React16.2的fiber架构详解(3)
查看>>
React造轮子:拖拽排序组件「Dragact」
查看>>
WDTP:利器,在于轻便犀利
查看>>
探索从 MVC 到 MVVM + Flux 架构模式的转变
查看>>
【303天】跃迁之路——程序员高效学习方法论探索系列(实验阶段61-2017.12.05)...
查看>>
开机动画
查看>>
使用 CodeMirror 打造属于自己的在线代码编辑器
查看>>
【275天】每日项目总结系列013(2017.11.07)
查看>>
Thrift RPC使用入门
查看>>
多个cell中展示倒计时,本地和服务器时间差异解决方案
查看>>
面试--网络
查看>>
jest 是如何 mock 掉模块的
查看>>
Typescript:基本类型
查看>>
利用PHP实现常用的数据结构之队列(小白系列文章三)
查看>>
vue-webpack-boilerplate里面各文件解析
查看>>
HttpClient获取Cookie的一次踩坑实录
查看>>
当你只有一个设备的时候,如何做好屏幕适配
查看>>
CentOS6.9下JAVA程序泪崩
查看>>