全库级 stream复制:maintain_global方法

本文介绍如何在RHEL6.3环境下使用Oracle11g的Stream技术进行全库级别的数据复制。具体步骤包括配置管理用户、数据库链接、归档模式等,并详细解释了如何通过maintain_global方法实现单向下游捕获(downstreamcapture)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 rhel6.3,oracle 11203,全库级 stream复制:maintain_global方法,downstream capture

1.     准备工作

使用maintain_global来配置一个单向的downstream capture的全库复制,目标库已经在。

 

源端(source database)

目标端(destination database)

 

Hostname

Rhel63db

Tan63rep

 

Db_name

Strmtan

Strmdest

 

Gblobal_name

Strmtan

Strmdest

 

Instance_name

Strmtan

Strmdest

 

Db_unique_name

Strmtan

Strmdest

 

 

1.1. 在所有的database上部署管理用户

应当创建一个新用户和表空间,不应用sys,system用户,system系统表空间。

表空间

SQL> create tablespace streamtbs datafile

    '/data01/apps/oracle/oradata/strmtan/streamtbs01.dbf' size 50m

    autoextend on maxsize unlimited segment space management auto;

将logminer的数据字典从system分离,防止撑满system表空间

SQL> execute dbms_logmnr_d.set_tablespace('streamtbs');

用户

SQL> create user strmadmin identified by strmadmin default tablespace streamtbs;

相关权限

SQL> grant dba to strmadmin;

1.   The DBA role is required for a user to create or altercapture processes, synchronous captures, and apply processes. When the user does not need to perform these tasks,DBA role can be revoked from the user.

GRANT_ADMIN_PRIVILEGE一些特有权限

BEGIN

  DBMS_STREAMS_AUTH.GRANT_ADMIN_PRIVILEGE(

    grantee          => 'strmadmin',   

    grant_privileges => TRUE);

END;

/

1.2. 配置网络连接和database links

网络配置已经做好,而且简单,不再做说明,只做database link部分

 

每个dblink必须用 streams administrator’s chema (就是前面创建的strmadmin)

 

源端(source database):

SQL> conn strmadmin/strmadmin

create database link strmdest connect to strmadmin

identified by strmadmin using 'strmdest';

 

Database link created.

目标端(destination database)

SQL> conn strmadmin/strmadmin

create database link strmtan connect to strmadmin

identified by strmadmin using 'strmtan';

1.3. 保证两端archivelog模式

检查

SQL> conn /as sysdba

Connected.

SQL> archive log list

Database log mode              Archive Mode

Automatic archival             Enabled

Archive destination            /u01/strmtan/arch1

Oldest online log sequence     1

Next log sequence to archive   2

1.4. 检查密码文件是否存在

源端和目标端都需要密码文件,目标端需要从源端拷贝。有了密码文件以及相应参数(remote_login_passwordfile)正确,就可以远程以sys用户登陆,此过程没有完成会影响日志文件的传输。

1.5. 设置初始化参数

所有库都需要改的

alter system set aq_tm_processes=2 scope=both;

alter system set global_names=true scope=both;

alter system set undo_retention=3600 scope=both;

alter system set job_queue_processes=10 scope=both;

alter system set parallel_max_servers=20 scope=both;

alter system set nls_date_format='YYYY-MM-DD HH24:MI:SS' scope=spfile;

alter system set streams_pool_size=100M scope=spfile;

alter system set shared_pool_size=100m scope=both;

alter system set open_links=4 scope=spfile;

alter system set LOG_ARCHIVE_DEST_STATE_2=enable scope=both;

alter system set timed_statistics= TRUE scope=spfile;

alter system set LOG_ARCHIVE_CONFIG='DG_CONFIG=(strmtan,strmdest)'  scope=both;

log_archive_dest_n

源端:

--real time log方式

Alter system set LOG_ARCHIVE_DEST_2='SERVICE=STRMDEST LGWR ASYNC OPTIONAL NOREGISTER VALID_FOR=(ONLINE_LOGFILE,PRIMARY_ROLE) DB_UNIQUE_NAME=STRMDEST'  scope=both;

 

目标端

alter system set log_archive_dest_1='LOCATION=/u01/strmdest/arch1/ MANDATORY VALID_FOR=(ONLINE_LOGFILE,PRIMARY_ROLE)' scope=both;

 

 

Alter system set LOG_ARCHIVE_DEST_2='LOCATION=/u01/strmdest/arch2 MANDATORY VALID_FOR=(STANDBY_LOGFILE,PRIMARY_ROLE)' scope=both;

 

1.6. 启用追加日志supplemental log

可以在Database级或table级启用supplemental log 。在table级别,确认schema下所有table都有合理的主键(Primary key),则不再需要启用追加日志

 

源端

 

database级

SQL> alter database add supplemental log data ;

 

1.7. 增加standby redo log

源端:

SQL> select bytes from V$log;

52428800

察看redo log大小,设置的standby redo log 大小不能小于redo log 大小。

 

SQL> SELECT COUNT(GROUP#) FROM V$LOG;

            3

确定downstream database的log file groups的id,至少为source database的n+1。downstream日志组的数量可以是一个或多个。

目标端:

SQL>ALTER DATABASE ADD STANDBY LOGFILE GROUP 4

   ('/data01/apps/oracle/oradata/strmdest/slog4.rdo',

 '/data01/apps/oracle/oradata/strmdest/slog4b.rdo') SIZE 500M;

 

SQL> SELECT GROUP#, THREAD#, SEQUENCE#, ARCHIVED, STATUS

   FROM V$STANDBY_LOG;

    GROUP#    THREAD#  SEQUENCE# ARC STATUS

---------- ---------- ---------- --- ----------

         4          0          0 YES UNASSIGNED

1.8. 测试:

源端

alter system archive log current;

然后在目标端dest_2找相应的log文件,表明以上配置成功。

 

2.     Stream配置
1.1. 配置directory

源端

conn strmadmin/strmadmin

create directory dir_source as '/u01/admin';

目标端:

conn strmadmin/strmadmin

create directory dir_dest as '/u01/admin';

 

1.2. 执行maintain_global

conn strmadmin/strmadmin@strmdest

begin

DBMS_STREAMS_ADM.MAINTAIN_GLOBAL(

source_directory_object => 'dir_source ',

destination_directory_object => 'dir_dest ',

source_database => 'strmtan',

destination_database => 'strmdest',

perform_actions => true,

dump_file_name => 'streams_rep.dmp',

bi_directional => false,

include_ddl => true,

instantiation => DBMS_STREAMS_ADM.INSTANTIATION_FULL);

end;

/

 

等了将30分钟后出结果

PL/SQL procedure successfully completed.

3.测试

SQL> create table test1(id  number(10));

SQL> insert into test1 values(111);

SQL> commit;

Conn /as sysdba

SQL> alter system archive log current;

 

在源库的scott用户上执行了以上操作后,等待5分钟左右后,在目标库上找到了结果,说明目标库应用源库的DDL操作和DML操作。

 

以下是一个简单的使用 C++ 和 FFmpeg 实现的 RTSP 服务器示例: ```cpp #include <iostream> #include <string> #include <thread> #include <chrono> #include <mutex> #include <condition_variable> extern "C" { #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libavutil/avutil.h> #include <libswscale/swscale.h> } class RtspServer { public: RtspServer(const std::string& url, int width, int height, int fps) : m_url(url), m_width(width), m_height(height), m_fps(fps) { av_register_all(); avformat_network_init(); m_fmt = av_guess_format("rtsp", m_url.c_str(), NULL); if (!m_fmt) { std::cout << "Failed to guess format for " << m_url << std::endl; return; } m_fmt_ctx = avformat_alloc_context(); m_fmt_ctx->oformat = m_fmt; snprintf(m_fmt_ctx->filename, sizeof(m_fmt_ctx->filename), "%s", m_url.c_str()); m_video_st = avformat_new_stream(m_fmt_ctx, NULL); if (!m_video_st) { std::cout << "Failed to create video stream" << std::endl; return; } m_codec = avcodec_find_encoder(AV_CODEC_ID_H264); if (!m_codec) { std::cout << "Failed to find H.264 codec" << std::endl; return; } m_codec_ctx = avcodec_alloc_context3(m_codec); m_codec_ctx->codec_id = AV_CODEC_ID_H264; m_codec_ctx->codec_type = AVMEDIA_TYPE_VIDEO; m_codec_ctx->width = m_width; m_codec_ctx->height = m_height; m_codec_ctx->time_base.num = 1; m_codec_ctx->time_base.den = m_fps; m_codec_ctx->gop_size = m_fps; m_codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P; if (m_fmt_ctx->oformat->flags & AVFMT_GLOBALHEADER) { m_codec_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; } int ret = avcodec_open2(m_codec_ctx, m_codec, NULL); if (ret < 0) { std::cout << "Failed to open codec" << std::endl; return; } avcodec_parameters_from_context(m_video_st->codecpar, m_codec_ctx); av_dump_format(m_fmt_ctx, 0, m_url.c_str(), 1); ret = avio_open(&m_fmt_ctx->pb, m_url.c_str(), AVIO_FLAG_WRITE); if (ret < 0) { std::cout << "Failed to open output URL" << std::endl; return; } ret = avformat_write_header(m_fmt_ctx, NULL); if (ret < 0) { std::cout << "Failed to write header" << std::endl; return; } m_frame = av_frame_alloc(); m_frame->width = m_width; m_frame->height = m_height; m_frame->format = AV_PIX_FMT_YUV420P; av_frame_get_buffer(m_frame, 32); m_sws_ctx = sws_getContext(m_width, m_height, AV_PIX_FMT_BGR24, m_width, m_height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL); if (!m_sws_ctx) { std::cout << "Failed to create SWS context" << std::endl; return; } } ~RtspServer() { if (m_sws_ctx) { sws_freeContext(m_sws_ctx); } if (m_frame) { av_frame_free(&m_frame); } if (m_fmt_ctx) { av_write_trailer(m_fmt_ctx); if (m_fmt_ctx->pb) { avio_closep(&m_fmt_ctx->pb); } avformat_free_context(m_fmt_ctx); } avcodec_free_context(&m_codec_ctx); } void run() { std::thread thread([this]() { while (!m_stop) { auto start_time = std::chrono::high_resolution_clock::now(); // Generate synthetic video frames here cv::Mat image(m_height, m_width, CV_8UC3, cv::Scalar(0, 255, 0)); cv::circle(image, cv::Point(m_width/2, m_height/2), m_height/4, cv::Scalar(0, 0, 255), -1); cv::cvtColor(image, m_bgr_frame, cv::COLOR_RGB2BGR); // Convert to YUV420P format uint8_t* in_data[1] = { m_bgr_frame.data }; int in_linesize[1] = { 3 * m_width }; uint8_t* out_data[3] = { m_frame->data[0], m_frame->data[1], m_frame->data[2] }; int out_linesize[3] = { m_width, m_width / 2, m_width / 2 }; sws_scale(m_sws_ctx, in_data, in_linesize, 0, m_height, out_data, out_linesize); // Encode and write to output AVPacket pkt = { 0 }; av_init_packet(&pkt); int ret = avcodec_send_frame(m_codec_ctx, m_frame); if (ret < 0) { std::cout << "Failed to send frame" << std::endl; continue; } while (ret >= 0) { ret = avcodec_receive_packet(m_codec_ctx, &pkt); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { break; } if (ret < 0) { std::cout << "Failed to receive packet" << std::endl; continue; } pkt.stream_index = m_video_st->index; av_packet_rescale_ts(&pkt, m_codec_ctx->time_base, m_video_st->time_base); ret = av_interleaved_write_frame(m_fmt_ctx, &pkt); if (ret < 0) { std::cout << "Failed to write frame" << std::endl; continue; } av_packet_unref(&pkt); } // Sleep to maintain frame rate auto end_time = std::chrono::high_resolution_clock::now(); auto elapsed_time = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time); if (elapsed_time < std::chrono::milliseconds(1000 / m_fps)) { std::this_thread::sleep_for(std::chrono::milliseconds(1000 / m_fps) - elapsed_time); } } }); thread.detach(); } void stop() { m_stop = true; } private: std::string m_url; int m_width; int m_height; int m_fps; AVFormatContext* m_fmt_ctx = NULL; AVFormatContext* m_fmt = NULL; AVCodec* m_codec = NULL; AVCodecContext* m_codec_ctx = NULL; AVStream* m_video_st = NULL; AVFrame* m_frame = NULL; SwsContext* m_sws_ctx = NULL; cv::Mat m_bgr_frame; bool m_stop = false; }; int main(int argc, char* argv[]) { std::string url = "rtsp://localhost:8554/live"; int width = 640; int height = 480; int fps = 30; RtspServer server(url, width, height, fps); server.run(); std::this_thread::sleep_for(std::chrono::seconds(30)); server.stop(); return 0; } ``` 该示例使用 OpenCV 生成合成视频帧,并使用 FFmpeg 编码为 H.264 格式,然后将其写入 RTSP 输出。请注意,该示例仅用于演示目的,生成的视频不包含任何实际内容。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值