PHP 开发直播短视频社交系统

直播短视频陪玩 专栏收录该内容
1 篇文章 0 订阅

技术交流:
技术交流群


gihub地址: https://github.com/DOUBLE-Baller/momo

web演示地址: http://www.jinqianlive.com

直播后台演示地址: http://www.jinqianlive.com/admin

账号 :test
密码: test


直播短视频app下载 https://baoya.lanzous.com/imcL9e57tej(用手机浏览器打开下载,不要用微信直接下载)


陪玩app下载 https://baoya.lanzous.com/izTEKgg0yhi (用手机浏览器打开下载,不要用微信直接下载)


IOS 视频演示:https://pan.baidu.com/s/18KaHu-39TMQLetb0m7XD0Q 提取码:v929


文档地址:http://www.jinqianlive.com/appapi/listAllApis.php?type=expand


在这里插入图片描述
在这里插入图片描述


入门推荐书籍

技术结构

前端

  • 前端技术栈将会单独开一篇详细阐述,以下为前端页面展示截图。

在这里插入图片描述
在这里插入图片描述


后端

系统开发语言

  • PHP 视频互动系统由 WEB 系统、REDIS 服务、MYSQL 服务、视频服务、聊天服务、后台管理系统和定时监控组成,后台管理采用PHP 语言开发,所有服务提供横向扩展。
  1. WEB 系统提供页面、接口逻辑。
  2. REDIS 服务提供数据的缓存、存储动态数据。
  3. MYSQL 服务提供静态数据的存储。
  4. 视频服务提供视频直播,傍路直播,转码、存储、点播等。
  5. 聊天服务提供直播群聊,私聊,消息通知等。
  6. 定时监控:监听主播异常掉线情况、直播消息推送等。

视频服务

直播配置

RTMP服务添加一个application这个名字可以任意起,也可以起多个名字,由于是直播我就叫做它live,如果打算弄多个序列的直播就可以live_cctv。

#user  nobody;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;


events {
    worker_connections  1024;
}

rtmp {  #RTMP server
    server {    
        listen 1935;  #server port
        chunk_size 4096;  #chunk_size
        # vod server
        application vod {
            play /mnt/hgfs/dn_class/vod; #media file position
        }
        # live server 1
    application live{ #Darren live first add
        live on;
    }
        # live server 2
    application live_cctv{ #Darren live  add
        live on;
    }
    }
}
........
其他配置不需理会

在Ubuntu端用ffmpeg产生一个模拟直播源,向rtmp服务器推送

推流

ffmpeg -re -i /mnt/hgfs/dn_class/vod/35.mp4 -c copy -f flv rtmp://192.168.100.33/live/35

注意,源文件必须是H.264+AAC编码的

拉流

ffplay rtmp://192.168.100.33/live/35

点播配置

  1. 建立媒体文件夹/mnt/hgfs/dn_class/vod
    把媒体文件 35.mp4复制到/mnt/hgfs/dn_class/vod目录下。
    然后我们就可以开启一个视频点播的服务了。打开配置文件nginx.conf(路径/usr/local/nginx/conf/nginx.conf),添加RTMP的配置。
    #user  nobody;
    worker_processes  1;
    
    #error_log  logs/error.log;
    #error_log  logs/error.log  notice;
    #error_log  logs/error.log  info;
    
    #pid        logs/nginx.pid;
    
    
    events {
        worker_connections  1024;
    }
    
    rtmp {  #RTMP server
        server {    
            listen 1935;  #server port
            chunk_size 4096;  #chunk_size
            application vod {
                play /mnt/hgfs/dn_class/vod; #media file position
            }
        }
    }
    ........
    其他配置不需理会

聊天服务

特性

  • 轻量级
  • 高性能
  • 纯Golang实现
  • 支持单个、多个、单房间以及广播消息推送
  • 支持单个Key多个订阅者(可限制订阅者最大人数)
  • 心跳支持(应用心跳和tcp、keepalive)
  • 支持安全验证(未授权用户不能订阅)
  • 多协议支持(websocket,tcp)
  • 可拓扑的架构(job、logic模块可动态无限扩展)
  • 基于Kafka做异步消息推送

安装

一、安装依赖

$ yum -y install java-1.7.0-openjdk

二、安装Kafka消息队列服务

kafka在官网已经描述的非常详细,在这里就不过多说明,安装、启动请查看这里.

三、搭建golang环境

1.下载源码(根据自己的系统下载对应的安装包)

$ cd /data/programfiles
$ wget -c --no-check-certificate https://storage.googleapis.com/golang/go1.5.2.linux-amd64.tar.gz
$ tar -xvf go1.5.2.linux-amd64.tar.gz -C /usr/local

2.配置GO环境变量
(这里我加在/etc/profile.d/golang.sh)

$ vi /etc/profile.d/golang.sh
# 将以下环境变量添加到profile最后面
export GOROOT=/usr/local/go
export PATH=$PATH:$GOROOT/bin
export GOPATH=/data/apps/go
$ source /etc/profile

四、部署im

1.下载goim及依赖包

$ yum install hg
$ go get -u github.com/Terry-Mao/goim
$ mv $GOPATH/src/github.com/Terry-Mao/goim $GOPATH/src/goim
$ cd $GOPATH/src/goim
$ go get ./...

2.安装router、logic、comet、job模块(配置文件请依据实际机器环境配置)

$ cd $GOPATH/src/goim/router
$ go install
$ cp router-example.conf $GOPATH/bin/router.conf
$ cp router-log.xml $GOPATH/bin/
$ cd ../logic/
$ go install
$ cp logic-example.conf $GOPATH/bin/logic.conf
$ cp logic-log.xml $GOPATH/bin/
$ cd ../comet/
$ go install
$ cp comet-example.conf $GOPATH/bin/comet.conf
$ cp comet-log.xml $GOPATH/bin/
$ cd ../logic/job/
$ go install
$ cp job-example.conf $GOPATH/bin/job.conf
$ cp job-log.xml $GOPATH/bin/

到此所有的环境都搭建完成!

五、启动im

$ cd /$GOPATH/bin
$ nohup $GOPATH/bin/router -c $GOPATH/bin/router.conf 2>&1 > /data/logs/goim/panic-router.log &
$ nohup $GOPATH/bin/logic -c $GOPATH/bin/logic.conf 2>&1 > /data/logs/goim/panic-logic.log &
$ nohup $GOPATH/bin/comet -c $GOPATH/bin/comet.conf 2>&1 > /data/logs/goim/panic-comet.log &
$ nohup $GOPATH/bin/job -c $GOPATH/bin/job.conf 2>&1 > /data/logs/goim/panic-job.log &

如果启动失败,默认配置可通过查看panic-xxx.log日志文件来排查各个模块问题.

六、测试

Arch

在这里插入图片描述

Benchmark Server

CPUMemoryOSInstance
Intel® Xeon® CPU E5-2630 v2 @ 2.60GHzDDR3 32GBDebian GNU/Linux 81

Benchmark Case

  • Online: 1,000,000
  • Duration: 15min
  • Push Speed: 40/s (broadcast room)
  • Push Message: {“test”:1}
  • Received calc mode: 1s per times, total 30 times

Benchmark Resource

  • CPU: 2000%~2300%
  • Memory: 14GB
  • GC Pause: 504ms
  • Network: Incoming(450MBit/s), Outgoing(4.39GBit/s)

Benchmark Result

  • Received: 35,900,000/s

推送协议可查看push http协议文档

配置

TODO

例子

Websocket: Websocket Client Demo

Android: Android

iOS: iOS

文档

push http协议文档推送接口

集群

comet

comet 属于接入层,非常容易扩展,直接开启多个comet节点,修改配置文件中的base节点下的server.id修改成不同值(注意一定要保证不同的comet进程值唯一),前端接入可以使用LVS 或者 DNS来转发

logic

logic 属于无状态的逻辑层,可以随意增加节点,使用nginx upstream来扩展http接口,内部rpc部分,可以使用LVS四层转发

kafka

kafka 可以使用多broker,或者多partition来扩展队列

router

router 属于有状态节点,logic可以使用一致性hash配置节点,增加多个router节点(目前还不支持动态扩容),提前预估好在线和压力情况

job

job 根据kafka的partition来扩展多job工作方式,具体可以参考下kafka的partition负载


PHP 为什么 “慢” ???

Laravel + Swoole 提速 30倍

  • 复用容器
  • 启用协程
  • 数据库连接池

  • 复用容器
    熟悉 Laravel 的朋友都知道 IoC 容器是整个框架的核心,几乎所有 Laravel 提供的服务都被注册在 IoC 容器中。每当容器启动时,Laravel 就会将大部分服务注册到容器中来,有些服务还会去加载文件,比如配置、路由等,可以说启动容器是比较 “耗时” 的。我们再次观察上面的脚本,可以看到 request 回调的第一行就是创建 IoC 容器($app),这也意味着每次在处理请求时都会创建一次容器,这样不仅重复执行了许多代码,还造成不小的 IO 开销,所以上述脚本显然不是最优的做法。那我们试试只创建一个容器,再让所有的请求都复用这个容器。我们可以在 worker 进程启动时(也就是 workerStart 回调中)创建并启动容器,这样在 request 回调中就能复用了。现在将 swoole.php 如下:
<?php

require __DIR__.'/vendor/autoload.php';

use HuangYi\Shadowfax\Http\Request;
use HuangYi\Shadowfax\Http\Response;
use Illuminate\Contracts\Http\Kernel;
use Illuminate\Http\Request as IlluminateRequest;
use Swoole\Http\Server;

$server = new Server('127.0.0.1', 9501);

$server->set([
    'worker_num' => 1,
    'enable_coroutine' => false,
]);

$app = null;

$server->on('workerStart', function () use (&$app) {
    $app = require __DIR__.'/bootstrap/app.php';

    $app->instance('request', IlluminateRequest::create('http://localhost'));

    $app->make(Kernel::class)->bootstrap();
});

$server->on('request', function ($request, $response) use (&$app) {
    $kernel = $app->make(Kernel::class);

    $illuminateResponse = $kernel->handle(
        $illuminateRequest = Request::make($request)->toIlluminate()
    );

    Response::make($illuminateResponse)->send($response);

    $kernel->terminate($illuminateRequest, $illuminateResponse);
});

$server->start();
  • 启用协程
    协程是 Swoole 的最强武器,也是实现高并发的精髓所在。那么在 Laravel 中使用协程会有问题吗?首先启动 Swoole 的协程特性,将 enable_coroutine 设置为 true 即可,然后在 routes/web.php 里面添加两个路由:
<?php

use Swoole\Coroutine;

app()->singleton('counter', function () {
    $counter = new stdClass;
    $counter->number = 0;

    return $counter;
});

Route::get('one', function () {
    app('counter')->number = 1;

    Coroutine::sleep(5);

    echo sprintf("one: %d\n", app('counter')->number);
});

Route::get('two', function () {
    app('counter')->number = 2;

    Coroutine::sleep(5);

    echo sprintf("two: %d\n", app('counter')->number);
});

上述代码首先在容器里面注册了一个 counter 单例,路由 one 将 counter 单例的 number 属性设置为 1,然后模拟协程被挂起 5 秒,恢复后打印出 number 属性的值。路由 two 也类似,只是将 number 属性设置为了 2。启动服务器后,我们先访问 one,然后立马访问 two(间隔不要超过 5 秒)。我们可以观察到 Console 输出的信息为:

one: 2
two: 2
  • 数据库连接池
    注意: 在协程环境下使用数据库如果不配合连接池,就会造成连接异常。当然,使用 Swoole 的 Channel 来创建连接池非常简单,但是如果直接在业务代码中使用连接池,程序员需要自行控制何时取何时回收,而且还不能使用 Laravel 的 Model 了,这点我是绝对不能接受的。还有一点,由于在业务代码中使用了 Swoole 的接口,这意味着你的程序必须运行在 Swoole 之上,再也无法切回 PHP-FPM 了。Shadowfax 做到了无感知的使用连接池,开发者依然像平时那样用 Model 来查询或者更新数据,唯一需要做的就是将程序中使用到的数据库连接名配置到 db_pools 当中即可。Shadowfax 是如何做到的呢?我们只需要搞清楚一点就能明白原理了,Laravel 中的数据库连接都是通过 Illuminate\Database\DatabaseManager::connection() 方法来获取的,我们可以继承这个类并改造 connection() 方法,如果取的是 db_pools 中配置的连接,那么就从对应的连接池中获取。最后使用这个改造后的类注覆盖原来的 db 服务即可。具体的实现就请阅读源码 。
<?php

namespace HuangYi\Shadowfax\Laravel;

use Illuminate\Database\Connection;
use Illuminate\Database\Connectors\ConnectionFactory;
use Illuminate\Database\DatabaseManager as LaravelDatabaseManager;

class DatabaseManager extends LaravelDatabaseManager
{
    use HasConnectionPools;

    /**
     * The callback to be executed to reconnect to a database in pool.
     *
     * @var callable
     */
    protected $poolReconnector;

    /**
     * Create a new DatabaseManager instance.
     *
     * @param  \Illuminate\Contracts\Foundation\Application  $app
     * @param  \Illuminate\Database\Connectors\ConnectionFactory  $factory
     * @param  array  $poolsConfig
     * @return void
     */
    public function __construct($app, ConnectionFactory $factory, array $poolsConfig = [])
    {
        parent::__construct($app, $factory);

        $this->poolsConfig = $poolsConfig;

        $this->poolReconnector = function ($connection) {
            $this->poolReconnect($connection);
        };
    }

    /**
     * Get a database connection instance.
     *
     * @param  string|null  $name
     * @return \Illuminate\Database\ConnectionInterface
     */
    public function connection($name = null)
    {
        $name = $name ?: $this->getDefaultConnection();

        if (! $this->isPoolConnection($name)) {
            return parent::connection($name);
        }

        if ($connection = $this->getConnectionFromContext($name)) {
            return $connection;
        }

        return $this->getConnectionFromPool($name);
    }

    /**
     * Resolve the connection.
     *
     * @param  string  $name
     * @return \Illuminate\Database\Connection
     */
    protected function resolveConnection($name)
    {
        [$database, $type] = $this->parseConnectionName($name);

        $connection = $this->configure($this->makeConnection($database), $type);

        $connection->setReconnector($this->poolReconnector);

        return $connection;
    }

    /**
     * Get the connection key in coroutine context.
     *
     * @param  string  $name
     * @return string
     */
    protected function getConnectionKeyInContext($name)
    {
        return 'db.connections.'.$name;
    }

    /**
     * Reconnect to the given database.
     *
     * @param  string|null  $name
     * @return \Illuminate\Database\Connection
     */
    public function reconnect($name = null)
    {
        $name = $name ?: $this->getDefaultConnection();

        if (! $this->isPoolConnection($name)) {
            return parent::reconnect($name);
        }
    }

    /**
     * Reconnect the connection in pool.
     *
     * @param  \Illuminate\Database\Connection  $connection
     * @return \Illuminate\Database\Connection
     */
    public function poolReconnect(Connection $connection)
    {
        $connection->disconnect();

        $fresh = $this->makeConnection($connection->getName());

        return $connection
            ->setPdo($fresh->getRawPdo())
            ->setReadPdo($fresh->getRawReadPdo());
    }
}

swoole扩展安装

pecl install swoole

swoole框架

composer install

webroot目录配置到Nginx/Apache的虚拟主机目录中,使webroot/可访问。

详细部署说明

1. 安装composer(php依赖包工具)

curl -sS https://getcomposer.org/installer | php
mv composer.phar /usr/local/bin/composer

注意:如果未将php解释器程序设置为环境变量PATH中,需要设置。因为composer文件第一行为#!/usr/bin/env php,并不能修改。
更加详细的对composer说明:http://blog.csdn.net/zzulp/article/details/18981029

2. composer install

切换到PHPWeb项目目录,执行指令composer install,如很慢则

composer install --prefer-dist

3. Ningx配置HTTPS

  • Apache请参照Nginx配置,自行修改实现
  • 这里使用了www.xxx.com作为域名,需要配置host或者改成你的域名
server {
    listen       80;
    server_name  www.xxx.com;
    index index.html index.php;
    
    location / {
        root   /path/to/web/webroot;

        proxy_set_header X-Real-IP $remote_addr;
        if (!-e $request_filename) {
            rewrite ^/(.*)$ /index.php;
        }
    }
    
    location ~ .*\.(php|php5)?$ {
	    fastcgi_pass  127.0.0.1:9000;
	    fastcgi_index index.php;
	    include fastcgi.conf;
    }
}

**注意:https下必须采取wss So-有两种方案 1.采用nginx 反向代理4431端口 swoole 的端口和4431进行通讯。2.swoole 确认是否启用了openssl,是否在编译时加入了--enable-openssl的支持,然后在set 证书路径即可。两种方案选择其一就好,不过第一种方案有个潜在神坑就是你通过反向代理拿不到真实的IP地址了,这点值得注意,Nginx有办法拿到真实的ip,不懂可以私聊我,光wss的坑太多了就不一一说了。**


何为 laravel-admin

是一个可以快速帮你构建后台管理的工具,它提供的页面组件和表单元素等功能,能帮助你使用很少的代码就实现功能完善的后台管理功能

特性

  • 内置用户和权限系统
  • model-grid支持快速构建数据表格
  • model-form支持快速构建数据表单
  • model-tree支持快速构建树状数据
  • 内置40+种form元素组件、以及支持扩展组件
  • 支持Laravel的多种模型关系
  • mysql、mongodb、pgsql等多数据库支持
  • 支持引入第三方前端库
  • 数据库和artisan命令行工具的web实现
  • 支持自定义图表
  • 多种常用web组件
  • 支持本地和oss文件上传

目录结构

app/Admin
├── Controllers
│   ├── ExampleController.php
│   └── HomeController.php
├── bootstrap.php
└── routes.php

克隆项目

git clone https://github.com/DOUBLE-Baller/momo.git

进入项目

cd momo

安装功能包

composer install 

复制.env文件

cp .env.example .env

生成密钥

php artisan key:generate

运行迁移

# 注意修改.env文件的数据库信息
php artisan migrate

建立文件链接(如果报错请百度解决,都是小问题)

php artisan storage:link

初始化数据库

php artisan db:seed-sql 
# 输入yes

后台地址:http://xxxx/admin 账户:admin,密码:admin

创建后台控制器

# 以创建用户管理为例
php artisan admin:controller UserController

注意:控制器里面修改相应模型,变量,视图即可,视图请参考auth里面的代码

使用说明

搜索和导出功能需自己完善

  • 路由文件:app/Admin/routes.php
  • 配置文件:config/admin.php
  • 语言文件:resources/lang/zh-CN/admin.php
  • 后台控制器路径:app/Admin/Controllers
  • 后台视图路径:app/Admin/Views
  • 视图请参考auth里面的代码
  • 视图页面代码请参考adminlte2.4文件
  • 资源文件:public/plugins
  • 获取登录用户Admin::user()
  • 获取登录用户IDAdmin::id()
  • 判断登录用户是否是某个角色(判断角色标识)Admin::isAdmin('slug'['slug','slug'])
  • 视图获取登录用户admin('user')
  • 视图获取登录用户IDadmin('id')
  • 视图判断登录用户是否是某个角色(判断角色标识)admin('isAdmin','slug'['slug','slug'])

问题反馈

在使用中有任何问题,欢迎反馈给我们,可以用以下联系方式跟我们交流

整套直播教学视频 进群后@群主索取
在这里插入图片描述

  • 3
    点赞
  • 3
    评论
  • 23
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值