Webdis内部解析

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
全局流量管理 GTM,标准版 1个月
简介:

Webdis是redis的http代理,源代码在:git://github.com/nicolasff/webdis.git

webdis.json是配置文件

webdis.c是入口程序

 

其中有三个比较重要的结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
struct  server {
 
     int  fd;
     struct  event  ev;
     struct  event_base * base ;   //libevent的event事件
 
     struct  conf *cfg;  //配置文件,设置有多少个进程(http_threads)啥的放在里面
 
     /* worker threads */
     struct  worker **w;  //有多个worker,父进程有多少worker线程
     int  next_worker;
 
     /* log lock */
     struct  {
         pid_t self;
         int  fd;
     } log;  //日志结构
};

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
struct  worker {
 
     /* self */
     pthread_t thread; 
     struct  event_base * base //libevent的event事件
 
     /* connection dispatcher */
     struct  server *s;  //父server
     int  link[2]; //由pipe建立的管道,link[0]是管道读取端,link[1]是管道写入端
 
     /* Redis connection pool */
     struct  pool *pool;  //连接池,与redis连接的连接池
};
1
2
3
4
5
6
7
8
9
10
11
12
13
struct  pool {
 
struct  worker *w; //worker线程
 
struct  conf *cfg; //配置文件
 
const  redisAsyncContext **ac; //redis的同步上下文
 
int  count; //pool大小,即s->cfg->pool_size_per_thread
 
int  cur;
 
};

 

这三个结构每个结构都有一个指针指向父结构,比如pool的worker*

这样能保证从任意一个结构中都能取得父结构的需要的属性

 

 

webdis的server-worker-pool的关系是这样的:

一个Server包含多个worker,每个woker占一个进程的资源

一个worker包含一个pool

Server的任务是接受HTTP请求,传递HTTP的套接字给worker

Worker才是webdis的实际处理类,一方面接受Server传递过来的HTTP请求,一方面由pool保持和redis的连接

Pool是连接池,保持了与redis的连接,防止重复的连接操作造成过多的资源浪费

 

webdis的入口是Webdis.c文件

主要运行了:

Server_new(conf)

server_start(s)

 

-------------------------------new 的过程开始----------------------------------------

Server_new主要函数:

conf_read

worker_new * n

 

worker_new主要函数:

Pipe(w->link) //建立管道

w->pool = pool_new(w, s->cfg->pool_size_per_thread);

 

pool_new主要函数:

p->ac = calloc(count, sizeof(redisAsyncContext*));

p->cfg = w->s->cfg;

 

pool中有一个redisAsyncContext结构,这个结构是hiredis的范围了:

Hiredis是redis的C客户端库

https://github.com/antirez/hiredis

Hiredis is a minimalistic C client library for the Redis database.

 

Hiredis:

使用方法大是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
redisAsyncContext *c = redisAsyncConnect( "127.0.0.1" , 6379);
 
int  redisAsyncCommand(
 
redisAsyncContext *ac, redisCallbackFn *fn, void  *privdata,
 
const  char  *format, ...);
 
int  redisAsyncCommandArgv(
 
redisAsyncContext *ac, redisCallbackFn *fn, void  *privdata,
 
int  argc, const  char  **argv, const  size_t *argvlen);
 
void  redisAsyncDisconnect(redisAsyncContext *ac);
1
------------------------------- new  的过程结束----------------------------------------
1
  
1
-------------------------------start 的过程开始---------------------------------------

server_start主要函数:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
s-> base  = event_base_new(); //注册一个事件
 
worker_start(s->w[i]); //开启worker
 
s->fd = socket_setup(s->cfg->http_host, s->cfg->http_port); //建立socket
 
 
 
/* start http server */
 
event_set(&s->ev, s->fd, EV_READ | EV_PERSIST, server_can_accept, s);
 
event_base_set(s-> base , &s->ev);
 
event_add(&s->ev, NULL);
 
event_base_dispatch(s-> base );

 

worker_start主要函数:

1
pthread_create(&w->thread, NULL, worker_main, w); //开了一个线程来运行worker_main函数

worker_main主要函数:

1
2
3
4
5
6
7
8
9
10
11
12
w-> base  = event_base_new(); //注册event
 
/* monitor pipe link */
event_set(&ev, w->link[0], EV_READ | EV_PERSIST, worker_on_new_client, w);
event_base_set(w-> base , &ev);
event_add(&ev, NULL);
 
/* connect to Redis */
worker_pool_connect(w); //worker和pool的连接,即worker和redis的连接
 
/* loop */
event_base_dispatch(w-> base );

worker_pool_connect主要函数:

1
pool_connect(w->pool, 1); //指定w->pool来连接redis

 

pool_connect主要函数: //连接redis

1
2
3
4
5
6
7
8
9
ac = redisAsyncConnect(p->cfg->redis_host, p->cfg->redis_port);
 
redisLibeventAttach(ac, p->w-> base );
 
redisAsyncSetConnectCallback(ac, pool_on_connect);
 
redisAsyncSetDisconnectCallback(ac, pool_on_disconnect);
 
redisAsyncCommand(ac, NULL, NULL, "AUTH %s" , p->cfg->redis_auth);
1
下面就进入到了hiredis的部分了
1
-------------------------------start 的过程结束---------------------------------------
1
  







本文转自轩脉刃博客园博客,原文链接:http://www.cnblogs.com/yjf512/archive/2012/03/13/2393716.html,如需转载请自行联系原作者

相关文章
|
1月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
71 2
|
2月前
|
缓存 Java 程序员
Map - LinkedHashSet&Map源码解析
Map - LinkedHashSet&Map源码解析
76 0
|
2月前
|
算法 Java 容器
Map - HashSet & HashMap 源码解析
Map - HashSet & HashMap 源码解析
62 0
|
2月前
|
存储 Java C++
Collection-PriorityQueue源码解析
Collection-PriorityQueue源码解析
66 0
|
2月前
|
安全 Java 程序员
Collection-Stack&Queue源码解析
Collection-Stack&Queue源码解析
86 0
|
16天前
|
PyTorch Shell API
Ascend Extension for PyTorch的源码解析
本文介绍了Ascend对PyTorch代码的适配过程,包括源码下载、编译步骤及常见问题,详细解析了torch-npu编译后的文件结构和三种实现昇腾NPU算子调用的方式:通过torch的register方式、定义算子方式和API重定向映射方式。这对于开发者理解和使用Ascend平台上的PyTorch具有重要指导意义。
|
20天前
|
缓存 监控 Java
Java线程池提交任务流程底层源码与源码解析
【11月更文挑战第30天】嘿,各位技术爱好者们,今天咱们来聊聊Java线程池提交任务的底层源码与源码解析。作为一个资深的Java开发者,我相信你一定对线程池并不陌生。线程池作为并发编程中的一大利器,其重要性不言而喻。今天,我将以对话的方式,带你一步步深入线程池的奥秘,从概述到功能点,再到背景和业务点,最后到底层原理和示例,让你对线程池有一个全新的认识。
50 12
|
1月前
|
存储 安全 Linux
Golang的GMP调度模型与源码解析
【11月更文挑战第11天】GMP 调度模型是 Go 语言运行时系统的核心部分,用于高效管理和调度大量协程(goroutine)。它通过少量的操作系统线程(M)和逻辑处理器(P)来调度大量的轻量级协程(G),从而实现高性能的并发处理。GMP 模型通过本地队列和全局队列来减少锁竞争,提高调度效率。在 Go 源码中,`runtime.h` 文件定义了关键数据结构,`schedule()` 和 `findrunnable()` 函数实现了核心调度逻辑。通过深入研究 GMP 模型,可以更好地理解 Go 语言的并发机制。
|
1月前
|
消息中间件 缓存 安全
Future与FutureTask源码解析,接口阻塞问题及解决方案
【11月更文挑战第5天】在Java开发中,多线程编程是提高系统并发性能和资源利用率的重要手段。然而,多线程编程也带来了诸如线程安全、死锁、接口阻塞等一系列复杂问题。本文将深度剖析多线程优化技巧、Future与FutureTask的源码、接口阻塞问题及解决方案,并通过具体业务场景和Java代码示例进行实战演示。
53 3
|
2月前
|
存储
让星星⭐月亮告诉你,HashMap的put方法源码解析及其中两种会触发扩容的场景(足够详尽,有问题欢迎指正~)
`HashMap`的`put`方法通过调用`putVal`实现,主要涉及两个场景下的扩容操作:1. 初始化时,链表数组的初始容量设为16,阈值设为12;2. 当存储的元素个数超过阈值时,链表数组的容量和阈值均翻倍。`putVal`方法处理键值对的插入,包括链表和红黑树的转换,确保高效的数据存取。
63 5
下一篇
DataWorks