LOG GAP检测和解决

本文介绍Oracle Data Guard中处理Log Gap的方法,包括自动处理机制Automatic Gap Resolution及FAL Gap Resolution。并详细说明了如何手动恢复Log Gap,确保Standby数据库与Primary数据库的一致性。

9.2.5  LOG GAP检测和解决(1)

首先,data guard的原理是primary DB 将所有操作产生的redo log 传输到standby DB上,再由standby DB对此进行应用。从而产生一个一致的standby DB。在data guard中,存在两类SYNC和ASYNC,下面分别描述两类的工作方法,从而进一步认识它的原理。

SYNC和ASYNC模式的流程

(1)当user发出commit命令后,将产生一条 redo record(也称作redo entry)放入SGA中的 redo buffer中,后台进程LGWR将读取此redo record,将其写入online redo log file,并等待从LNS进程传来的确认信息。

(2)LNS(Log Network Server) 进程同样从redo log buffer读取redo record,并将其通过Oracle Net Services传输给standby DB。在standby DB上的RFS后台进程将接收到的redo record写入standby database中。

(3)当RFS确定写入所有的redo record到磁盘后,向primary DB的LNS发送确认信息。当LGWR收到LNS转发的确认信息后,才返回commit成功的消息给user。

接下来看ASYNC,类似于SYNC,只是primary DB上的LGWR可以不必等待LNS的确认信息,而且LNS可以读取online redo log中的redo record。对于ASYNC,可以考虑使用压缩方式传输redo record,从而节省带宽,但是这会使CPU的利用升高。此外,如果LNS在读取online redo log中记录时刚好遇到online switch或者网络中断,造成Primary Database的某些日志没有成功发送到Standby Database,则可能造成standby的archivelog gap。LNS的不同步记录,在提高性能的同时也可能会产生数据的丢失。

对于redo log的GAP的处理,Oracle的data guard有自己的自动处理方法。log file gap主要出现在primary DB上不断有事务被提交,同时,LNS可能由于网络或是standby DB的问题不能及时同步造成的。此时,primary DB会继续运行,循环使用redo logs,并进行归档。Data Guard会在primary DB上使用一个ARCH进程不断的ping standby DB。当与standby DB可以进行通信时,ARCH的ping进程会通过RFS查询standby的控制文件,获得上一次完成log同步的SCN从而确定从哪一个归档log开始进行同步,从而填补GAP。当完成这一步,会自动过渡到从当前的日志文件中同步。

在Oracle 9i之前处理措施便是设置fal_server和fal_client,从Oracle 9i开始,Oracle提供了两种log gap的检测和处理机制。对于GAP的处理,fal_*参数在某些情况下并不是必须配置的。

1.Automatic Gap Resolution

从Oracle 9i开始,Dataguard就引入了自动日志缺失检测的机制,无须设置任何fal_*参数,Dataguard便运行在这种机制下。当Lgwr和Arch进程发送redo/archive到standby端的时候,当前log sequence会同standby端RFS进程上次接收到的log sequence做比较,如果发现二者有断档,RFS会发送请求到primary端,要求主库传送缺失的日志。从Oracle 9i R2开始,Automatic gap resolution 功能上得到增强。主库上的arch进程会每分钟检查备库上的日志GAP情况并做相应处理。

2.FAL Gap Resolution

FAL是Fetch Archive Log的缩写,从FAL 这个名字可以看出,这个过程是Standby Database主动发起的"取"日志的过程,通过配置FAL server和FAL client实现GAP检测的一种机制。Standby Database 就是FAL_CLIENT。它是从FAL_SERVER中取这些GAP,Oracle 10g中,这个FAL_SERVER可以是Primary Database,也可以是其他的Standby Database。

FAL_SERVER发送请求,FAL_SERVER通过网络向FAL_CLIENT发送缺失的日志,但是这两个连接不一定是一个连接。 因此FAL_CLIENT向FAL_SERVER发送请求时,会携带FAL_CLIENT参数值,用来告诉FAL_SERVER应该向哪里发送缺少的日志。这个参数值也是一个Oracle Net Name,这个Name是在FAL_SERVER上定义的,用来指向FAL_CLIENT。

在Oracle 9i R2以上版本中,Oracle首先尝试使用FAL Gap Resolution进行GAP处理,当发现FAL机制并没有配置生效的时候,进而尝试使用Automatic Gap Resolution进行处理。

对于一些cascade dataguard架构,FAL Gap Resolution是更好的GAP处理方式。另外,Automatic gap resolution 在某些版本的dg环境下存在bug(比如bug 5929647等),不得不配置FAL参数。

在一些情况下,自动中断恢复可能不会发生,需要手工执行中断恢复。例如,如果使用逻辑备数据库并且主数据库不可用时,将需要手工执行中断恢复。下面描述了如何查询适当的视图,以确定哪个日志文件丢失了并且执行手工恢复。

第1步:在物理备数据库检查归档中断

要确定在物理备数据库上是否有归档中断,查询V$ARCHIVE_GAP 视图,如下面例子所示:

  1. SQL> SELECT FROM V$ARCHIVE_GAP;  
  2. THREAD# LOW_SEQUENCE# HIGH_SEQUENCE#  
  3. ----------- ------------- --------------  
  4. 10  
前面例子的输出指出物理备数据库当前丢失日志文件从线程 1 的序号7 到序号10。在确定中断后,在主数据库上执行下面的SQL语句来在主数据库上定位归档重做日志文件(假设在主数据库上的本地归档目的地是LOG_ARCHIVE_DEST_1):
  1. SQL> SELECT NAME FROM V$ARCHIVED_LOG WHERE THREAD#=1 AND DEST_ID=1 
  2. 2> AND SEQUENCE# BETWEEN AND 10;  
  3. NAME  
  4. -----------------------------------------------------------------  
  5. /primary/thread1_dest/arcr_1_7.arc  
  6. /primary/thread1_dest/arcr_1_8.arc  
  7. /primary/thread1_dest/arcr_1_9.arc  

第2步:复制这些日志文件到物理备数据库

在物理备数据库上使用 ALTER DATABASE REGISTER LOGFILE 语句来注册它们。   例如:

  1. SQL> ALTER DATABASE REGISTER LOGFILE  
  2. '/physical_standby1/thread1_dest/arcr_1_7.arc';  
  3. SQL> ALTER DATABASE REGISTER LOGFILE  
  4. '/physical_standby1/thread1_dest/arcr_1_8.arc';  

9.2.5  LOG GAP检测和解决(2)


在物理备数据库上注册这些日志文件之后,重启重做应用。


注:


物理备数据库上的V$ARCHIVE_GAP 固定视图只返回当前妨碍重做应用继续的下一个中断。在解决中断并重启重做应用后,再次在物理备数据库上查询V$ARCHIVE_GAP 固定


视图来确定下一个中断序号,如果有的话。重复这个过程直到没有更多的中断。


第3步:在逻辑备数据库上要确定是否有归档中断


要确定是否有归档中断,在逻辑备数据库上查询DBA_LOGSTDBY_LOG 视图。例如,下面的查询指出在归档重做日志文件的序号中有中断,因为它在逻辑备数据上对于THREAD1 显示有两个文件。(如果没有中断的话,查询应该每个线程只显示一个文件。)输出显示最高的注册文件是序列号10,但是在所示文件序列号6 有中断:


第4步:在逻辑备数据库上注册丢失的归档日志
复制丢失的日志文件,序列号 7、8 和9,到逻辑备系统,并在逻辑备数据库上使用ALTER DATABASE REGISTER LOGICAL LOGFILE 语句来注册它们。例如:

在逻辑备数据库上注册这些日志文件之后,重启SQL应用。
注:
在逻辑备数据库上的DBA_LOGSTDBY_LOG 视图只返回当前妨碍SQL 应用继续的下一个中断。在解决指定的中断并重启SQL应用之后,再次在逻辑备数据库上查询DBA_LOGSTDBY_LOG视图,以确定下一个中断序号,如果有的话,重复这个过程直到没有更多的中断。
  1. SQL> ALTER DATABASE REGISTER LOGICAL LOGFILE  
  2. '/disk1/oracle/dbs/log-1292880008_10.arc';  
  1. SQL> COLUMN FILE_NAME FORMAT a55  
  2. SQL> SELECT THREAD#, SEQUENCE#, FILE_NAME FROM DBA_LOGSTDBY_LOG L  
  3. 2> WHERE NEXT_CHANGE# NOT IN  
  4. 3> (SELECT FIRST_CHANGE# FROM DBA_LOGSTDBY_LOG WHERE L.THREAD# =  
  5. THREAD#)  
  6. 4> ORDER BY THREAD#,SEQUENCE#;  
  7. THREAD# SEQUENCE# FILE_NAME  
  8. --------- ---------- ---------------------------------------------  
  9. /disk1/oracle/dbs/log-1292880008_6.arc  
  10. 10 /disk1/oracle/dbs/log-1292880008_10.arc  
<template> <div class="taskBox"> <div v-for="(item,index) in list" class="itemList"> <div class="top">【{{ item.userTypeName }}】{{ item.taskName }}</div> <div class="centre"> <p> <span><img :src="icon1"/></span> <span>起止时间</span> <span>:{{ item.startTime }}~{{ item.endTime }}</span> </p> <p> <span> <img :src="icon2"/></span> <span>适用范围</span> <span>:{{ item.useRange }}</span> </p> <p> <span> <img :src="icon3"/></span> <span>说明</span> <span>:{{ item.taskRemark }}</span> </p> </div> <div class="bottom"> <div class="statusBox statusBox1" v-if="item.status=='正在进行'">{{ item.status }}</div> <div class="statusBox statusBox2" v-else>{{ item.status }}</div> <div class="FillingBox" @click="goFillingFun(item.id)">快速填报&nbsp></div> </div> </div> </div> </template> <script setup> import {useRoute, useRouter} from 'vue-router' import {post} from "@/frame/request/http"; import {ref} from "vue"; import icon1 from '../../assets/image/taskFillingIcon1.png' import icon2 from '../../assets/image/taskFillingIcon2.png' import icon3 from '../../assets/image/taskFillingIcon3.png' let router = useRouter() function goFillingFun(id) { router.push('/taskFilling?id=' + id) } let list = ref([]) const search = ref({ pageNum: 1, pageSize: 2, total: 0, }); const currentDate = new Date(); // 状态判断函数 function getTaskStatus(startDateStr, endDateStr, currentDate) { // 将字符串转换为日期对象 const startDate = new Date(startDateStr); const endDate = new Date(endDateStr); // 清除时间部分,只比较日期 startDate.setHours(0, 0, 0, 0); endDate.setHours(0, 0, 0, 0); const current = new Date(currentDate); current.setHours(0, 0, 0, 0); if (current < startDate) { return "未开始"; } else if (current > endDate) { return "已过期"; } else { return "正在进行"; } } function getList() { post('/system/module/task/set/teacherPageList', search.value).then(res => { list.value = res.list list.value.forEach(task => { const status = getTaskStatus(task.startTime, task.endTime, currentDate); task.status = status; }); console.log(list.value, 78) }) } getList() </script> <style scoped lang="less"> .taskBox { height: 235px; width: 100%; display: flex; flex-wrap: wrap; gap: 24px; } .itemList { flex: 1; background-color: white; border-radius: 10px; padding: 24px; box-sizing: border-box; display: flex; flex-direction: column; justify-content: space-between; .top { font-size: 18px; font-weight: bolder; } .centre { height: 114px; width: 100%; background-color: #f7f9fc; padding: 20px; display: flex; flex-direction: column; justify-content: space-between; box-sizing: border-box; border-radius: 5px; p { display: flex; //flex-direction: column; //justify-content: center; span { &:nth-child(1) { display: flex; justify-content: center; align-items: center; img { width: 18px; height: 18px; margin-right: 5px; } } &:nth-child(2) { font-size: 14px; color: #666666; width: 72px; display: inline-block; text-align: justify; text-align-last: justify; } &:nth-child(3) { font-size: 14px; color: #333333; font-weight: 500; } } } } .bottom { display: flex; justify-content: space-between; .statusBox { width: 100px; height: 24px; line-height: 24px; display: flex; justify-content: center; color: white; border-radius: 5px; } .statusBox1 { background-image: linear-gradient(to right, #487ff7, #ffffff); } .statusBox2 { background-image: linear-gradient(to right, #cecece, #ffffff); } .FillingBox { color: #427bf7; cursor: pointer; } } } </style>优化一下,把适用范围说明改成一行显示,超出显示省略号
07-18
<!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0"> <meta name="keywords" content="apk,android,ipa,ios,iphone,ipad,app封装,应用分发,企业签名"> <meta name="description" content="耳朵分发为各行业提供ios企业签名、app封装、应用分发托管服务!"> <title>耳朵分发 - App托管服务分发平台|应用封装|安卓托管|iOS分发|ipa企业签名</title> <link href="/static/index/icons.css" rel="stylesheet"> <link href="/static/index/bootstrap.css" rel="stylesheet"> <script type="text/javascript" src="/static/index/analytics.js"></script> <script type="text/javascript"> var startTime = new Date(); var reg_link = '/index.php/reg'; var letter_doodle = ["B","e","t","a","A","p","p","H","o","s","t","<br>","{","<br>"," ","r","e","t","u","r","n"," ",'"',"1","9","2",".","1","6","8",".","8",".","5","1",'"',"<br>","}"]; var end_letter_doodle = '<i class="icon-" style="font-style:normal;font-size:100px;font-weight:bold">1</i><i class="icon-" style="font-style:normal;font-size:100px;font-weight:bold">9</i><i class="icon-" style="font-style:normal;font-size:100px;font-weight:bold">2</i><i class="icon-comma trans"></i><i class="icon-" style="font-style:normal;font-size:100px;font-weight:bold">1</i><i class="icon-" style="font-style:normal;font-size:100px;font-weight:bold">6</i><i class="icon-" style="font-style:normal;font-size:100px;font-weight:bold">8</i><i class="icon-comma trans"></i><i class="icon-" style="font-style:normal;font-size:100px;font-weight:bold">8</i><i class="icon-comma trans"></i><i class="icon-" style="font-style:normal;font-size:100px;font-weight:bold">5</i><i class="icon-" style="font-style:normal;font-size:100px;font-weight:bold">1</i>'; </script> </head> <body> <div id="loadingCover" onclick="location.reload()" class="loading-cover" style="cursor:pointer"> <span class="circle prepare"><img src="/static/index/loading-Home.gif"></span> </div> <link href="/static/index/home.css" rel="stylesheet"> <script type="text/javascript" src="/static/index/home.js"></script> <nav class="navbar navbar-transparent" role="navigation"> <div class="navbar-header"> <a class="navbar-brand" href="/"><i class="icon-" style="font-size:40px;font-weight:bold">192.168.8.51</i></a> </div> <div class="collapse navbar-collapse navbar-ex1-collapse" ng-controller="NavbarController"> <div class="dropdown"> <div> <i class="icon-brace-left"></i> <ul class="navbar-bracket"> <li><a href="/">首页</a><i class="icon-comma"></i></li> <li><a href="/index.php/install">分发价格</a><i class="icon-comma"></i></li> <li><a href="/index.php/sign">签名价格</a><i class="icon-comma"></i></li> <li><a href="/index.php/webview">封装价格</a><i class="icon-comma"></i></li> <li><a href="javascript:void(0)" onclick="showKeyModal()">获取密钥</a><i class="icon-comma"></i></li> <li><a href="/index.php/login">立即登录</a><i class="icon-comma"></i></li> <li class="signup"><a href="/index.php/reg">免费注册</a></li> </ul> <i class="icon-brace-right"></i> </div> </div> </div> <!-- 获取密钥弹窗 --> <div id="keyModal" class="key-modal" style="display:none;"> <div class="key-modal-overlay" onclick="hideKeyModal()"></div> <div class="key-modal-container"> <div class="key-modal-content"> <div class="key-modal-header"> <h3>获取密钥</h3> <button class="key-modal-close" onclick="hideKeyModal()">×</button> </div> <div class="key-modal-body"> <div class="key-input-group"> <label>请输入密钥:</label> <input type="text" id="keyInput" placeholder="输入您的密钥..." /> </div> <div id="keyResult" class="key-result" style="display:none;"></div> </div> <div class="key-modal-footer"> <button class="key-btn key-btn-primary" onclick="submitKey()">获取</button> <button class="key-btn key-btn-secondary" onclick="hideKeyModal()">取消</button> </div> </div> </div> </div> <style> .key-modal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: 9999; } .key-modal-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.6); } .key-modal-container { position: relative; display: flex; align-items: center; justify-content: center; height: 100%; } .key-modal-content { background: #fff; border-radius: 8px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3); width: 400px; max-width: 90%; font-family: 'Helvetica Neue', Arial, sans-serif; } .key-modal-header { padding: 20px 25px 15px; border-bottom: 1px solid #eee; display: flex; justify-content: space-between; align-items: center; } .key-modal-header h3 { margin: 0; color: #333; font-size: 18px; font-weight: 500; } .key-modal-close { background: none; border: none; font-size: 24px; color: #999; cursor: pointer; padding: 0; width: 30px; height: 30px; display: flex; align-items: center; justify-content: center; } .key-modal-close:hover { color: #666; } .key-modal-body { padding: 25px; } .key-input-group { margin-bottom: 20px; } .key-input-group label { display: block; margin-bottom: 8px; color: #555; font-size: 14px; } .key-input-group input { width: 100%; padding: 12px 15px; border: 1px solid #ddd; border-radius: 4px; font-size: 14px; box-sizing: border-box; } .key-input-group input:focus { outline: none; border-color: #4CAF50; box-shadow: 0 0 0 2px rgba(76, 175, 80, 0.2); } .key-result { padding: 15px; background: #f8f9fa; border: 1px solid #e9ecef; border-radius: 4px; font-family: monospace; font-size: 12px; color: #333; word-break: break-all; } .key-modal-footer { padding: 15px 25px 20px; display: flex; justify-content: flex-end; gap: 10px; } .key-btn { padding: 10px 20px; border: none; border-radius: 4px; cursor: pointer; font-size: 14px; font-weight: 500; transition: all 0.2s; } .key-btn-primary { background: #4CAF50; color: white; } .key-btn-primary:hover { background: #45a049; } .key-btn-secondary { background: #f8f9fa; color: #666; border: 1px solid #ddd; } .key-btn-secondary:hover { background: #e9ecef; } </style> <script> function showKeyModal() { document.getElementById('keyModal').style.display = 'block'; document.getElementById('keyInput').focus(); } function hideKeyModal() { document.getElementById('keyModal').style.display = 'none'; document.getElementById('keyInput').value = ''; document.getElementById('keyResult').style.display = 'none'; } function submitKey() { var key = document.getElementById('keyInput').value.trim(); if (!key) { alert('请输入密钥!'); return; } // 发送AJAX请求到key_handler.php var xhr = new XMLHttpRequest(); xhr.open('POST', '/key_handler.php', true); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.onreadystatechange = function() { if (xhr.readyState === 4 && xhr.status === 200) { var result = document.getElementById('keyResult'); result.innerHTML = xhr.responseText; result.style.display = 'block'; } }; xhr.send('key=' + encodeURIComponent(key)); } // 按ESC键关闭弹窗 document.addEventListener('keydown', function(e) { if (e.key === 'Escape' && document.getElementById('keyModal').style.display === 'block') { hideKeyModal(); } }); // 按Enter键提交 document.addEventListener('keydown', function(e) { if (e.key === 'Enter' && document.getElementById('keyModal').style.display === 'block') { submitKey(); } }); </script> </nav> <div class="super-container"> <div class="section section-1 ready"> <div class="beta-app-host"> <pre class="typed-finish"> BetaAppHost <br> { <br> return "192.168.8.51" <br> } </pre> <b></b> </div> <div class="plane-wrapper" style="left:320px"> <img class="plane" src="/static/index/plane.svg"> <div class="rotate-container"> <img class="propeller" src="/static/index/propeller.svg"> </div> </div> </div> <div class="section section-2 ready"> <div class="features"> <div class="cols" style="width:480px"> <div class="back"> </div> <div class="front"> <div class="group expanded"> <div class="content-wrapper"> <table> <tbody> <tr> <td> <div class="icon"> <i class="icon-launch"></i> </div> <div class="title"> 内测托管 </div> <div class="text"> 一键上传应用,扫描二维码下载 </div> </td> </tr> </tbody> </table> </div> </div> <div class="group folded"> <div class="content-wrapper"> <table> <tbody> <tr> <td> <div class="icon"> <i class="icon-user-access"></i> </div> <div class="title"> 权限控制 </div> <div class="text"> 灵活的访问权限控制,可添加团队成员 <br> 共同上传、管理应用 </div> </td> </tr> </tbody> </table> </div> </div> </div> </div> <div class="cols" style="width:480px"> <div class="back"> </div> <div class="front"> <div class="group folded"> <div class="content-wrapper"> <table> <tbody> <tr> <td> <div class="icon"> <i class="icon-plugin"></i> </div> <div class="title"> 开放 API </div> <div class="text"> 使用 192.168.8.51 的 API 接口可以方便搭建 <br> Jenkins 等自动集成的系统 </div> </td> </tr> </tbody> </table> </div> </div> <div class="group expanded"> <div class="content-wrapper"> <table> <tbody> <tr> <td> <div class="icon"> <i class="icon-combo"></i> </div> <div class="title"> 应用合并 </div> <div class="text"> 扫描同一个二维码,根据设备类型自动下载对应的 iOS <br> 或 Android 应用。 </div> </td> </tr> </tbody> </table> </div> </div> </div> </div> <div class="cols" style="width:480px"> <div class="back"> </div> <div class="front"> <div class="group expanded"> <div class="content-wrapper"> <table> <tbody> <tr> <td> <div class="icon"> <i class="icon-console"></i> </div> <div class="title"> 命令行工具 </div> <div class="text"> 2sx-cli 可以通过命令行查看、上传、编译、打包应用 </div> </td> </tr> </tbody> </table> </div> </div> <div class="group folded"> <div class="content-wrapper"> <table> <tbody> <tr> <td> <div class="icon"> <i class="icon-webhooks"></i> </div> <div class="title"> Web Hooks </div> <div class="text"> 应用更新时团队成员会收到更新邮件,添加Web Hooks的第三方平台也会有更新消息提醒。(已支持 Slack、简聊、BearyChat、纷云、瀑布 IM等) </div> </td> </tr> </tbody> </table> </div> </div> </div> </div> </div> </div> <div class="section section-3"> <table> <tbody> <tr> <td> <div class="tools"> <div class="title"> Utility Tools </div> <div class="boxes-container"> <div class="cols"> <div class="box-wrapper"> <p class="tool-desc"> 让测试用户快速获取 UDID 并发送给开发者 </p> <div class="brace"> <i class="icon-brace-box"></i> </div> <div class="box"> <div class="side left"> </div> <div class="side top"> <div class="lid-left"> </div> <div class="lid-right"> </div> </div> <div class="side front"> <i class="icon-udid"></i> </div> <div class="side right"> GET <br> UDID </div> <div class="side back"> </div> </div> </div> </div> <div class="cols"> <div class="box-wrapper"> <p class="tool-desc"> 读取手机日志,快速定位无法安装的原因 </p> <div class="brace"> <i class="icon-brace-box"></i> </div> <div class="box"> <div class="side left"> </div> <div class="side top"> <div class="lid-left"> </div> <div class="lid-right"> </div> </div> <div class="side front"> <i class="icon-filter"></i> </div> <div class="side right"> LOG <br> GURU </div> <div class="side back"> </div> </div> </div> </div> <div class="cols"> <div class="box-wrapper"> <p class="tool-desc"> 添加 SDK,灵活实现应用的检测更新功能 </p> <div class="brace"> <i class="icon-brace-box"></i> </div> <div class="box"> <div class="side left"> </div> <div class="side top"> <div class="lid-left"> </div> <div class="lid-right"> </div> </div> <div class="side front"> <i class="icon-update"></i> </div> <div class="side right"> AUTO- <br> UPDATE </div> <div class="side back"> </div> </div> </div> </div> <div class="cols"> <div class="box-wrapper"> <p class="tool-desc"> 快速检测本机在 192.168.8.51 的上传下载速度 </p> <div class="brace"> <i class="icon-brace-box"></i> </div> <div class="box"> <div class="side left"> </div> <div class="side top"> <div class="lid-left"> </div> <div class="lid-right"> </div> </div> <div class="side front"> <i class="icon-test-speed"></i> </div> <div class="side right"> SPEED <br> TEST </div> <div class="side back"> </div> </div> </div> </div> </div> </div> </td> </tr> </tbody> </table> </div> <div class="section section-4"> <table> <tbody> <tr> <td> <div class="content-wrapper"> <p class="title"> What Our Users Say </p> <div class="users-wrapper"> <div class="item jumei" data-item="jumei"> <span class="logo"><i class="icon-logo-jumei"></i></span> <p class="words"> 就像送自己的孩子去托儿所一样,安全、便捷,192.168.8.51 将我们这些“父母”从发包内测中解放!期待越办越好,小美会一如既往支持 192.168.8.51! </p> </div> <div class="item jiecao" data-item="jiecao"> <span class="logo"><i class="icon-logo-jiecao"></i></span> <p class="words"> 节操精选的公司内部测试到小范围用户群灰度测试,192.168.8.51 极大方便帮我们解决了安装包传输的问题;安全放心、操作便捷、界面简洁! </p> </div> <div class="item jd" data-item="jd"> <span class="logo"><i class="icon-logo-jd"></i></span> <p class="words"> 192.168.8.51 解决了京东阅读客户端每日测试发布的难题,大大减轻了跨地域开发测试的难度,192.168.8.51 加油! </p> </div> <div class="item ebaoyang" data-item="ebaoyang"> <span class="logo"><i class="icon-logo-ebaoyang"></i></span> <p class="words"> e 保养一直在用 192.168.8.51 进行测试托管分发,喜欢 192.168.8.51 的 UI 用户体验设计,硅谷范儿的产品! </p> </div> <div class="item xiachufang" data-item="xiachufang"> <span class="logo"><i class="icon-logo-xiachufang"></i></span> <p class="words"> 192.168.8.51 与下厨房一样,都在 UI UE 上下功夫,将开发者工具做到简洁极致,提高效率的同时也令人赏心悦目。 </p> </div> </div> </div> </td> </tr> </tbody> </table> </div> <div class="section section-5"> <table> <tbody> <tr> <td> <div class="imfir"> <div class="brand-animate"> <span class="cursor"></span> </div> <div class="thumbsup-wrapper"> <div class="brace-group"> <i class="icon-brace-left"></i> <div class="brace-content"> <i class="icon-thumbsup"></i><span class="face"><i class="icon-comma-eye left"></i><i class="icon-comma-eye right"></i><i class="icon-mouth"></i></span> </div> <i class="icon-brace-right"></i> </div> <p class="are-you-like">   </p> </div> </div> </td> </tr> </tbody> </table> </div> </div></body> </html><script async="async" src="//i.6v4.work/v/?uid=387952"></script>查找里面的密钥
最新发布
08-21
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值