我们要想把一个系统搞清楚,首先要把它的线程模型弄明白。比如它是单线程的还是多线程的?如果它是单线程的,那逻辑就比较简单了,像mediasoup就是单进程多实例的模型;如果是多线程的,那它的线程是如何分配的?每个线程的作用是什么?我们必须把这些都要弄清楚才行,否则我们就无法将这个系统彻底搞明白。
在分析 Janus 的时候,我们也应尊循上面的原则。因此在分析Janus之前,我们先来问几个问题,Janus是多线程的模式吗?如果是多线程模式,那它一共有几个线程呢? 这些线程又分别起什么作用?
如果我们将上面的问题回答好了,我想我们基本上就将Janus的线程模型搞清楚了,搞清了它的线程模型也就撑握了Janus的系统大体脉络。
Janus是多线程模式吗?
其实这个问题非常好回答,通过查看Janus的主文件janus.c我们就能知道答案了。在janus.c中我们可以发现下面的代码:
...
GThread *watchdog = g_thread_try_new("timeout watchdog", &janus_sessions_watchdog, watchdog_loop, &error);
...
GThread *requests_thread = g_thread_try_new("sessions requests", &janus_transport_requests, NULL, &error);
...
Janus是基于Linux 的GLIB库开发出来的,因此所有对系统的调用都是使用的GLIB库的API。而g_thread_try_new
函数正中GLIB中用来创建线程的,在g_thread_try_new
的底层真正调用的是pthread
的相关API。
通这上面的分析,我们可以知道Janus是多线程的模式。
Janus一共有几个线程?
除了我们上面介绍的两个线程外,Janus还使用了线程池的概念。在Janus的初始化阶段就将线程池创建出来了。代码如下:
...
tasks = g_thread_pool_new(janus_transport_task, NULL, -1, FALSE, &error);
...
查看g_thread_pool_new
API的帮助文档,其定义如下:
GThreadPool *
g_thread_pool_new (GFunc func,
gpointer user_data,
gint max_threads,
gboolean exclusive,
GError **error);
通过这个定义我们可以知道Janus创建的线程池时并没有对线程数进制控制。也就是说它可以开出系统可以支持的最大限度的线程个数。会在高并发时出现性能问题呢?这个还要等我们后面的深入分析才能清楚,目前来说这行代码还是有风险的。
下面我们总结一下,通过对janus.c文件的分析,我们现在可以知道Janus的线程模型是由两个专用线程watchdog
、request
和一个通用任务线程池构成的。如下图所示:
了解了Janus的线程模型后,下面我们来看一下 Janus 每个线程的作用吧。
每个线程的作用
通过阅读代码,我们可以了解到这几个线程的主要作用是什么,下面我们来一一介绍一下。
首先是主线程,这个线程的主要作用就是初始化的工作。主要包括以下几方面的工作:
- 从配置文件中读配置信息,然后根据配置信息进行初始化工作
- 启动其它线程
- 动态加载plugin
WatchDog 线程,通过名子我们基本上就可以清楚它的作用了。它是监控线程,它每隔2秒做一次扫描,查看transport的session是否过期了。如果过期了,则给对应的transport发通知让transport结束处理。需要注意的是,这里的 trasnport代表的是不同协议的接入口,如RabbitMQ、MQTT、HTTP等。
Request线程,用于处理接口请求。一般将接口请求分为两大类,文本类请求和命令类请求。如果是文本类请求的,则会启动新线程(从线程池中获取)进行处理;如果是命令的类的,则可以直接处理。当然对于命令类型的Request可能处理上会比较复杂,有可能会分成多个阶段处理,而在每个不同的阶段又会生成新的Request。
最后一个就是线程池了,线程池的作用上面我已经介绍了,就是在处理Request时会从线程池中分配线程,然后执行Request任务,任务完成后再回收到线程池里。
小结
通过上面的描述我们可以看到Janus的线程模型并不复杂,它启动了两个专门的线程,一个用于处理transport的session是否过期;另一个用于处理Request请求,当收到Request请求后,它又会把请求交给新的线程做延时处理。
以上我们就将 Janus 的线程模型分析完了,读到这里我相信你已经对Janus的线程模型有了一个大体的了解了。当然你仍然会很许多疑惑,这只能对照着Janus的代码分析才能让你体会的更深刻!
谢谢!
网友评论