Swoole一键操作基于阿里云的RDS数据库迁移+OSS文件搬迁
传统的数据库搬迁思路是把数据库表的结构及数据都查询出来,然后通过循环进行数据结构重组拼接。然后导出!数据量少的话,这样当然是没毛病。当数据量太大的时候,服务器的内存开销就吃不住了,很容易炸掉,导致服务器瘫掉。当然我之前也这么干的 ,所以也一直想办法解决这个问题 ,当你体会到大数据搬迁的那酸爽、提心吊胆你就明白了
一天我看到一条sql
SELECT COUNT( * ) as cnt FROM information_schema.TABLES WHERE TABLE_SCHEMA = 旧数据库名
CREATE TABLE IF NOT EXISTS 新数据库名.表名 LIKE 旧数据库名.表名
INSERT 新数据库名.表名 SELECT * FROM 旧数据库名.表名
相信看到这几条sql 就应该有思路了,没错就是这三条sql!
废话不说了 上代码
<?php
namespace action\swoole;
/**
* 换域名
*/
class changesiteAction extends \Action{
private $bucket = 'oss';
private $oldPrefix = '';
private $newPrefix = '';
private $maxkeys = 1000;
private $initDB = array('aaa',bbb',ccc','ccc'); //多分支数据库
private $upgrading = array(
'tag' => 'copying',
'room' => '1');
private $config = array(
'demo_action_admin_certificateconfig',
'demo_action_admin_dealerentranceconfig',
'demo_action_cash_config',
'demo_action_customer_config',
'demo_action_dealer_config',
'demo_action_delivery_config',
'demo_action_itemcomm_config',
'demo_action_poster_config',
'demo_action_seckill_config',
'demo_action_shop_config',
'demo_action_user_config',
'demo_action_admin_skinconfig',
'demo_action_wechat_config',
'demo_action_xiaoi_config',
'demo_action_yunpay_config',
'demo_model_item_config',
'demo_sysapi_ultraconfig',
'demo_sysapi_payconfig'
);
//重新连接
public function reload(){
if($this->linker->server->reload()) $message = array('msgcode'=>'RELOAD');
else $message = array('msgcode'=>'FAILURE');
PUSH($this->linker,$message);
}
//心跳连接
public function heartbeat() {
$res = $this->linker->messaging;
$roomid = $res['roomid'];
PUSH($this->linker,array('errcode'=>'heartbeat'),'adventure_'.$roomid);
return false;
}
public function init(){
// 此时已经可以进行通信!
PUSH($this->linker,$this->upgrading);
return $this->upgrading;
}
//第一步
public function copyStart(){
$arg = $this->linker->messaging;
if(empty($arg['newsite'])) return PUSH($this->linker,array('errcode'=>'ERR_POST_NEWSITE','errmsg'=>'新域名为空'));
if(empty($arg['oldsite'])) return PUSH($this->linker,array('errcode'=>'ERR_POST_OLDSITE','errmsg'=>'旧域名为空'));
$newsite=strtolower(trim($arg['newsite']));
$oldsite=strtolower(trim($arg['oldsite']));
$m = $this->m(DBMATRIX);
//检测旧域名是否存在
$site = $m->sel()->from('customer')->where(array("domain = ",$oldsite))->exe();
if(empty($site)){
PUSH($this->linker,array('errcode'=>'ERR_EXIST_DOMAIN','errmsg'=>'旧域名不存在'));
return false;
}
// 检查新域名是否被使用
$mysql = "select id from demo_customer where domain = '{$newsite}'";
$myres = $m->exe(false,$mysql);
if(!empty($myres)){
PUSH($this->linker,array('errcode'=>'DOMAIN_HAS_USE','errmsg'=>'新域名已使用过'));
return false;
}
//查询数据库表的数量
$oldDB = preg_replace("/[\W]/", "_", $oldsite);
$sql = "SELECT COUNT( * ) as cnt FROM information_schema.TABLES WHERE TABLE_SCHEMA = '{$oldDB}'";
$tables_num = $this->m($this->initDB[$site['branch']])->exe(false,$sql)['cnt'];
//添加域名修改记录表
$mysql="select * from demo_changesite_log where newsite='{$newsite}' and oldsite = '{$oldsite}'";
$logres=$this->m(DBMATRIX)->exe(false,$mysql);
if(empty($logres)){
$data['sql_sum'] = $tables_num;
$data['siteid']=$site['id'];
$data['newsite']=$newsite;
$data['oldsite']=$oldsite;
$data['step'] = 1;
//$data['admid'] = $_SESSION['admid'];
$res=$this->m(DBMATRIX)->ins('changesite_log')->values($data)->exe();
if(empty($res)){
PUSH($this->linker,array('errcode'=>'ERR_INS_LOG','errmsg'=>'修改记录添加失败'));
return false;
}
return PUSH($this->linker,array('errcode'=>'FINISHREADY','id'=>$res,'numsql'=>$tables_num,'step'=>1));
}
return PUSH($this->linker,array('errcode'=>'FINISHREADY','id'=>$logres['id'],'numsql'=>$tables_num,'step'=>$logres['step']));
}
//第二步
public function copyData(){
$arg = $this->linker->messaging;
if(empty($arg['id'])) return PUSH($this->linker,array('errcode'=>'ERR_POST_ID','errmsg'=>'ID为空'));
$log = $this->m(DBMATRIX)->sel('oldsite,newsite')->from('changesite_log')->where(array('id =',$arg['id']))->exe();dump($log);
if(empty($log)) return PUSH($this->linker,array('errcode'=>'ERR_LOG','errmsg'=>'记录不存在','id'=>$arg['id']));
$newsite=strtolower(trim($log['newsite']));
$oldsite=strtolower(trim($log['oldsite']));
$oldDB = preg_replace("/[\W]/", "_", $oldsite);
$newDB = preg_replace("/[\W]/", "_", $newsite);
$site=$this->m(DBMATRIX)->sel('id,branch')->from('customer')->where(array('domain=',$oldsite))->exe();dump($site);
//切换数据库
$sql='use `'.$newDB.'`';
$res=$this->m($this->initDB[$site['branch']])->exe(false,$sql);
if(!$res){
//创建新数据库
$sql='create database `'.$newDB.'`';
$this->m($this->initDB[$site['branch']])->exe(false,$sql);
$sql='use `'.$newDB.'`';
$res = $this->m($this->initDB[$site['branch']])->exe(false,$sql);
if(!empty($res)) return PUSH($this->linker,array('errcode'=>'ERR_DATABASW','errmsg'=>'数据库创建失败'));
}
/**
* 这里直接进行表结构及数据的复制,直接省去由于害怕数据丢失的备份
* CREATE TABLE admin_jingzhunfenxiao_com.admin2 LIKE 3n4w_jingzhunfenxiao_com.demo_admin; 复制表结构
* INSERT admin_jingzhunfenxiao_com.admin2 SELECT * FROM 3n4w_jingzhunfenxiao_com.demo_admin; 复制表数据
* array(286) {
[0] => array(1) {
["Tables_in_zzz_zzz_com"] => string(15) "demo_agent_item"
}
[1] => array(1) {
["Tables_in_zzz_zzz_com"] => string(17) "demo_agent_record"
}
[2] => array(1) {
["Tables_in_zzz_zzz_com"] => string(15) "demo_agent_spec"
}
}
**/
$sql = "show tables";
$tables = $this->m($oldsite)->exe(true,$sql);
$numsql = 0;$errsql = '';
if(!empty($tables)){
$m = $this->m($oldsite);
foreach ($tables as $k => $va) {
$numsql = $k;
$tablename = $va['Tables_in_'.$oldDB];
$ssql = "show tables {$tablename}";
$tab = $m->exe(false,$ssql);
if(empty($tab)){
$tsql = "CREATE TABLE IF NOT EXISTS {$newDB}.{$tablename} LIKE {$oldDB}.{$tablename}";
$tres = $m->exe(false,$tsql);
if(empty($tres)){
$errsql = $k.'-1';break;
}
$dsql = "INSERT {$newDB}.{$tablename} SELECT * FROM {$oldDB}.{$tablename}";
$dres = $m->exe(false,$dsql);
}
PUSH($this->linker,array('errcode'=>'SUCCESS_CREATE','num'=>$numsql+1));
}
//有错误导致创建没有继续执行,记录错误位置
if(!empty($errsql)){
$mysql="update demo_changesite_log set step=2 , sqlid={$errsql} where id={$arg['id']}";
$myres=$this->m(DBMATRIX)->exe(false,$mysql);echo $mysql;die;
return PUSH($this->linker,array('errcode'=>'ERR_CREATE','errmsg'=>'数据断开连接'));
}
}
$mysql="update demo_changesite_log set step=2 , sqlid={$numsql} where id={$arg['id']}";
$myres=$this->m(DBMATRIX)->exe(false,$mysql);
return PUSH($this->linker,array('errcode'=>'FINISHCOPYDATA','errmsg'=>'复制成功'));
}
//第三步 复制oss文件
// SOCKET 模式搬迁
public function startSocketCopy(){
$arg = $this->linker->messaging;
if(empty($arg['id'])) return PUSH($this->linker,array('errcode'=>'ERR_POST_ID','errmsg'=>'ID为空'));
$log = $this->m(DBMATRIX)->sel('oldsite,newsite')->from('changesite_log')->where(array('id =',$arg['id']))->exe();
if(empty($log)) return PUSH($this->linker,array('errcode'=>'ERR_LOG','errmsg'=>'记录不存在'));
$newsite=strtolower(trim($log['newsite']));
$oldsite=strtolower(trim($log['oldsite']));
$this->oldPrefix = $oldsite.'/';
$this->newPrefix = $newsite.'/';
$this->copyInSocket($this->fullTheList($this->oldPrefix));
$mysql="update demo_changesite_log set step=3 where id={$arg['id']}";
$myres=$this->m(DBMATRIX)->exe(false,$mysql);
return PUSH($this->linker,array('errcode'=>'FINISHCOPYOSS','errmsg'=>'OSS文件搬迁完成'));
}
//第四步 修改总站配置及删除旧库
public function alterConfig(){
$arg = $this->linker->messaging;
if(empty($arg['id'])) return PUSH($this->linker,array('errcode'=>'ERR_POST_ID','errmsg'=>'ID为空'));
$log = $this->m(DBMATRIX)->sel('oldsite,newsite')->from('changesite_log')->where(array('id =',$arg['id']))->exe();
if(empty($log)) return PUSH($this->linker,array('errcode'=>'ERR_LOG','errmsg'=>'记录不存在'));
$newsite=strtolower(trim($log['newsite']));
$oldsite=strtolower(trim($log['oldsite']));
$m=$this->m(DBMATRIX);
//搬总站配置
for($i=0;!empty($this->config[$i]);$i++){
// 找出新域名名配置
$mysql = "select id,http_host from `".$this->config[$i]."` where `http_host` = '{$newsite}'";
$config_from = $m->exe(false,$mysql);
if($config_from) continue;
// 找出原域名配置
$mysql = "select id,http_host from `".$this->config[$i]."` where `http_host` = '{$oldsite}'";
$config_from = $m->exe(false,$mysql);
if(!$config_from){
$mysql = "insert into `".$this->config[$i]."`(http_Host) values('{$newsite}') ";
$myre = $m->exe(false,$mysql);
if(!$myre) return PUSH($this->linker,array('errcode'=>'ERR_CONFIG','errmsg'=>'数据断开连接'));
}else{
// 新域名配置插入表
$mysql = "update `".$this->config[$i]."` set http_host='{$newsite}' where http_host = '{$oldsite}'";
$myre = $this->m(DBMATRIX)->exe(false,$mysql);
if(!$myre) return PUSH($this->linker,array('errcode'=>'ERR_CONFIG','errmsg'=>'数据断开连接'));
}
}
//修改customer
$site = $m->sel('id,version,branch')->from('customer')->where(array('domain=',$newsite))->exe();
if(!$site){
$site = $m->sel('id,version,branch')->from('customer')->where(array('domain=',$oldsite))->exe();
$res = $m->upd('customer')->set(array('domain'=>$newsite))->where(array('id=',$site['id']))->exe();
if(!$res) return PUSH($this->linker,array('errcode'=>'ERR_CUSTOMER','errmsg'=>'数据断开连接'));
}
//把新域名写入域名修改表(customer_update)
$list=$m->sel()->from('customer_update')->where(array('siteid=',$site['id']," and domain=",$newsite))->exe();
if(!$list){
$data = date("Y-m-d H:i:s");
$sql="insert into demo_customer_update (siteid,domain,time) values({$site['id']},'{$newsite}','{$data}')";
$log=$m->exe(false,$sql);
if(!$log) return PUSH($this->linker,array('errcode'=>'ERR_INSERT','errmsg'=>'数据断开连接'));
}
//删除旧数据库
$database = preg_replace("/[\W]/", "_", $oldsite);
$sql='DROP DATABASE `'.$database.'`';
//$res= $this->m($this->initDB[$site['branch']])->exe(false,$sql);
//if(!$res) return PUSH($this->linker,array('errcode'=>'ERR_DROP_DATABASE','errmsg'=>'数据断开连接'));
$mysql="update demo_changesite_log set step=6 ,state=1 where id={$arg['id']}";
$res=$m->exe(false,$mysql);
return PUSH($this->linker,array('errcode'=>'FINISHTASK','errmsg'=>'任务完成'));
}
private function fullTheList($Prefix){
$ObjectListInfo = A($this->linker,'oss/object/listObjects',array($this->bucket,array('max-keys'=>$this->maxkeys,'prefix'=>$Prefix)));
$ObjectList = $subObjectList = $ObjectListInfo->getObjectList();
$PrefixList = $subPrefixList = $ObjectListInfo->getPrefixList();
/*
每次只能获取1000条
循环拼接第1000条后面的文件或文件夹到数组中
*/
while(true){
$numObject = count($subObjectList);
$numPrefix = count($subPrefixList);
if($numObject+$numPrefix == 0) break;
if($numObject+$numPrefix < $this->maxkeys) break;
/*
只有文件时,取文件
只有文件夹时,取文件夹
都有时,取较大值
*/
while(true){
if(!$numObject) {$lastObject = $subPrefixList[$numPrefix-1]->getPrefix();break;}
if(!$numPrefix) {$lastObject = $subObjectList[$numObject-1]->getKey();break;}
$Key = $subObjectList[$numPrefix-1]->getKey();
$Prefix = $subPrefixList[$numObject-1]->getPrefix();
$lastObject = strcmp($Key,$Prefix)>0?$Key:$Prefix;
break;
}
$subObjectListInfo = A($this->linker,'oss/object/listObjects',array($this->bucket,array('max-keys'=>$this->maxkeys,'prefix'=>$Prefix,'marker'=>$lastObject)));
$subObjectList = $subObjectListInfo->getObjectList();
$subPrefixList = $subObjectListInfo->getPrefixList();
$ObjectList = array_merge($ObjectList,$subObjectList);
$PrefixList = array_merge($PrefixList,$subPrefixList);
}
return array('ObjectList'=>$ObjectList,'PrefixList'=>$PrefixList);
}
/*
递归函数:传入完整的文件与文件夹列表
参数:array(
'ObjectList'=>$ObjectList,
'PrefixList'=>$PrefixList
);
*/
private function copyInSocket($the){
foreach($the['ObjectList'] as $obj){
$key = $obj->getKey();
if(preg_match('/\+/',$key)) continue;
$newKey = $this->newKey($this->oldPrefix,$this->newPrefix,$key);
$res = A($this->linker,'oss/object/copyObject',array($this->bucket,$key,$this->bucket,$newKey));
PUSH($this->linker,array('errcode'=>'COPYOBJECT'));
}
foreach($the['PrefixList'] as $pre) $this->copyInSocket($this->fullTheList($pre->getPrefix()));
}
private function newKey($oldPrefix,$newPrefix,$obj){
return preg_replace('/^'.str_replace('/','\/',$oldPrefix).'/',$newPrefix,$obj);
}
}
前端代码
html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>换域名</title>
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<link rel="stylesheet" href="http://3n4w.oss-cn-shenzhen.aliyuncs.com/public/client-resource/layui-master/dist/css/layui.css">
<link rel="stylesheet" type="text/css" href="/admin/public/common.css">
<link rel="stylesheet" type="text/css" href="/admin/public/reset.css"/>
<link rel="stylesheet" type="text/css" href="domain.css"/>
<!-- 注意:如果你直接复制所有代码到本地,上述css路径需要改成你本地的 -->
</head>
<body >
<blockquote class="layui-elem-quote">
<span class="title">域名更换操作</span>
</blockquote>
<div class="content">
<div class="layui-inline">
<div class="layui-form-item">
<label class="layui-form-label">旧域名</label>
<div class="layui-input-inline">
<input type="text" name="username" lay-verify="required" placeholder="请输入" autocomplete="off" class="layui-input" id="oldsite">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">新域名</label>
<div class="layui-input-inline">
<input type="text" name="username" lay-verify="required" placeholder="请输入" autocomplete="off" class="layui-input" id="newsite">
</div>
</div>
</div>
<div class="layui-inline">
<button class="layui-btn save-btn fl" id="save-btn">保存</button>
<button class="layui-btn reload fl" id="reload">重启</button>
</div>
</div>
<div class="progress" id="progress">
<fieldset class="layui-elem-field layui-field-title" style="margin-top: 30px;">
<legend>操作进度</legend>
</fieldset>
<ul class="layui-timeline">
<li class="layui-timeline-item">
<i class="layui-icon layui-timeline-axis"></i>
<div class="layui-timeline-content layui-text">
<div class="layui-timeline-title"><label class="step1">换域名准备阶段</label><label class="state st1"></label></div>
</div>
</li>
<li class="layui-timeline-item">
<i class="layui-icon layui-timeline-axis"> </i>
<div class="layui-timeline-content layui-text">
<div class="layui-timeline-title"><label class=" step2">数据库表数据复制</label><label class="state st2"></label></div>
</div>
</li>
<li class="layui-timeline-item">
<i class="layui-icon layui-timeline-axis"></i>
<div class="layui-timeline-content layui-text">
<div class="layui-timeline-title"><label class="step3">OSS存储文件复制</label><label class="state st3"></label></div>
</div>
</li>
<li class="layui-timeline-item">
<i class="layui-icon layui-timeline-axis"></i>
<div class="layui-timeline-content layui-text">
<div class="layui-timeline-title"><label class="step4">配置文件修改</label><label class="state st4"></label></div>
</div>
</li>
<li class="layui-timeline-item">
<i class="layui-icon layui-timeline-axis"></i>
<div class="layui-timeline-content layui-text">
<div class="layui-timeline-title"><label class="step5">操作已完成</label></div>
</div>
</li>
</ul>
</div>
<script type="text/javascript" src="http://3n4w.oss-cn-shenzhen.aliyuncs.com/public/client-resource/layui-master/dist/layui.js"></script>
<!-- 注意:如果你直接复制所有代码到本地,上述js路径需要改成你本地的 -->
<script type="text/javascript" src="domain.js"></script>
<script>
</script>
</body>
</html>
js
layui.use(['form'], function() {
var form = layui.form,
$ = layui.jquery;
var websocket = new WebSocket('ws://192.168.1.1:9997?swoole=dev&mca=swoole/changesite/init&http_host=www.baidu.com');
var save_btn = document.getElementById("save-btn");
var oldsite = document.getElementById("oldsite");
var newsite = document.getElementById("newsite");
var progress = document.getElementById("progress");
var finishcopy = document.getElementById("finishcopy");
var reload_btn = document.getElementById('reload');
reload_btn.onclick = function(){
var copyStart = {
mca : 'swoole/changesite/reload'};
websocket.send(JSON.stringify(copyStart));
}
var reload = {
mca : 'swoole/changesite/reload',
arg : 'arg1',};
var beating = {
mca : 'swoole/changesite/beating',
arg : 'arg1',};
var copyNum = 0;var id = 0;var step =0;
var copyReady = function(num){console.log(num);
$('.step1').addClass('has-end').parents('.layui-timeline-content').siblings('.layui-icon').addClass('has-over');
$('.st1').html('已完成');
$('.st2').html("正在复制<b class='has-copy'>0</b> /<b class='tabnum'>"+num+" </b>");
if(step==1){
copyData();
}
if(step==2){
startSocketCopy();
}
if(step==3){
$('.step2').addClass('has-end').parents('.layui-timeline-content').siblings('.layui-icon').addClass('has-over');
$('.st2').html("已完成");
alterConfig();
}
}
var copyData = function(){
var copyStart = {
mca : 'swoole/changesite/copyData',
id : id};
websocket.send(JSON.stringify(copyStart));
}
var startSocketCopy = function(){
$('.step2').addClass('has-end').parents('.layui-timeline-content').siblings('.layui-icon').addClass('has-over');
$('.st2').html("已完成");
$('.st3').html("正在复制<b class='has-file'>0</b>");
var copyStart = {
mca : 'swoole/changesite/startSocketCopy',
id : id};console.log(copyStart);
websocket.send(JSON.stringify(copyStart));
}
var alterConfig = function(){
$('.step3').addClass('has-end').parents('.layui-timeline-content').siblings('.layui-icon').addClass('has-over');
$('.st3').html("已完成");
$('.st4').html("正在修改配置文件");
var copyStart = {
mca : 'swoole/changesite/alterConfig',
id : id};
websocket.send(JSON.stringify(copyStart));
}
var taskEnd = function(){
$('.step4').addClass('has-end').parents('.layui-timeline-content').siblings('.layui-icon').addClass('has-over');
$('.st4').html("已完成");
$('.step5').addClass('has-end').parents('.layui-timeline-content').siblings('.layui-icon').addClass('has-over');
}
save_btn.onclick = function(){
progress.style.display = 'block';
var copyStart = {
mca : 'swoole/changesite/copyStart',
oldsite : oldsite.value,
newsite : newsite.value};
websocket.send(JSON.stringify(copyStart));
}
websocket.onopen = function (evt) {
console.log("Connected to WebSocket server.");
websocket.send(JSON.stringify(reload));
window.setInterval(function(){websocket.send(JSON.stringify(beating));}, 10000);
};
websocket.onmessage = function (evt) {
var that = this;
var data = eval('('+evt.data+')');
console.log(data);
switch(data.message.errcode){
case 'FINISHREADY':
id = data.message.id;
step = data.message.step;
copyReady(data.message.numsql);
break;
case 'FINISHCOPYDATA':
startSocketCopy();
break;
case 'FINISHCOPYOSS':
alterConfig();
break;
case 'FINISHTASK':
taskEnd();
break;
case 'SUCCESS_CREATE':
$('.has-copy').html(data.message.num);console.log(data.message.num);
break;
case 'COPYOBJECT':
$('.has-file').html(++copyNum);
break;
//default:console.log(data.message.errmsg);break;
}
};
websocket.onclose = function (evt) {console.log("Disconnected");};
websocket.onerror = function (evt, e) {console.log('Error occured: ');console.log(evt.data);};
});
css
.content {
padding: 20px 80px;
}
button.layui-btn.save-btn.fl {
margin-left: 100px;
}
.layui-timeline {
padding-left: 100px;
}
.finish {
background-color: #a53333;
}
.progress{
display: none;
}
.state{
color: #c74949;
padding-left: 75px;
}
.has-over{
background-color: #c74949;
}
.has-end{
color: #c74949;
}
Swoole一键操作基于阿里云的RDS数据库迁移+OSS文件搬迁的更多相关文章
- 悠星网络基于阿里云分析型数据库PostgreSQL版的数据实践
说到“大数据”,当下这个词很火,各行各业涉及到数据的,目前都在提大数据,提数据仓库,数据挖掘或者机器学习,但同时另外一个热门的名词也很火,那就是“云”.越来越多的企业都在搭建属于自己的云平台,也有一些 ...
- 阿里云设置CDN加速访问OSS文件
快速配置OSS:https://help.aliyun.com/document_detail/31885.html?spm=5176.doc31886.6.97.8iuJo5 快速配置CDN:htt ...
- 阿里云rds数据库迁移实战(多数据源)
由于某几个业务表数据量太大,数据由业务写,数据部门读. 写压力不大,读却很容易导致长时间等待问题(读由单独系统进行读),导致连接被占用,从而容易并发稍稍增长导致全库卡死! 于是,就拆库呗. 业务系统拆 ...
- 基于阿里云server搭建SVNserver
基于阿里云server搭建SVNserver 本系列文章由ex_net(张建波)编写,转载请注明出处. http://blog.csdn.net/ex_net/article/details/8577 ...
- 基于阿里云的JavaEE系统框架介绍
基于阿里云的系统框架展望 1) CDN 用于缓存静态文件等等.七牛和阿里的都还可以. 七牛要做的久一点,各种图片处理的接口要完善一些 阿里的CDN要稍微好一点点,但是没有不安全的访问方式,访问稍微没有 ...
- 构建基于阿里云OSS文件上传服务
转载请注明来源:http://blog.csdn.net/loongshawn/article/details/50710132 <构建基于阿里云OSS文件上传服务> <构建基于OS ...
- 基于阿里云SLB/ESS/EIP/ECS/VPC的同城高可用方案演练
今天基于阿里云SLB/ESS/EIP/ECS/VPC等产品进行了一次同城高可用方案演练: 基本步骤如下: 1. 在华东1创建VPC网络VPC1,在华东1可用区B和G各创建一个虚拟交换机vpc1_swi ...
- 基于阿里云容器服务用docker容器运行ASP.NET 5示例程序
小试阿里云容器服务 之后,接下来有一个挡不住的小试冲动--用docker容器运行程序.首先想到的程序是 ASP.NET 5示例程序,于是参考msdn博客中的这篇博文 Running ASP.NET 5 ...
- 一·创建Linux服务器(基于阿里云)
本系统是基于阿里云服务器,购买请前往https://www.aliyun.com/?spm=5176.8142029.388261.1.taXish ,由于经济能力的限制,本人购买的是最低配置如下 其 ...
随机推荐
- Hyperledger Fabric的test-network启动过程Bash源码详解
前言 在基于Debian搭建Hyperledger Fabric 2.4开发环境及运行简单案例中,我们已经完成了Fabric 2.4的环境搭建及fabric-samples/test-network官 ...
- 【转载】Java密钥库及keytool使用详解
---------------- 版权声明:本文为CSDN博主「adrninistrat0r」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明. 原文链接:https: ...
- 【FAQ】应用集成HMS Core部分服务出现“ 6003报错”情况的解决方法来啦
背景 开发者在应用中集成HMS Core部分服务时,android sdk 以及flutter等跨平台sdk,会出现编译打包后,运行报6003错误码的情况.根据查询可以得知,错误代码 6003 表示证 ...
- 如何基于 ZEGO SDK 实现 Windows 一对一音视频聊天应用
互联网发展至今,实时视频和语音通话越来越被大众所依赖. 今天,我们将会继续介绍如何基于ZEGO SDK实现音视频通话功能,前两篇文章分别介绍了Android,Flutter平台的实现方式,感兴趣的小伙 ...
- Axios及其async await封装
Axios(IE8+) 基于promise的http库可用于浏览器与node.js 1.特性 支持promise API 拦截请求和相应 转换请求数据和响应数据 取消请求 自动转换JSON数据 客户端 ...
- Java语言学习day15--7月21日
今日内容介绍1.Eclipse开发工具2.超市库存管理系统 ###01Eclipse的下载安装 * A: Eclipse的下载安装 * a: 下载 * http://www.eclipse.org ...
- python基础练习题(题目 文本颜色设置)
day23 --------------------------------------------------------------- 实例035:设置输出颜色 题目 文本颜色设置. 分析:不会, ...
- LVM 逻辑卷学习
一个执着于技术的公众号 前言 每个Linux使用者在安装Linux时都会遇到这样的困境:在为系统分区时,如何精确评估和分配各个硬盘分区的容量,因为系统管理员不但要考虑到 当前某个分区需要的容量,还要预 ...
- JDBC:加载数据库驱动、连接数据库(详细讲解)
加载数据库驱动: 1)由于Java是一个纯面向对象语言,任何事物在其中都必须抽象成类或者类对象,数据库也不例外,JDBC同样也把数据库抽象成面向对象的结构: 2)JDBC将整个数据库驱动器在底层抽象成 ...
- 简述 private、protected、 public、 internal修饰符的访问权限
1.private: 私有的,只能在此类中访问 2.protected: 受保护的,只能在此类及其继承类中访问 3.public: 公开的,没有访问限制 4:internal: 内部的,只能在当前程序 ...