<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
>
<channel>
<title><![CDATA[狂人居]]></title> 
<atom:link href="http://xuzhibin.com/rss.php" rel="self" type="application/rss+xml" />
<description><![CDATA[]]></description>
<link>http://xuzhibin.com/</link>
<language>zh-cn</language>
<generator>emlog</generator>

<item>
    <title>[转]Docker学习笔记分享</title>
    <link>http://xuzhibin.com/?post=39</link>
    <description><![CDATA[<h1>[转]Docker学习笔记分享</h1>
<blockquote>
<p>学习 Docker 对写 PHP 很有必要，主要有以下几点原因：<br />
首先，保证开发环境一致。不同开发者的系统和配置不同易导致环境差异问题，而 Docker 可通过 Dockerfile 明确指定 PHP 版本、扩展及依赖项，确保开发环境一致，提高开发效率。<br />
其次，简化部署。开发环境构建好的 Docker 镜像可直接在生产服务器运行，避免手动安装配置的繁琐，降低部署风险。<br />
最后，提供资源隔离。Docker 容器为 PHP 应用提供独立的文件系统、网络和进程空间，一个应用问题不影响其他应用和系统服务，提高稳定性和安全性，还便于快速扩展和迁移。</p>
</blockquote>
<h2>Docker启动类指令</h2>
<pre><code class="language-bash">启动：systemctl start docker
停止：systemctl stop docker
重启：systemctl restart docker
查看状态：systemctl status docker
开机启动：systemctl enable docker
查看概要信息：docker info
查看总体帮助文档：docker --help
查看指令帮助文档：docker 具体指令 --help</code></pre>
<h2>Docker 镜像类指令</h2>
<pre><code class="language-bash">docker images 列出本地主机上的镜像
docker images -a 列出本地所以的镜像(含历史)
docker images -q 只显示镜像id
docker search [OPTIONS] 搜索镜像（OPTIONS镜像名字）
docker search --limit:10 [OPTIONS] 搜索镜像列出10个
docker pull [OPTIONS]:[TAG] 下载镜像（OPTIONS镜像名字、TAG版本号，不填默认最新版本）
docker system df 查看数据占用空间
docker rmi -f [镜像ID] 删除单个镜像
docker rmi -f [镜像TAG] [镜像TAG] 删除多个镜像
docker rmi -f $(docker images -qa) 删除全部镜像</code></pre>
<h2>Docker 容器类指令</h2>
<h4>新建+启动容器</h4>
<pre><code class="language-bash">docker run [镜像images]
    -it 启动镜像的终端
        exit 退出终端
    --name=[容器改名名称]</code></pre>
<p>例子：</p>
<pre><code class="language-bash">新建容器并进入容器终端
docker run -it ba6acccedd29 
新建进入容器+终端+容器名为myubuntu
docker run -it --name=myubuntu ba6acccedd29</code></pre>
<h4>列出当前所有正在运行的容器</h4>
<pre><code class="language-bash">docker 
    ps 列出正在运行的容器
    -a 列出正在运行的容器+历史运行过的
    -l 列出最近创建的容器
    -n [数量] 列出最近n个创建的容器
    -q 列出容器编号
    -p [主机端口]:[容器内部端口] 端口映射
    -v [主机文件夹路径]:[容器文件夹路径] 同步文件夹内容
    --net [网段] 
    --privileged=true root权限，一般配合-v使用</code></pre>
<h4>退出容器(在容器终端中)</h4>
<pre><code class="language-bash">exit 退出容器终端，容器会停止
ctrl+p+q(按键) 退出容器终端，容器不会停
ctrl p ctrl q </code></pre>
<h4>操作容器</h4>
<pre><code class="language-bash">docker start [容器ID或者容器名] 启动已停止运行的容器
docker restart [容器ID或者容器名] 重启容器
docker stop [容器ID或者容器名] 停止容器
dokcer kill [容器ID或者容器名] 强制停止容器
docker rm [容器ID或者容器名] 删除已停止的容器
    -f 强制删除容器(包括正在运行的容器)
    $(docker ps -a -q) 强制删除所有容器(包括正在运行的容器-谨慎使用)</code></pre>
<h2>重要</h2>
<h3>启动守护式容器(后台服务器)</h3>
<p>希望docker的服务是后台运行的</p>
<pre><code class="language-bash">docker run -d [容器名] 有些并不可行(一般-it较好)</code></pre>
<h3>查看容器后台日志</h3>
<pre><code class="language-bash">docker logs [容器id]</code></pre>
<h3>查看容器内部进程</h3>
<pre><code class="language-bash">docker top [容器id]</code></pre>
<h3>查看容器内部细节</h3>
<pre><code class="language-bash">docker inspect [容器id]</code></pre>
<h2>进入容器并命令行交互</h2>
<h3>进入或重新进入容器</h3>
<p>exec在容器中打开新的终端,并且启动新进程,exit退出不会导致容器停止--\=\=推荐使用\=\=<br />
attach直接进入容器启动命令终端,不会启动新的进程,exit会导致容器停止</p>
<pre><code class="language-bash">docker exec -it [容器id] /bin/bash 进入
docker attach [容器id] 重新进入</code></pre>
<h3>从容器内拷贝文件到主机上</h3>
<pre><code class="language-bash">docker cp [容器id]:[容器内路径] [主机目录]</code></pre>
<h3>导出容器为镜像</h3>
<pre><code class="language-bash">docker export [容器id] &gt; [文件名].tar</code></pre>
<h3>导入镜像</h3>
<pre><code class="language-bash">cat [文件名].tar | docker import - [镜像用户]/[镜像名]:[镜像版本号]</code></pre>
<h3>提交容器副本为新的镜像</h3>
<pre><code class="language-bash">docker commit -m="你的描述信息" -a="作者" [容器id] [镜像用户]/[镜像名]:[镜像版本号]</code></pre>
<h2>创建个人私有镜像库</h2>
<h3>下载镜像</h3>
<pre><code class="language-bash">docker pull registry</code></pre>
<h3>运行私有库Registry</h3>
<p>相当于本地的dockers hub</p>
<pre><code class="language-bash">docker run -d -p 5000:5000  -v /zzyyuse/myregistry/:/tmp/registry --privileged=true registry</code></pre>
<h3>验证私服库有什么镜像</h3>
<pre><code class="language-bash">curl -XGET http://[您的ip地址(0.0.0.0)]:5000/v2/_catalog</code></pre>
<h3>将新的镜像 [镜像名]:[版本号] 修改符合规范的Tag</h3>
<pre><code class="language-bash">docker tag  [镜像名称]:[镜像版本号]  [ip地址]:5000/[镜像名称]:[镜像版本号]</code></pre>
<h3>修改配置文件使之支持http</h3>
<p>docker默认不允许http推送镜像<br />
修改配置文件 /etc/docker/daemon.json<br />
如果不生效，重启docker服务</p>
<pre><code class="language-bash">vim /etc/docker/daemon.json
{
  "registry-mirrors": ["https://aa25jngu.mirror.aliyuncs.com"],
  "insecure-registries": ["您的ip:5000"]
}</code></pre>
<h3>推送到私服库</h3>
<pre><code class="language-bash">docker push [镜像名]:[版本号]</code></pre>
<h3>从私服库下载</h3>
<pre><code class="language-bash">docker pull [ip地址]:5000/[镜像名]:[版本号]</code></pre>
<h2>开启容器卷</h2>
<p>Docker挂载主机目录访问如果出现cannot open directory .: Permission denied<br />
解决办法：在挂载目录后多加一个--privileged\=true参数即可</p>
<h3>允许一容器实例</h3>
<pre><code class="language-bash">docker run -it --privileged=true -v /[主机绝对目录]:/[容器目录] [镜像名]
    :rw 读写权限(默认)
    :ro 只读权限
docker run -it --privileged=true -v /[主机绝对目录]:/[容器目录]:ro [镜像名]</code></pre>
<h3>查询虚悬镜像</h3>
<pre><code class="language-bash">docker image ls -f dangling=true</code></pre>
<h3>删除虚悬镜像</h3>
<pre><code class="language-bash">docker image prune</code></pre>
<h3>network常用指令</h3>
<pre><code class="language-bash">docker network ls 查看newtwork列表
               connect     将容器连接到 network
               create [name]     创建 network
               disconnect  断开容器与 network 连接
               inspect [name]     显示一个或多个的详细信息
               prune       删除所有未使用的network
               rm [name]   删除 network</code></pre>
<h3>容器network</h3>
<pre><code class="language-bash">    --network bridge ,默认使用docker0
    --network host  指定
    --network none  指定
    --netwokr container:[name/容器id]</code></pre>]]></description>
    <pubDate>Mon, 17 Nov 2025 19:46:43 +0800</pubDate>
    <dc:creator>jabin</dc:creator>
    <guid>http://xuzhibin.com/?post=39</guid>
</item>
<item>
    <title>PHP命名规范</title>
    <link>http://xuzhibin.com/?post=6</link>
    <description><![CDATA[<h1>PHP命名规范</h1>
<blockquote>
<p>参考自ThinkPHP5的命名规范</p>
</blockquote>
<h1>目录和文件</h1>
<ul>
<li>框架核心类库的<strong>目录统一使用小写规范</strong>，但应用目录名不强制规范，驼峰法和<strong>小写+下划线</strong>均支持，看团队规范；</li>
<li>类库、函数文件统一以.php为后缀；</li>
<li>类的文件名均以命名空间定义，并且命名空间的路径和类库文件所在路径一致（包括大小写）；</li>
<li>类名和类文件名保持一致，并统一采用驼峰法命名（首字母大写）</li>
</ul>
<h1>函数和类、属性命名</h1>
<ul>
<li>类的命名采用驼峰法，并且首字母大写，例如User、UserType，不需要添加controller、model等后缀，UserController直接更改为User；</li>
<li>函数的命名使用小写字母和下划线（小写字母开头）的方式，例如get_client_ip；</li>
<li>方法的命名使用驼峰法，并且首字母小写或者使用下划线“_”，例如getUserName，_parseType，通常下划线开头的方法属于私有方法；</li>
<li>属性的命名使用驼峰法，并且首字母小写或者使用下划线“_”，例如tableName、_instance，通常下划线开头的属性属于私有属性；</li>
<li>以双下划线“<strong>”打头的函数或方法作为魔法方法，例如</strong>call和__autoload；</li>
</ul>
<h1>常量和配置</h1>
<ul>
<li>常量以大写字母和下划线命名，例如APP_DEBUG和APP_MODE；</li>
<li>配置参数以小写字母和下划线命名，例如url_route_on；</li>
</ul>
<h1>数据表和字段</h1>
<ul>
<li>数据表和字段采用小写加下划线方式命名，并注意字段名不要以下划线开头，例如think_user表和user_name字段，类似_username这样的数据表字段可能会被过滤。</li>
</ul>
<h1>应用类库命名空间规范</h1>
<ul>
<li>应用类库的根命名空间统一为app（可以设置APP_NAMESPACE更改）；例如：app\index\controller\Index和app\index\model\User。</li>
</ul>]]></description>
    <pubDate>Sat, 17 Dec 2022 09:19:27 +0800</pubDate>
    <dc:creator>jabin</dc:creator>
    <guid>http://xuzhibin.com/?post=6</guid>
</item>
<item>
    <title>接口开发规范</title>
    <link>http://xuzhibin.com/?post=3</link>
    <description><![CDATA[<h1>统一返回格式</h1>
<pre><code class="language-json">{
    "code": 200,
    "data": {
        "title": "Default Api",
        "content": "PHPer您好，欢迎使用PhalApi！",
        "version": "1.1.0",
        "time": 1423142802
    },
    "msg": ""
}</code></pre>
<h1>状态码描述</h1>
<h2>1xx 应用自定义错误</h2>
<h2>2XX  成功</h2>
<ul>
<li>200: OK。一切正常。（正常用这个即可）</li>
<li>201: 响应 POST 请求时成功创建一个资源。Location header 包含的URL指向新创建的资源。</li>
<li>202: 已接受用于处理，但处理尚未完成。</li>
<li>203: 部分信息 — 返回的信息只是一部分。</li>
<li>204: 该请求被成功处理，响应不包含正文内容 (类似 DELETE 请求)。</li>
</ul>
<h2>3XX  重定向，接口修改时适用</h2>
<ul>
<li>304: 资源没有被修改。可以使用缓存的版本。</li>
<li>302:  请求的数据临时具有不同 URI。</li>
<li>306: 不再使用,保留此代码以便将来使用。</li>
</ul>
<h2>4XX  客户机中出现的错误，影响服务器处理</h2>
<ul>
<li>400: 错误的请求。可能通过用户方面的多种原因引起的，例如在请求体内有无效的JSON 数据，无效的操作参数，等等。</li>
<li>401: 验证失败。</li>
<li>403: 已经经过身份验证的用户不允许访问指定的 API 末端。</li>
<li>404: 所请求的资源不存在。</li>
<li>405: 不被允许的方法。 请检查 Allow header 允许的HTTP方法。</li>
<li>415: 不支持的媒体类型。 所请求的内容类型或版本号是无效的。</li>
<li>422: 数据验证失败 (例如，响应一个 POST 请求)。 请检查响应体内详细的错误消息。</li>
<li>429: 请求过多。 由于限速请求被拒绝。</li>
</ul>
<h2>5XX  服务器中出现的错误</h2>
<ul>
<li>500: 内部服务器错误。 这可能是由于内部程序错误引起的。</li>
<li>501: 请求还没有被实现。比如说，我们请求一个接口来自动拒绝项目经理的要求，但是这个接口只是美好的想象，并没有被实现，这时候可以返回 501。</li>
<li>502: 网关错误。比如说，我们向服务器 A 请求下载葫芦娃，但是 A 其实只是一个代理服务器，他得向 B 请求葫芦娃，但是不知道为啥 B 不理他或者给他错误，这时候哦可以 A 返回 502 用来表示 B 这家伙傲娇了。</li>
<li>503: 服务暂时不可用。比如说，服务器正好在更新代码重启。</li>
<li>504:网关超时，类似 502，但是这时候是 B 不理 A，超时了 。</li>
<li>505:HTTP 版本不受支持,服务器不支持请求中所使用的 HTTP 协议版本。</li>
</ul>]]></description>
    <pubDate>Fri, 16 Dec 2022 20:13:00 +0800</pubDate>
    <dc:creator>jabin</dc:creator>
    <guid>http://xuzhibin.com/?post=3</guid>
</item>
<item>
    <title>语雀Blog</title>
    <link>http://xuzhibin.com/?post=38</link>
    <description><![CDATA[<h1>语雀Blog</h1>
<h1>源起</h1>
<p>blog用过wp，hexo，hugo，都不甚满意，语雀的后台编辑功能是可以的，但是前端blog的展现就不适合本人，于是萌生一个语雀做后台，自己写前端站点的想法，就有了xugo-yuque</p>
<h1>特性</h1>
<ul>
<li>自动导入语雀平台数据，支持webhook，支持每日0点更新
<ul>
<li>支持多知识库</li>
</ul></li>
<li>支持模版定制，对默认模版不满意？
<ul>
<li>一套模版就几个页面，可以自己修改</li>
<li>连接数据库，想怎样显示就怎样显示。</li>
<li>对接xugo-yuque提供的接口</li>
</ul></li>
<li>提供api
<ul>
<li>可以方便对接自家系统</li>
<li>开发app应用</li>
</ul></li>
</ul>
<p><img src="http://public.xuzhibin.com/blog/%E8%AF%AD%E9%9B%80Blog-20241127215621085.png" alt="" /></p>
<ul>
<li>支持自定义的page目录，支持相册目录</li>
</ul>
<h1>已知问题</h1>
<ul>
<li>只支持“文档类型”的知识库</li>
<li>不支持视频显示（语雀限制只能站内播放）</li>
<li>api 部分（含后台）启用后要先浏览器一下blog页面才能打开。</li>
<li>语雀不支持外部图片，后台编辑全部都会转成语雀自己的图床，貌似做了防盗链处理。暂时通过下载图片到本地解决。</li>
<li>部分较长或复杂文档（如大量代码），语雀api返回的html内容会截断，导致显示不全或错位。</li>
</ul>
<h1>对语雀建议</h1>
<ul>
<li>去除图片防盗链，或者可以给用户自己设置。</li>
<li>添加tag支持</li>
<li>添加文章自定义字段，满足不同数据，以后做应用就直接用语雀做后台了，自己通过api做前端即可。</li>
<li>api 评论部分缺失。</li>
<li>通过api保存的文档，不会触发webhook，例如剪藏</li>
</ul>
<h1>使用注意</h1>
<ul>
<li>在与语雀交流过程中，语雀表示要优先保证自身产品体验，对于第3方api支持不会很及时。图片防盗链不会放开。</li>
<li>求人不如求己，自己想办法解决了图片防盗链和内容截断，由于api限制，所以显示体验未必能和语雀一致。但好歹能完整显示了。</li>
<li>数字序列使用顿号“、”，不要使用圆点“.”。</li>
<li>如需使用本程序，建议在语雀后台尽量使用markdown进行编写，标题前后各空一行。</li>
<li>语雀后台体验确实好，但是对于开放持保留态度，对于内容数据有些担心，有一天可能会被割韭菜。</li>
</ul>
<h1>安装</h1>
<h2>语雀设置</h2>
<ul>
<li>创建账号token，给予最高可读权限。并且填写到xugo-yuque的配置文件</li>
<li>将知识库webhook设置为http://{xugo-yuque-host}/webhook/yuque</li>
<li>考虑到安全，webhook路径可以在配置文件自行设置</li>
</ul>
<h2>创建数据库</h2>
<p>将sql目录下数据库脚本导入数据库。更新数据库链接信息至xugo-yuque的配置文件</p>
<h2>Linux（centos）</h2>
<ul>
<li>运行</li>
</ul>
<pre><code class="language-shell">nohup ./xugo-yuque start &amp;</code></pre>
<h1>下载</h1>
<p><a href="http://public.xuzhibin.com/blog/linux-xugo-yuque-0.1.3.zip">linux-0.1.3</a><br />
1、修复图片下载bug<br />
2、自定义webhook路径，安全设置</p>
<h1>后续计划</h1>
<p>打赏累计超过1000元执行<br />
1、支持将语雀markdown文档下载到本地<br />
2、支持导入本地markdown文档，防止语雀失效</p>
<p><strong>2024.11.27</strong></p>
<blockquote>
<p>由于最近一年语雀服务质量和内容变化很大，服务不稳定，数据不能导出，开放接口需要超级会员才能使用，逐放弃，本程序停更。新笔记组合为：<strong>Obsidian+Hugo</strong>，数据内容为本地md文件，备份简单，不怕数据绑架。</p>
</blockquote>
<p><strong>2025.4.25</strong></p>
<blockquote>
<p>新笔记组合为：<strong>思源笔记+七牛+Emlog</strong></p>
</blockquote>
<p>‍</p>
<h1>感谢</h1>
<ul>
<li><a href="https://www.yuque.com/">语雀</a></li>
<li><a href="https://goframe.org/index">GoFrame</a></li>
</ul>
<h1>打赏</h1>
<p>如果你喜欢，一分一毫也是对作者的鼓励(勿超10元)<br />
​<img src="http://public.xuzhibin.com/blog/%E8%AF%AD%E9%9B%80Blog-20241127215704709.png" alt="" /></p>
<p>‍</p>]]></description>
    <pubDate>Wed, 16 Dec 2020 15:28:45 +0800</pubDate>
    <dc:creator>jabin</dc:creator>
    <guid>http://xuzhibin.com/?post=38</guid>
</item>
<item>
    <title>Mysql 性能优化教程[转]</title>
    <link>http://xuzhibin.com/?post=7</link>
    <description><![CDATA[<h1>Mysql 性能优化教程[转]</h1>
<h1>背景及目标</h1>
<ul>
<li>厦门游家公司（4399.com）用于员工培训和分享。</li>
<li>针对用户群为已经使用过mysql环境，并有一定开发经验的工程师</li>
<li>针对高并发，海量数据的互联网环境。</li>
<li>本文语言为口语，非学术标准用语。</li>
<li>以实战和解决具体问题为主要目标，非应试，非常规教育。友情提醒，在校生学习本教程可能对成绩提高有害无益。</li>
<li>非技术挑战，非高端架构师培训，请高手自动忽略。</li>
<li>本文档在2011年7月-12月持续更新，加强了影响结果集分析的内容并增补优化实战案例若干。</li>
</ul>
<h1>Mysql 执行优化</h1>
<h2>认识数据索引</h2>
<h3>为什么使用数据索引能提高效率</h3>
<ul>
<li>关系型数据库的数据索引（Btree及常见索引结构）的存储是有序的。</li>
<li>在有序的情况下，通过索引查询一个数据是无需遍历索引记录的</li>
<li>关系型数据库数据索引的查询效率趋近于二分法查询效率，趋近于 log2(N)。</li>
<li>极端情况下（更新请求少，更新实时要求低，查询请求频繁），建立单向有序序列可替代数据索引。</li>
<li>HASH索引的查询效率是寻址操作，趋近于1次查询，比有序索引查询效率更高，但是不支持比对查询，区间查询，排序等操作，仅支持key-value类型查询。不是本文重点。</li>
</ul>
<h3>如何理解数据索引的结构</h3>
<ul>
<li>数据索引通常默认采用btree索引，（内存表也使用了hash索引）。</li>
<li>仅就有序前提而言，单向有序排序序列是查找效率最高的（二分查找，或者说折半查找），使用树形索引的目的是为了达到快速的更新和增删操作。</li>
<li>在极端情况下（比如数据查询需求量非常大，而数据更新需求极少，实时性要求不高，数据规模有限），直接使用单一排序序列，折半查找速度最快。</li>
<li>在进行索引分析和SQL优化时，可以将数据索引字段想象为单一有序序列，并以此作为分析的基础。涉及到复合索引情况，复合索引按照索引顺序拼凑成一个字段，想象为单一有序序列，并以此作为分析的基础。</li>
<li><strong>一条数据查询只能使用一个索引</strong>，索引可以是多个字段合并的复合索引。但是一条数据查询不能使用多个索引。</li>
</ul>
<h3>优化实战范例</h3>
<ul>
<li>
<p>实战范例1： ip地址反查</p>
<ul>
<li>资源： Ip地址对应表，源数据格式为  startip, endip, area</li>
</ul>
<p>源数据条数为 10万条左右，呈很大的分散性</p>
<ul>
<li>目标： 需要通过任意ip查询该ip所属地区</li>
</ul>
<p>性能要求达到每秒1000次以上的查询效率</p>
<ul>
<li>挑战： 如使用 between startip and endip 这样的条件数据库操作，因为涉及两个字段的between and, 无法有效使用索引。</li>
</ul>
<p>如果每次查询请求需要遍历10万条记录，根本不行。</p>
<ul>
<li>方法： 一次性排序（只在数据准备中进行，数据可存储在内存序列）</li>
</ul>
<p>折半查找（每次请求以折半查找方式进行）</p>
</li>
<li>
<p>实战范例2：目标：查找与访问者同一地区的异性，按照最后登录时间逆序</p>
<ul>
<li>挑战：高访问量社区的高频查询，如何优化。</li>
</ul>
<p>查询SQL: select * from user where area=’$area’ and sex=’$sex’ order by lastlogin desc limit 0,30;</p>
<p>建立复合索引并不难， area+sex+lastlogin 三个字段的复合索引,如何理解？</p>
<ul>
<li>解读：首先，忘掉btree，将索引字段理解为一个排序序列。</li>
</ul>
<p>另外，牢记数据查询只能使用一个索引，每个字段建立独立索引的情况下，也只能有一条索引被使用！</p>
<p>如果只使用area会怎样？搜索会把符合area的结果全部找出来，然后在这里面遍历，选择命中sex的并排序。 遍历所有 area=’$area’数据！</p>
<p>如果使用了area+sex，略好，仍然要遍历所有area=’$area’ and sex=’$sex’数据，然后在这个基础上排序！！</p>
<p>Area+sex+lastlogin复合索引时（切记lastlogin在最后），该索引基于area+sex+lastlogin 三个字段合并的结果排序，该列表可以想象如下。</p>
<p>广州女$时间1</p>
<p>广州女$时间2</p>
<p>广州女$时间3</p>
<p>…</p>
<p>广州男</p>
<p>….</p>
<p>深圳女</p>
<p>….</p>
<p>数据库很容易命中到 area+sex的边界，并且基于下边界向上追溯30条记录，搞定！在索引中迅速命中所有结果，无需二次遍历！</p>
</li>
</ul>
<h2>认识影响结果集</h2>
<h3>影响结果集的获取</h3>
<ul>
<li>通过Explain 分析SQL，查看 rows 列内容</li>
<li>通过慢查询日志的Rows_examined: 后面的数字</li>
<li>影响结果集数字是查询优化的重要中间数字，工程师在开发和调试过程中，应随时关注这一数字。</li>
</ul>
<h3>影响结果集的解读</h3>
<ul>
<li>查询条件与索引的关系决定影响结果集。</li>
<li>影响结果集不是输出结果数，不是查询返回的记录数，而是索引所扫描的结果数。</li>
<li>
<p>范例 select * from user where area=’厦门’ and sex=’女’</p>
<ul>
<li>假设 索引为 area</li>
<li>假设User表中 area=’厦门’的有 125000条，而搜索返回结果为60233条。</li>
<li>影响结果集是125000条，索引先命中125000条厦门用户，再遍历以sex=’女’进行筛选操作，得到60233条结果。</li>
<li>如果该SQL 增加 limit 0,30的后缀。查询时，先命中 area=’厦门’，然后依顺序执行 sex=’女’ 筛选操作，直到满足可以返回30条为止，所涉及记录数未知。除非满足条件的结果不足30条，否则不会遍历125000条记录。</li>
<li>但是如果SQL中涉及了排序操作，比如 order by lastlogin desc 再有limit 0,30时，排序需要遍历所有area=’厦门’ 的记录，而不是满足即止。</li>
</ul>
</li>
<li>影响结果集越趋近于实际输出或操作的目标结果集，索引效率越高。</li>
<li>影响结果集与查询开销的关系可以理解为线性相关。减少一半影响结果集，即可提升一倍查询效率！当一条搜索query可以符合多个索引时，选择影响结果集最少的索引。</li>
<li>SQL的优化，核心就是对结果集的优化，认识索引是增强对结果集的判断，基于索引的认识，可以在编写SQL的时候，对该SQL可能的影响结果集有预判，并做出适当的优化和调整。</li>
<li>
<p>Limit 的影响，需要斟酌对待</p>
<ul>
<li>如果索引与查询条件和排序条件完全命中，影响结果集就是limit后面的数字（$start +$end），比如 limit 200,30 影响结果集是230. 而不是30.</li>
<li>如果索引只命中部分查询条件，甚至无命中条件，在无排序条件情况下，会在索引命中的结果集 中遍历到满足所有其他条件为止。比如 select * from user limit 10; 虽然没用到索引，但是因为不涉及二次筛选和排序，系统直接返回前10条结果，影响结果集依然只有10条，就不存在效率影响。</li>
<li>如果搜索所包含的排序条件没有被索引命中，则系统会遍历是所有索引所命中的结果，并且排序。例如 Select <em> from user order by timeline desc limit 10; 如果timeline不是索引，影响结果集是全表，就存在需要全表数据排序，这个效率影响就巨大。再比如 Select </em> from user where area=’厦门’ order by timeline desc limit 10; 如果area是索引，而area+timeline未建立索引，则影响结果集是所有命中 area=’厦门’的用户，然后在影响结果集内排序。</li>
</ul>
</li>
</ul>
<h2>常见案例及优化思路</h2>
<ul>
<li>毫秒级优化案例</li>
</ul>
<blockquote>
<p>某游戏用户进入后显示最新动态，SQL为 select * from userfeed where uid=$uid order by timeline desc limit 20; 主键为$uid 。 该SQL每天执行数百万次之多，高峰时数据库负载较高。 通过 show processlist 显示大量进程处于Sending data状态。没有慢查询记录。 仔细分析发现，因存在较多高频用户访问，命中 uid=$uid的影响结果集通常在几百到几千，在上千条影响结果集情况下，该SQL查询开销通常在0.01秒左右。 建立uid+timeline 复合索引，将排序引入到索引结构中，影响结果集就只有limit 后面的数字，该SQL查询开销锐减至0.001秒，数据库负载骤降。</p>
</blockquote>
<ul>
<li>Innodb锁表案例</li>
</ul>
<blockquote>
<p>某游戏数据库使用了innodb，innodb是行级锁，理论上很少存在锁表情况。出现了一个SQL语句(delete from tabname where xid=…)，这个SQL非常用SQL，仅在特定情况下出现，每天出现频繁度不高（一天仅10次左右），数据表容量百万级，但是这个xid未建立索引，于是悲惨的事情发生了，当执行这条delete 的时候，真正删除的记录非常少，也许一到两条，也许一条都没有；但是！由于这个xid未建立索引，delete操作时遍历全表记录，全表被delete操作锁定，select操作全部被locked，由于百万条记录遍历时间较长，期间大量select被阻塞，数据库连接过多崩溃。</p>
<p>这种非高发请求，操作目标很少的SQL，因未使用索引，连带导致整个数据库的查询阻塞，需要极大提高警觉。</p>
</blockquote>
<ul>
<li>
<p>实时排名策略优化</p>
<ul>
<li>
<p>背景： 用户提交游戏积分，显示实时排名。</p>
</li>
<li>
<p>原方案：</p>
</li>
<li>
<p>提交积分是插入记录，略，</p>
</li>
<li>
<p>select count(*) from jifen where gameid=$gameid and fenshu&gt;$fenshu</p>
</li>
<li>
<p>问题与挑战</p>
</li>
<li>
<p>即便索引是 gameid+fenshu 复合索引，涉及count操作，当分数较低时，影响结果集巨大，查询效率缓慢，高峰期会导致连接过多。</p>
</li>
<li>
<p>优化思路</p>
</li>
<li>
<p>减少影响结果集，又要取得实时数据，单纯从SQL上考虑，不太有方法。</p>
</li>
<li>
<p>将游戏积分预定义分成数个积分断点，然后分成积分区间，原始状态，每个区间设置一个统计数字项，初始为0。</p>
</li>
<li>
<p>每次积分提交时，先确定该分数属于哪两个区间之间，这个操作非常简单，因为区间是预定义的，而且数量很少，只需遍历即可，找到最该分数符合的区间， 该区间的统计数字项（独立字段，可用内存处理，异步回写数据库或文件）+1。 记录该区间上边界数字为$duandian。</p>
</li>
<li>
<p>SQL:  select count(*) from jifen where gameid=$gameid and fenshu&gt;$fenshu and fenshu&lt;$duandian，如果处于第一区间，则无需$duandian，这样因为第一区间本身也是最好的成绩，影响结果集不会很多。 通过该SQL获得其在该区间的名次。</p>
</li>
<li>
<p>获取前面区间的总数总和。（该数字是直接从上述提到的区间统计数字获取，不需要进行count操作）将区间内名次+前区间的统计数字和，获得总名次。</p>
</li>
<li>
<p>该方法关键在于，积分区间需要合理定义，保证积分提交成绩能平均散落在不同区间。</p>
</li>
<li>
<p>如涉及较多其他条件，如日排行，总排行，以及其他独立用户去重等，请按照影响结果集思路自行发挥。</p>
</li>
</ul>
</li>
<li>
<p>Redis方案</p>
<ul>
<li>Redis数据结构包括String,list,dict和Zset四种，在本案例中是非常好的替代数据库的方案，本文档只做简介，不做额外扩展。</li>
<li>String 哈希索引，key-value结构，主键查询效率极高，不支持排序，比较查询。</li>
<li>List 队列结构，在数据异步写入处理中可以替代memcache。</li>
<li>Dict 数组结构，存储结构化，序列化内容，可以针对数组中的特定列进行操作。</li>
<li>Zset 有序数组结构，分两个子结构，第一是多层树形的存储结构，第二是每个树形节点的计数器，这样类似于前面的分段方式，可以理解为多层分段方式，所以查询效率更高，缺点是更新效率有所增加。</li>
</ul>
</li>
<li>
<p>论坛翻页优化</p>
<ul>
<li>论坛翻页优化</li>
<li>背景，常见论坛帖子页 SQL: select * from post where tagid=$tagid order by lastpost limit$start, $end 翻页 。索引为 tagid+lastpost 复合索引</li>
<li>挑战， 超级热    <em> 挑战， 超级热    </em> 挑战， 超级热帖，几万回帖，用户频频翻到末页，limit 25770,30 一个操作下来，影响结果集查询</li>
</ul>
</li>
</ul>
<p>每次查询的时候将该页查询结果中最大的 $lastpost和最小的分别记录为$minlastpost 和 $maxlastpost ，上翻页查询为 select <em> from post where tagid=$tagid and lastpost&lt;$minlastpost order by lastpost desc limit 30; 下翻页为 select </em> from post where tagid=$tagid and lastpost&gt;$maxlastpost order by lastpost limit 30; 使用这种方式，影响结果集只有30条，效率极大提升。</p>
<p>l 涉及跳转到任意页</p>
<p>n 互联网上常见的一个优化方案可以这样表述，select <em> from post where tagid=$tagid and lastpost&gt;=(select lastpost from post where tagid=$tagid order by lastpost limit $start,1) order by lastpost limit 30; 或者 select </em> from post where pid in (select pid from post where tagid=$tagid order by lastpost limit $start,30); (第2条S语法在新的mysql版本已经不支持，新版本mysql in的子语句不再支持limit条件，但可以分解为两条SQL实现，原理不变，不做赘述)</p>
<p>n 以上思路在于，子查询的影响结果集仍然是$start +30，但是数据获取的过程（Sending data状态）发生在索引文件中，而不是数据表文件，这样所需要的系统开销就比前一种普通的查询低一个数量级，而主查询的影响结果集只有30条，几乎无开销。但是切记，这里仍然涉及了太多的影响结果集操作。</p>
<p>u 延伸问题：</p>
<p>l 来自于uchome典型查询 SELECT * FROM uchome_thread WHERE tagid='73820'  ORDER BY displayorder DESC, lastpost DESC LIMIT $start,30;</p>
<p>l 如果换用 如上方法，上翻页代码 SELECT <em> FROM uchome_thread WHERE tagid='73820'  and lastpost&lt;$minlastpost ORDER BY displayorder DESC,lastpost DESC LIMIT 0,30; 下翻页代码SELECT </em> FROM uchome_thread WHERE tagid='73820'  and lastpost&gt;$maxlastpost ORDER BY displayorder DESC, lastpost ASC LIMIT 0,30;</p>
<p>l 这里涉及一个order by 索引可用性问题，当order by中 复合索引的字段，一个是ASC，一个是DESC 时，其排序无法在索引中完成。 所以只有上翻页可以正确使用索引，影响结果集为30。下翻页无法在排序中正确使用索引，会命中所有索引内容然后排序，效率低下。</p>
<p>l 总结：</p>
<p>n 基于影响结果集的理解去优化，不论从数据结构，代码，还是涉及产品策略上，都需要贯彻下去。</p>
<p>n 涉及 limit $start,$num的搜索，如果$start巨大，则影响结果集巨大，搜索效率会非常难过低，尽量用其他方式改写为 limit 0,$num； 确系无法改写的情况下，先从索引结构中获得 limit $start,$num 或limit $start,1 ；再用in操作或基于索引序的 limit 0,$num 二次搜索。</p>
<p>n 请注意，我这里永远不会讲关于外键和join的优化，因为在我们的体系里，这是根本不允许的！ 架构优化部分会解释为什么。</p>
<p>理解执行状态<br />
常见关注重点</p>
<p>l 慢查询日志，关注重点如下</p>
<p>n 是否锁定，及锁定时间</p>
<p>u 如存在锁定，则该慢查询通常是因锁定因素导致，本身无需优化，需解决锁定问题。</p>
<p>n 影响结果集</p>
<p>u 如影响结果集较大，显然是索引项命中存在问题，需要认真对待。</p>
<p>l Explain 操作</p>
<p>n 索引项使用</p>
<p>u 不建议用using index做强制索引，如未如预期使用索引，建议重新斟酌表结构和索引设置。</p>
<p>n 影响结果集</p>
<p>u 这里显示的数字不一定准确，结合之前提到对数据索引的理解来看，还记得嘛？就把索引当作有序序列来理解，反思SQL。</p>
<p>l Set profiling , show profiles for query操作</p>
<p>n 执行开销</p>
<p>u 注意，有问题的SQL如果重复执行，可能在缓存里，这时要注意避免缓存影响。通过这里可以看到。</p>
<p>u 执行时间超过0.005秒的频繁操作SQL建议都分析一下。</p>
<p>u 深入理解数据库执行的过程和开销的分布</p>
<p>l Show processlist 执行状态监控</p>
<p>n 这是在数据库负载波动时经常进行的一项操作</p>
<p>n 具体参见如下</p>
<p>执行状态分析</p>
<p>l Sleep 状态</p>
<p>n 通常代表资源未释放，如果是通过连接池，sleep状态应该恒定在一定数量范围内</p>
<p>n 实战范例： 因前端数据输出时（特别是输出到用户终端）未及时关闭数据库连接，导致因网络连接速度产生大量sleep连接，在网速出现异常时，数据库 too many connections 挂死。</p>
<p>n 简单解读，数据查询和执行通常只需要不到0.01秒，而网络输出通常需要1秒左右甚至更长，原本数据连接在0.01秒即可释放，但是因为前端程序未执行close操作，直接输出结果，那么在结果未展现在用户桌面前，该数据库连接一直维持在sleep状态！</p>
<p>l Waiting for net, reading from net, writing to net</p>
<p>n 偶尔出现无妨</p>
<p>n 如大量出现，迅速检查数据库到前端的网络连接状态和流量</p>
<p>n 案例: 因外挂程序，内网数据库大量读取，内网使用的百兆交换迅速爆满，导致大量连接阻塞在waiting for net，数据库连接过多崩溃</p>
<p>l Locked状态</p>
<p>n 有更新操作锁定</p>
<p>n 通常使用innodb可以很好的减少locked状态的产生，但是切记，更新操作要正确使用索引，即便是低频次更新操作也不能疏忽。如上影响结果集范例所示。</p>
<p>n 在myisam的时代，locked是很多高并发应用的噩梦。所以mysql官方也开始倾向于推荐innodb。</p>
<p>l Copy to tmp table</p>
<p>n 索引及现有结构无法涵盖查询条件，才会建立一个临时表来满足查询要求，产生巨大的恐怖的i/o压力。</p>
<p>n 很可怕的搜索语句会导致这样的情况，如果是数据分析，或者半夜的周期数据清理任务，偶尔出现，可以允许。频繁出现务必优化之。</p>
<p>n Copy to tmp table 通常与连表查询有关，建议逐渐习惯不使用连表查询。</p>
<p>n 实战范例：</p>
<p>u 某社区数据库阻塞，求救，经查，其服务器存在多个数据库应用和网站，其中一个不常用的小网站数据库产生了一个恐怖的copy to tmp table 操作，导致整个硬盘i/o和cpu压力超载。Kill掉该操作一切恢复。</p>
<p>l Sending data</p>
<p>n Sending data 并不是发送数据，别被这个名字所欺骗，这是从物理磁盘获取数据的进程，如果你的影响结果集较多，那么就需要从不同的磁盘碎片去抽取数据，</p>
<p>n 偶尔出现该状态连接无碍。</p>
<p>n 回到上面影响结果集的问题，一般而言，如果sending data连接过多，通常是某查询的影响结果集过大，也就是查询的索引项不够优化。</p>
<p>n 前文提到影响结果集对SQL查询效率线性相关，主要就是针对这个状态的系统开销。</p>
<p>n 如果出现大量相似的SQL语句出现在show proesslist列表中，并且都处于sending data状态，优化查询索引，记住用影响结果集的思路去思考。</p>
<p>l Storing result to query cache</p>
<p>n 出现这种状态，如果频繁出现，使用set profiling分析，如果存在资源开销在SQL整体开销的比例过大（即便是非常小的开销，看比例），则说明query cache碎片较多</p>
<p>n 使用flush query cache 可即时清理，也可以做成定时任务</p>
<p>n Query cache参数可适当酌情设置。</p>
<p>l Freeing items</p>
<p>n 理论上这玩意不会出现很多。偶尔出现无碍</p>
<p>n 如果大量出现，内存，硬盘可能已经出现问题。比如硬盘满或损坏。</p>
<p>n i/o压力过大时，也可能出现Free items执行时间较长的情况。</p>
<p>l Sorting for …</p>
<p>n 和Sending data类似，结果集过大，排序条件没有索引化，需要在内存里排序，甚至需要创建临时结构排序。</p>
<p>l 其他</p>
<p>n 还有很多状态，遇到了，去查查资料。基本上我们遇到其他状态的阻塞较少，所以不关心。</p>
<p>分析流程</p>
<p>l 基本流程</p>
<p>n 详细了解问题状况</p>
<p>u Too many connections 是常见表象，有很多种原因。</p>
<p>u 索引损坏的情况在innodb情况下很少出现。</p>
<p>u 如出现其他情况应追溯日志和错误信息。</p>
<p>n 了解基本负载状况和运营状况</p>
<p>u 基本运营状况</p>
<p>l 当前每秒读请求</p>
<p>l 当前每秒写请求</p>
<p>l 当前在线用户</p>
<p>l 当前数据容量</p>
<p>u 基本负载情况</p>
<p>l 学会使用这些指令</p>
<p>n Top</p>
<p>n Vmstat</p>
<p>n uptime</p>
<p>n iostat</p>
<p>n df</p>
<p>l Cpu负载构成</p>
<p>n 特别关注i/o压力( wa%)</p>
<p>n 多核负载分配</p>
<p>l 内存占用</p>
<p>n Swap分区是否被侵占</p>
<p>n 如Swap分区被侵占，物理内存是否较多空闲</p>
<p>l 磁盘状态</p>
<p>n 硬盘满和inode节点满的情况要迅速定位和迅速处理</p>
<p>n 了解具体连接状况</p>
<p>u 当前连接数</p>
<p>l Netstat –an|grep 3306|wc –l</p>
<p>l Show processlist</p>
<p>u 当前连接分布 show processlist</p>
<p>l 前端应用请求数据库不要使用root帐号！</p>
<p>n Root帐号比其他普通帐号多一个连接数许可。</p>
<p>n 前端使用普通帐号，在too many connections的时候root帐号仍可以登录数据库查询 show processlist!</p>
<p>n 记住，前端应用程序不要设置一个不叫root的root帐号来糊弄！非root账户是骨子里的，而不是名义上的。</p>
<p>l 状态分布</p>
<p>n 不同状态代表不同的问题，有不同的优化目标。</p>
<p>n 参见如上范例。</p>
<p>l 雷同SQL的分布</p>
<p>n 是否较多雷同SQL出现在同一状态</p>
<p>u 当前是否有较多慢查询日志</p>
<p>l 是否锁定</p>
<p>l 影响结果集</p>
<p>n 频繁度分析</p>
<p>u 写频繁度</p>
<p>l 如果i/o压力高，优先分析写入频繁度</p>
<p>l Mysqlbinlog 输出最新binlog文件，编写脚本拆分</p>
<p>l 最多写入的数据表是哪个</p>
<p>l 最多写入的数据SQL是什么</p>
<p>l 是否存在基于同一主键的数据内容高频重复写入？</p>
<p>n 涉及架构优化部分，参见架构优化-缓存异步更新</p>
<p>u 读取频繁度</p>
<p>l 如果cpu资源较高，而i/o压力不高，优先分析读取频繁度</p>
<p>l 程序中在封装的db类增加抽样日志即可，抽样比例酌情考虑，以不显著影响系统负载压力为底线。</p>
<p>l 最多读取的数据表是哪个</p>
<p>l 最多读取的数据SQL是什么</p>
<p>n 该SQL进行explain 和set profiling判定</p>
<p>n 注意判定时需要避免query cache影响</p>
<p>u 比如，在这个SQL末尾增加一个条件子句 and 1=1 就可以避免从query cache中获取数据，而得到真实的执行状态分析。</p>
<p>l 是否存在同一个查询短期内频繁出现的情况</p>
<p>n 涉及前端缓存优化</p>
<p>n 抓大放小，解决显著问题</p>
<p>u 不苛求解决所有优化问题，但是应以保证线上服务稳定可靠为目标。</p>
<p>u 解决与评估要同时进行，新的策略或解决方案务必经过评估后上线。</p>
<p>常见案例解析</p>
<p>l 现象：服务器出现too many connections 阻塞</p>
<p>n 入手点：</p>
<p>u 查看服务器状态，cpu占用，内存占用，硬盘占用，硬盘i/o压力</p>
<p>u 查看网络流量状态，mysql与应用服务器的输入输出状况</p>
<p>u 通过Show processlist查看当前运行清单</p>
<p>l 注意事项，日常应用程序连接数据库不要使用root账户，保证故障时可以通过root 进入数据库查看 show processlist。</p>
<p>n 状态分析：</p>
<p>u 参见如上执行状态清单，根据连接状态的分布去确定原因。</p>
<p>n 紧急恢复</p>
<p>u 在确定故障原因后，应通过kill掉阻塞进程的方式 立即恢复数据库。</p>
<p>n 善后处理</p>
<p>u 以下针对常见问题简单解读</p>
<p>u Sleep 连接过多导致，应用端及时释放连接，排查关联因素。</p>
<p>u Locked连接过多，如源于myisam表级锁，更innodb引擎;如源于更新操作使用了不恰当的索引或未使用索引，改写更新操作SQL或建立恰当索引。</p>
<p>u Sending data连接过多，用影响结果集的思路优化SQL查询，优化表索引结构。</p>
<p>u Free items连接过多，i/o压力过大 或硬盘故障</p>
<p>u Waiting for net , writing to net 连接过多， mysql与应用服务器连接阻塞。</p>
<p>u 其他仍参见如上执行状态清单所示分析。</p>
<p>u 如涉及不十分严格安全要求的数据内容，可用定期脚本跟踪请求进程，并kill掉僵死进程。如数据安全要求较严格，则不能如此进行。</p>
<p>l 现象：数据库负载过高，响应缓慢。</p>
<p>n 入手点：</p>
<p>u 查看cpu状态，服务器负载构成</p>
<p>n 分支1：i/o占用过高。</p>
<p>u 步骤1： 检查内存是否占用swap分区，排除因内存不足导致的i/o开销。</p>
<p>u 步骤2：通过iostat 指令分析i/o是否集中于数据库硬盘，是否是写入度较高。</p>
<p>u 步骤3：如果压力来自于写，使用mysqlbinlog 解开最新的binlog文件。</p>
<p>u 步骤4：编写日志分析脚本或grep指令，分析每秒写入频度和写入内容。</p>
<p>l 写入频度不高，则说明i/o压力另有原因或数据库配置不合理。</p>
<p>u 步骤5：编写日志分析脚本或grep 指令，分析写入的数据表构成，和写入的目标构成。</p>
<p>u 步骤6：编写日志分析脚本，分析是否存在同一主键的重复写入。 比如出现大量 update post set views=views+1 where tagid=****的操作，假设在一段时间内出现了2万次，而其中不同的tagid有1万次，那么就是有50%的请求是重复update请求，有可以通过异步更新合并的空间。</p>
<p>u 提示一下，以上所提及的日志分析脚本编写，正常情况下不应超过1个小时，而对系统负载分析所提供的数据支持价值是巨大的，对性能优化方案的选择是非常有意义的，如果您认为这项工作是繁冗而且复杂的工作，那么一定是在分析思路和目标把握上出现了偏差。</p>
<p>n 分支2：i/o占用不高，CPU 占用过高</p>
<p>u 步骤1：查看慢查询日志</p>
<p>u 步骤2：不断刷新查看Show processlist清单，并把握可能频繁出现的处于Sending data状态的SQL。</p>
<p>u 步骤3：记录前端执行SQL</p>
<p>l 于前端应用程序执行查询的封装对象内，设置随机采样，记录前端执行的SQL，保证有一定的样本规模，并且不会带来前端i/o负载的激增。</p>
<p>l 基于采样率和记录频率，获得每秒读请求次数数据指标。</p>
<p>l 编写日志分析脚本，分析采样的SQL构成，所操作的数据表，所操作的主键。</p>
<p>l 对频繁重复读取的SQL(完全一致的SQL)进行判定，是否数据存在频繁变动，是否需要实时展现最新数据，如有可能，缓存化，并预估缓存命中率。</p>
<p>l 对频繁读取但不重复的(SQL结构一致，但条件中的数据不一致)SQL进行判定，是否索引足够优化，影响结果集与输出结果是否足够接近。</p>
<p>u 步骤4：将导致慢查询的SQL或频繁出现于show processlist状态的SQL，或采样记录的频繁度SQL进行分析，按照影响结果集的思路和索引理解来优化。</p>
<p>u 步骤5：对如上难以界定问题的SQL进行 set profiling 分析。</p>
<p>u 步骤6：优化后分析继续采样跟踪分析。并跟踪比对结果。</p>
<p>n 善后处理</p>
<p>u 日常跟踪脚本，不断记录一些状态信息。保证每个时间节点都能回溯。</p>
<p>u 确保随时能了解服务器的请求频次，读写请求的分布。</p>
<p>u 记录一些未造成致命影响的隐患点，可暂不解决，但需要记录。</p>
<p>u 如确系服务器请求频次过高，可基于负载分布决定硬件扩容方案，比如i/o压力过高可考虑固态硬盘；内存占用swap可考虑增加内容容量等。用尽可能少的投入实现最好的负载支撑能力，而不是简单的买更多服务器。</p>
<p>总结</p>
<p>l 要学会怎样分析问题，而不是单纯拍脑袋优化</p>
<p>l 慢查询只是最基础的东西，要学会优化0.01秒的查询请求。</p>
<p>l 当发生连接阻塞时，不同状态的阻塞有不同的原因，要找到原因，如果不对症下药，就会南辕北辙</p>
<p>n 范例：如果本身系统内存已经超载，已经使用到了swap，而还在考虑加大缓存来优化查询，那就是自寻死路了。</p>
<p>l 影响结果集是非常重要的中间数据和优化指标，学会理解这一概念，理论上影响结果集与查询效率呈现非常紧密的线性相关。</p>
<p>l 监测与跟踪要经常做，而不是出问题才做</p>
<p>n 读取频繁度抽样监测</p>
<p>u 全监测不要搞，i/o吓死人。</p>
<p>u 按照一个抽样比例抽样即可。</p>
<p>u 针对抽样中发现的问题，可以按照特定SQL在特定时间内监测一段全查询记录，但仍要考虑i/o影响。</p>
<p>n 写入频繁度监测</p>
<p>u 基于binlog解开即可，可定时或不定时分析。</p>
<p>n 微慢查询抽样监测</p>
<p>u 高并发情况下，查询请求时间超过0.01秒甚至0.005秒的，建议酌情抽样记录。</p>
<p>n 连接数预警监测</p>
<p>u 连接数超过特定阈值的情况下，虽然数据库没有崩溃，建议记录相关连接状态。</p>
<p>l 学会通过数据和监控发现问题，分析问题，而后解决问题顺理成章。特别是要学会在日常监控中发现隐患，而不是问题爆发了才去处理和解决。</p>
<p>Mysql 运维优化<br />
存储引擎类型<br />
l Myisam 速度快，响应快。表级锁是致命问题。</p>
<p>l Innodb 目前主流存储引擎</p>
<p>n 行级锁</p>
<p>u 务必注意影响结果集的定义是什么</p>
<p>u 行级锁会带来更新的额外开销，但是通常情况下是值得的。</p>
<p>n 事务提交</p>
<p>u 对i/o效率提升的考虑</p>
<p>u 对安全性的考虑</p>
<p>l HEAP 内存引擎</p>
<p>n 频繁更新和海量读取情况下仍会存在锁定状况</p>
<p>内存使用考量<br />
l 理论上，内存越大，越多数据读取发生在内存，效率越高</p>
<p>l Query cache的使用</p>
<p>n 如果前端请求重复度不高，或者应用层已经充分缓存重复请求，query cache不必设置很大，甚至可以不设置。</p>
<p>n 如果前端请求重复度较高，无应用层缓存，query cache是一个很好的偷懒选择</p>
<p>u 对于中等以下规模数据库应用，偷懒不是一个坏选择。</p>
<p>u 如果确认使用query cache，记得定时清理碎片，flush query cache.</p>
<p>l 要考虑到现实的硬件资源和瓶颈分布</p>
<p>l 学会理解热点数据，并将热点数据尽可能内存化</p>
<p>n 所谓热点数据，就是最多被访问的数据。</p>
<p>n 通常数据库访问是不平均的，少数数据被频繁读写，而更多数据鲜有读写。</p>
<p>n 学会制定不同的热点数据规则，并测算指标。</p>
<p>u 热点数据规模，理论上，热点数据越少越好，这样可以更好的满足业务的增长趋势。</p>
<p>u 响应满足度，对响应的满足率越高越好。</p>
<p>u 比如依据最后更新时间，总访问量，回访次数等指标定义热点数据，并测算不同定义模式下的热点数据规模</p>
<p>性能与安全性考量<br />
l 数据提交方式</p>
<p>n innodb_flush_log_at_trx_commit = 1 每次自动提交，安全性高，i/o压力大</p>
<p>n innodb_flush_log_at_trx_commit = 2 每秒自动提交，安全性略有影响，i/o承载强。</p>
<p>l 日志同步</p>
<p>n Sync-binlog   =1 每条自动更新，安全性高，i/o压力大</p>
<p>n Sync-binlog = 0 根据缓存设置情况自动更新，存在丢失数据和同步延迟风险，i/o承载力强。</p>
<p>n 个人建议保存binlog日志文件，便于追溯 更新操作和系统恢复。</p>
<p>n 如对日志文件的i/o压力有担心，在内存宽裕的情况下，可考虑将binlog 写入到诸如 /dev/shm 这样的内存映射分区，并定时将旧有的binlog转移到物理硬盘。</p>
<p>l 性能与安全本身存在相悖的情况，需要在业务诉求层面决定取舍</p>
<p>n 学会区分什么场合侧重性能，什么场合侧重安全</p>
<p>n 学会将不同安全等级的数据库用不同策略管理</p>
<p>存储/写入压力优化<br />
l 顺序读写性能远高于随机读写</p>
<p>l 将顺序写数据和随机读写数据分成不同的物理磁盘进行，有助于i/o压力的疏解</p>
<p>数据库文件涉及索引等内容，写入是随即写<br />
binlog文件是顺序写<br />
淘宝数据库存储优化是这样处理的<br />
l 部分安全要求不高的写入操作可以用 /dev/shm 分区存储，简单变成内存写。</p>
<p>l 多块物理硬盘做raid10，可以提升写入能力</p>
<p>l 关键存储设备优化，善于比对不同存储介质的压力测试数据。</p>
<p>例如fusion-io在新浪和淘宝都有较多使用。<br />
l 涉及必须存储较为庞大的数据量时</p>
<p>压缩存储，可以通过增加cpu开销（压缩算法）减少i/o压力。前提是你确认cpu相对空闲而i/o压力很大。 新浪微博就是压缩存储的典范。<br />
通过md5去重存储，案例是领礼品的回复1    买古玩的回复2 （人多回复慢请谅解）的文件共享，以及dropbox这样的共享服务，如果你上传的是一个别人已有的文件，计算md5后，直接通过md5定位到原有文件，这样可以极大减少存储量。涉及文件共享，头像共享，相册等应用，通过这种方法可以减少超过70%的存储规模，对硬件资源的节省是相当巨大的。缺点是，删除文件需要甄别该md5是否有其他人使用。 去重存储，用户量越多，上传文件越多，效率越高！<br />
文件尽量不要存储到数据库内。尽量使用独立的文件系统存储，该话题不展开。<br />
运维监控体系<br />
l 系统监控</p>
<p>n 服务器资源监控</p>
<p>u Cpu, 内存，硬盘空间，i/o压力</p>
<p>u 设置阈值报警</p>
<p>n 服务器流量监控</p>
<p>u 外网流量，内网流量</p>
<p>u 设置阈值报警</p>
<p>n 连接状态监控</p>
<p>u Show processlist 设置阈值，每分钟监测，超过阈值记录</p>
<p>l 应用监控</p>
<p>n 慢查询监控</p>
<p>u 慢查询日志</p>
<p>u 如果存在多台数据库服务器，应有汇总查阅机制。</p>
<p>n 请求错误监控</p>
<p>u 高频繁应用中，会出现偶发性数据库连接错误或执行错误，将错误信息记录到日志，查看每日的比例变化。</p>
<p>u 偶发性错误，如果数量极少，可以不用处理，但是需时常监控其趋势。</p>
<p>u 会存在恶意输入内容，输入边界限定缺乏导致执行出错，需基于此防止恶意入侵探测行为。</p>
<p>n 微慢查询监控</p>
<p>u 高并发环境里，超过0.01秒的查询请求都应该关注一下。</p>
<p>n 频繁度监控</p>
<p>u 写操作，基于binlog，定期分析。</p>
<p>u 读操作，在前端db封装代码中增加抽样日志，并输出执行时间。</p>
<p>u 分析请求频繁度是开发架构 进一步优化的基础</p>
<p>u 最好的优化就是减少请求次数！</p>
<p>l 总结：</p>
<p>n 监控与数据分析是一切优化的基础。</p>
<p>n 没有运营数据监测就不要妄谈优化！</p>
<p>n 监控要注意不要产生太多额外的负载，不要因监控带来太多额外系统开销</p>
<p>Mysql 架构优化<br />
架构优化目标<br />
防止单点隐患</p>
<p>l 所谓单点隐患，就是某台设备出现故障，会导致整体系统的不可用，这个设备就是单点隐患。</p>
<p>l 理解连带效应，所谓连带效应，就是一种问题会引发另一种故障，举例而言，memcache+mysql是一种常见缓存组合，在前端压力很大时，如果memcache崩溃，理论上数据会通过mysql读取，不存在系统不可用情况，但是mysql无法对抗如此大的压力冲击，会因此连带崩溃。因A系统问题导致B系统崩溃的连带问题，在运维过程中会频繁出现。</p>
<p>n 实战范例： 在mysql连接不及时释放的应用环境里，当网络环境异常（同机房友邻服务器遭受拒绝服务攻击，出口阻塞），网络延迟加剧，空连接数急剧增加，导致数据库连接过多崩溃。</p>
<p>n 实战范例2：前端代码 通常我们封装 mysql_connect和memcache_connect，二者的顺序不同，会产生不同的连带效应。如果mysql_connect在前，那么一旦memcache连接阻塞，会连带mysql空连接过多崩溃。</p>
<p>n 连带效应是常见的系统崩溃，日常分析崩溃原因的时候需要认真考虑连带效应的影响，头疼医头，脚疼医脚是不行的。</p>
<p>方便系统扩容</p>
<p>l 数据容量增加后，要考虑能够将数据分布到不同的服务器上。</p>
<p>l 请求压力增加时，要考虑将请求压力分布到不同服务器上。</p>
<p>l 扩容设计时需要考虑防止单点隐患。</p>
<p>安全可控，成本可控</p>
<p>l 数据安全，业务安全</p>
<p>l 人力资源成本&gt;带宽流量成本&gt;硬件成本</p>
<p>n 成本与流量的关系曲线应低于线性增长（流量为横轴，成本为纵轴）。</p>
<p>n 规模优势</p>
<p>l 本教程仅就与数据库有关部分讨论，与数据库无关部门请自行参阅其他学习资料。</p>
<p>分布式方案<br />
分库&amp;拆表方案</p>
<p>l 基本认识</p>
<p>n 用分库&amp;拆表是解决数据库容量问题的唯一途径。</p>
<p>n 分库&amp;拆表也是解决性能压力的最优选择。</p>
<p>n 分库 – 不同的数据表放到不同的数据库服务器中（也可能是虚拟服务器）</p>
<p>n 拆表 – 一张数据表拆成多张数据表，可能位于同一台服务器，也可能位于多台服务器（含虚拟服务器）。</p>
<p>l 去关联化原则</p>
<p>n 摘除数据表之间的关联，是分库的基础工作。</p>
<p>n 摘除关联的目的是，当数据表分布到不同服务器时，查询请求容易分发和处理。</p>
<p>n 学会理解反范式数据结构设计，所谓反范式，第一要点是不用外键，不允许Join操作，不允许任何需要跨越两个表的查询请求。第二要点是适度冗余减少查询请求，比如说，信息表，fromuid, touid, message字段外，还需要一个fromuname字段记录用户名，这样查询者通过touid查询后，能够立即得到发信人的用户名，而无需进行另一个数据表的查询。</p>
<p>n 去关联化处理会带来额外的考虑，比如说，某一个数据表内容的修改，对另一个数据表的影响。这一点需要在程序或其他途径去考虑。</p>
<p>l 分库方案</p>
<p>n 安全性拆分</p>
<p>u 将高安全性数据与低安全性数据分库，这样的好处第一是便于维护，第二是高安全性数据的数据库参数配置可以以安全优先，而低安全性数据的参数配置以性能优先。参见运维优化相关部分。</p>
<p>n 基于业务逻辑拆分</p>
<p>u 根据数据表的内容构成，业务逻辑拆分，便于日常维护和前端调用。</p>
<p>u 基于业务逻辑拆分，可以减少前端应用请求发送到不同数据库服务器的频次，从而减少链接开销。</p>
<p>u 基于业务逻辑拆分，可保留部分数据关联，前端web工程师可在限度范围内执行关联查询。</p>
<p>n 基于负载压力拆分</p>
<p>u 基于负载压力对数据结构拆分，便于直接将负载分担给不同的服务器。</p>
<p>u 基于负载压力拆分，可能拆分后的数据库包含不同业务类型的数据表，日常维护会有一定的烦恼。</p>
<p>n 混合拆分组合</p>
<p>u 基于安全与业务拆分为数据库实例，但是可以使用不同端口放在同一个服务器上。</p>
<p>u 基于负载可以拆分为更多数据库实例分布在不同数据库上</p>
<p>u 例如，</p>
<p>l 基于安全拆分出A数据库实例，</p>
<p>l 基于业务拆分出B,C数据库实例，</p>
<p>l C数据库存在较高负载，基于负载拆分为C1,C2,C3,C4等 实例。</p>
<p>l 数据库服务器完全可以做到 A+B+C1 为一台，C2,C3,C4各单独一台。</p>
<p>l 分表方案</p>
<p>n 数据量过大或者访问压力过大的数据表需要切分</p>
<p>n 纵向分表（常见为忙闲分表）</p>
<p>u 单数据表字段过多，可将频繁更新的整数数据与非频繁更新的字符串数据切分</p>
<p>u 范例 user表 ，个人简介，地址，领礼品的回复1    买古玩的回复2 （人多回复慢请谅解）号，联系方式，头像 这些字段为字符串类型，更新请求少； 最后登录时间，在线时常，访问次数，信件数这些字段为整数型字段，更新频繁，可以将后面这些更新频繁的字段独立拆出一张数据表，表内容变少，索引结构变少，读写请求变快。</p>
<p>n 横向切表</p>
<p>u 等分切表，如哈希切表或其他基于对某数字取余的切表。等分切表的优点是负载很方便的分布到不同服务器；缺点是当容量继续增加时无法方便的扩容，需要重新进行数据的切分或转表。而且一些关键主键不易处理。</p>
<p>u 递增切表，比如每1kw用户开一个新表，优点是可以适应数据的自增趋势；缺点是往往新数据负载高，压力分配不平均。</p>
<p>u 日期切表，适用于日志记录式数据，优缺点等同于递增切表。</p>
<p>u 个人倾向于递增切表，具体根据应用场景决定。</p>
<p>n 热点数据分表</p>
<p>u 将数据量较大的数据表中将读写频繁的数据抽取出来，形成热点数据表。通常一个庞大数据表经常被读写的内容往往具有一定的集中性，如果这些集中数据单独处理，就会极大减少整体系统的负载。</p>
<p>u 热点数据表与旧有数据关系</p>
<p>l 可以是一张冗余表，即该表数据丢失不会妨碍使用，因源数据仍存在于旧有结构中。优点是安全性高，维护方便，缺点是写压力不能分担，仍需要同步写回原系统。</p>
<p>l 可以是非冗余表，即热点数据的内容原有结构不再保存，优点是读写效率全部优化；缺点是当热点数据发生变化时，维护量较大。</p>
<p>l 具体方案选择需要根据读写比例决定，在读频率远高于写频率情况下，优先考虑冗余表方案。</p>
<p>u 热点数据表可以用单独的优化的硬件存储，比如昂贵的闪存卡或大内存系统。</p>
<p>u 热点数据表的重要指标</p>
<p>l 热点数据的定义需要根据业务模式自行制定策略，常见策略为，按照最新的操作时间；按照内容丰富度等等。</p>
<p>l 数据规模，比如从1000万条数据，抽取出100万条热点数据。</p>
<p>l 热点命中率，比如查询10次，多少次命中在热点数据内。</p>
<p>l 理论上，数据规模越小，热点命中率越高，说明效果越好。需要根据业务自行评估。</p>
<p>u 热点数据表的动态维护</p>
<p>l 加载热点数据方案选择</p>
<p>n 定时从旧有数据结构中按照新的策略获取</p>
<p>n 在从旧有数据结构读取时动态加载到热点数据</p>
<p>l 剔除热点数据方案选择</p>
<p>n 基于特定策略，定时将热点数据中访问频次较少的数据剔除</p>
<p>n 如热点数据是冗余表，则直接删除即可，如不是冗余表，需要回写给旧有数据结构。</p>
<p>u 通常，热点数据往往是基于缓存或者key-value 方案冗余存储，所以这里提到的热点数据表，其实更多是理解思路，用到的场合可能并不多….</p>
<p>反范式设计（冗余结构设计）</p>
<p>l 反范式设计的概念</p>
<p>n 无外键，无连表查询。</p>
<p>n 便于分布式设计，允许适度冗余，为了容量扩展允许适度开销。</p>
<p>n 基于业务自由优化，基于i/o 或查询设计，无须遵循范式结构设计。</p>
<p>l 冗余结构设计所面临的典型场景</p>
<p>n 原有展现程序涉及多个表的查询，希望精简查询程序</p>
<p>n 数据表拆分往往基于主键，而原有数据表往往存在非基于主键的关键查询，无法在分表结构中完成。</p>
<p>n 存在较多数据统计需求（count, sum等），效率低下。</p>
<p>l 冗余设计方案</p>
<p>n 基于展现的冗余设计</p>
<p>u 为了简化展现程序，在一些数据表中往往存在冗余字段</p>
<p>u 举例，信息表  message，存在字段 fromuid,touid,msg,sendtime  四个字段，其中 touid+sendtime是复合索引。存在查询为 select * from message where touid=$uid order by sendtime desc  limit 0,30;</p>
<p>u 展示程序需要显示发送者姓名，此时通常会在message表中增加字段fromusername，甚至有的会增加fromusersex，从而无需连表查询直接输出信息的发送者姓名和性别。这就是一种简单的，为了避免连表查询而使用的冗余字段设计。</p>
<p>n 基于查询的冗余设计</p>
<p>u 涉及分表操作后，一些常见的索引查询可能需要跨表，带来不必要的麻烦。确认查询请求远大于写入请求时，应设置便于查询项的冗余表。</p>
<p>u 冗余表要点</p>
<p>l 数据一致性，简单说，同增，同删，同更新。</p>
<p>l 可以做全冗余，或者只做主键关联的冗余，比如通过用户名查询uid，再基于uid查询源表。</p>
<p>u 实战范例1</p>
<p>l 用户分表，将用户库分成若干数据表</p>
<p>l 基于用户名的查询和基于uid的查询都是高并发请求。</p>
<p>l 用户分表基于uid分成数据表，同时基于用户名做对应冗余表。</p>
<p>l 如果允许多方式登陆，可以有如下设计方法</p>
<p>n uid,passwd,用户信息等等，主数据表，基于uid 分表</p>
<p>n ukey,ukeytype,uid 基于ukey分表，便于用户登陆的查询。分解成如下两个SQL。</p>
<p>u select uid from ulist_key_13 where ukey=’$username’ and ukeytype=‘login’;</p>
<p>u select * from ulist_uid_23 where uid=$uid and passwd=’$passwd’;</p>
<p>n ukeytype定义用户的登陆依据，比如用户名，手机号，邮件地址，网站昵称等。 Ukey+ukeytype 必须唯一。</p>
<p>n 此种方式需要登陆密码统一，对于第三方connect接入模式，可以通过引申额外字段完成。</p>
<p>u 实战范例2：用户游戏积分排名</p>
<p>l 表结构 uid,gameid,score 参见前文实时积分排行。表内容巨大，需要拆表。</p>
<p>l 需求1：基于游戏id查询积分排行</p>
<p>l 需求2：基于用户id查询游戏积分记录</p>
<p>l 解决方案：建立完全相同的两套表结构，其一以uid为拆表主键，其二以gameid为拆表主键，用户提交积分时，向两个数据结构同时提交。</p>
<p>u 实战范例3：全冗余查询结构</p>
<p>l 主信息表仅包括 主键及备注memo 字段（text类型），只支持主键查询，可以基于主键拆表。所以需要展现和存储的内容均在memo字段重体现。</p>
<p>l 对每一个查询条件，建立查询冗余表，以查询条件字段为主键，以主信息表主键id 为内容。</p>
<p>l 日常查询只基于查询冗余表，然后通过in的方式从主信息表获得内容。</p>
<p>l 优点是结构扩展非常方便，只需要扩展新的查询信息表即可，核心思路是，只有查询才需要独立的索引结构，展现无需独立字段。</p>
<p>l 缺点是只适合于相对固定的查询架构，对于更加灵活的组合查询束手无策。</p>
<p>n 基于统计的冗余结构</p>
<p>u 为了减少会涉及大规模影响结果集的表数据操作，比如count，sum操作。应将一些统计类数据通过冗余数据结构保存。</p>
<p>u 冗余数据结构可能以字段方式存在，也可能以独立数据表结构存在，但是都应能通过源数据表恢复。</p>
<p>u 实战范例：</p>
<p>l 论坛板块的发帖量，回帖量，每日新增数据等。</p>
<p>l 网站每日新增用户数等。</p>
<p>l 参见Discuz论坛系统数据结构，有较多相关结构。</p>
<p>l 参见前文分段积分结构，是典型用于统计的冗余结构。</p>
<p>l 后台可以通过源数据表更新该数字。</p>
<p>l Redis的Zset类型可以理解为存在一种冗余统计结构。</p>
<p>n 历史数据表</p>
<p>u 历史数据表对应于热点数据表，将需求较少又不能丢弃的数据存入，仅在少数情况下被访问。</p>
<p>主从架构</p>
<p>l 基本认识</p>
<p>n 读写分离对负载的减轻远远不如分库分表来的直接。</p>
<p>n 写压力会传递给从表，只读从库一样有写压力，一样会产生读写锁！</p>
<p>n 一主多从结构下，主库是单点隐患，很难解决（如主库当机，从库可以响应读写，但是无法自动担当主库的分发功能）</p>
<p>n 主从延迟也是重大问题。一旦有较大写入问题，如表结构更新，主从会产生巨大延迟。</p>
<p>l 应用场景</p>
<p>n 在线热备</p>
<p>n 异地分布</p>
<p>u 写分布，读统一。</p>
<p>u 仍然困难重重，受限于网络环境问题巨多！</p>
<p>n 自动障碍转移</p>
<p>u 主崩溃，从自动接管</p>
<p>n 个人建议，负载均衡主要使用分库方案，主从主要用于热备和障碍转移。</p>
<p>l 潜在优化点</p>
<p>n 为了减少写压力，有些人建议主不建索引提升i/o性能，从建立索引满足查询要求。个人认为这样维护较为麻烦。而且从本身会继承主的i/o压力，因此优化价值有限。该思路特此分享，不做推荐。</p>
<p>故障转移处理</p>
<p>l 要点</p>
<p>n 程序与数据库的连接，基于虚地址而非真实ip，由负载均衡系统监控。</p>
<p>n 保持主从结构的简单化，否则很难做到故障点摘除。</p>
<p>l 思考方式</p>
<p>n 遍历对服务器集群的任何一台服务器，前端web，中间件，监控，缓存，db等等，假设该服务器出现故障，系统是否会出现异常？用户访问是否会出现异常。</p>
<p>n 目标：任意一台服务器崩溃，负载和数据操作均会很短时间内自动转移到其他服务器，不会影响业务的正常进行。不会造成恶性的数据丢失。（哪些是可以丢失的，哪些是不能丢失的）</p>
<p>缓存方案<br />
缓存结合数据库的读取</p>
<p>l Memcached是最常用的缓存系统</p>
<p>l Mysql 最新版本已经开始支持memcache插件，但据牛人分析，尚不成熟，暂不推荐。</p>
<p>l 数据读取</p>
<p>n 并不是所有数据都适合被缓存，也并不是进入了缓存就意味着效率提升。</p>
<p>n 命中率是第一要评估的数据。</p>
<p>n 如何评估进入缓存的数据规模，以及命中率优化，是非常需要细心分析的。</p>
<p>l 实景分析： 前端请求先连接缓存，缓存未命中连接数据库，进行查询，未命中状态比单纯连接数据库查询多了一次连接和查询的操作；如果缓存命中率很低，则这个额外的操作非但不能提高查询效率，反而为系统带来了额外的负载和复杂性，得不偿失。</p>
<p>n 相关评估类似于热点数据表的介绍。</p>
<p>n 善于利用内存，请注意数据存储的格式及压缩算法。</p>
<p>l Key-value 方案繁多，本培训文档暂不展开。</p>
<p>缓存结合数据库的写入</p>
<p>l 利用缓存不但可以减少数据读取请求，还可以减少数据库写入i/o压力</p>
<p>l 缓存实时更新，数据库异步更新</p>
<p>n 缓存实时更新数据，并将更新记录写入队列</p>
<p>n 可以使用类似mq的队列产品，自行建立队列请注意使用increment来维持队列序号。</p>
<p>n 不建议使用 get 后处理数据再set的方式维护队列</p>
<p>l 测试范例：</p>
<p>l 范例1</p>
<p>$var=Memcache_get($memcon,”var”);</p>
<p>$var++;</p>
<p>memcache_set($memcon,”var”,$var);</p>
<p>这样一个脚本，使用apache ab去跑，100个并发，跑10000次，然后输出缓存存取的数据，很遗憾，并不是1000，而是5000多，6000多这样的数字，中间的数字全在 get &amp; set的过程中丢掉了。</p>
<p>原因，读写间隔中其他并发写入，导致数据丢失。</p>
<p>l 范例2</p>
<p>用memcache_increment来做这个操作，同样跑测试</p>
<p>会得到完整的10000，一条数据不会丢。</p>
<p>l 结论： 用increment存储队列编号，用标记+编号作为key存储队列内容。</p>
<p>n 后台基于缓存队列读取更新数据并更新数据库</p>
<p>l 基于队列读取后可以合并更新</p>
<p>l 更新合并率是重要指标</p>
<p>l 实战范例：</p>
<p>某论坛热门贴，前端不断有views=views+1数据更新请求。</p>
<p>缓存实时更新该状态</p>
<p>后台任务对数据库做异步更新时，假设执行周期是5分钟，那么五分钟可能会接收到这样的请求多达数十次乃至数百次，合并更新后只执行一次update即可。</p>
<p>类似操作还包括游戏打怪，生命和经验的变化；个人主页访问次数的变化等。</p>
<p>n 异步更新风险</p>
<p>l 前后端同时写，可能导致覆盖风险。</p>
<p>l 使用后端异步更新，则前端应用程序就不要写数据库，否则可能造成写入冲突。一种兼容的解决方案是，前端和后端不要写相同的字段。</p>
<p>l 实战范例：</p>
<p>用户在线上时，后台异步更新用户状态。</p>
<p>管理员后台屏蔽用户是直接更新数据库。</p>
<p>结果管理员屏蔽某用户操作完成后，因该用户在线有操作，后台异步更新程序再次基于缓存更新用户状态，用户状态被复活，屏蔽失效。</p>
<p>l 缓存数据丢失或服务崩溃可能导致数据丢失风险。</p>
<p>l 如缓存中间出现故障，则缓存队列数据不会回写到数据库，而用户会认为已经完成，此时会带来比较明显的用户体验问题。</p>
<p>l 一个不彻底的解决方案是，确保高安全性，高重要性数据实时数据更新，而低安全性数据通过缓存异步回写方式完成。此外，使用相对数值操作而不是绝对数值操作更安全。</p>
<p>n 范例：支付信息，道具的购买与获得，一旦丢失会对用户造成极大的伤害。而经验值，访问数字，如果只丢失了很少时间的内容，用户还是可以容忍的。</p>
<p>n 范例：如果使用 Views=Views+…的操作，一旦出现数据格式错误，从binlog中反推是可以进行数据还原，但是如果使用Views=特定值的操作，一旦缓存中数据有错误，则直接被赋予了一个错误数据，无法回溯！</p>
<p>l 异步更新如出现队列阻塞可能导致数据丢失风险。</p>
<p>l 异步更新通常是使用缓存队列后，在后台由cron或其他守护进程写入数据库。</p>
<p>l 如果队列生成的速度&gt;后台更新写入数据库的速度，就会产生阻塞，导致数据越累计越多，数据库响应迟缓，而缓存队列无法迅速执行，导致溢出或者过期失效。</p>
<p>n 建议使用内存队列产品而不使用memcache 来进行缓存异步更新。</p>
<p>总结<br />
第一步，完成数据库查询的优化，需要理解索引结构，才能学会判断影响结果集。而影响结果集对查询效率线性相关，掌握这一点，编写数据查询语句就很容易判断系统开销，了解业务压力趋势。<br />
第二步，在SQL语句已经足够优化的基础上，学会对数据库整体状况的分析，能够对异常和负载的波动有正确的认识和解读；能够对系统资源的分配和瓶颈有正确的认识。<br />
学会通过监控和数据来进行系统的评估和优化方案设计，杜绝拍脑袋，学会抓大放小，把握要点的处理方法。<br />
第三步，在彻底掌握数据库语句优化和运维优化的基础上，学会分布式架构设计，掌握复杂，大容量数据库系统的搭建方法。<br />
最后，分享一句话，学会把问题简单化，正如Caoz 常说的，你如果认为这个问题很复杂，你一定想错了。</p>]]></description>
    <pubDate>Tue, 16 Apr 2019 09:19:34 +0800</pubDate>
    <dc:creator>jabin</dc:creator>
    <guid>http://xuzhibin.com/?post=7</guid>
</item>
<item>
    <title>React + Electron 搭建一个桌面应用[转]</title>
    <link>http://xuzhibin.com/?post=8</link>
    <description><![CDATA[<h1>React + Electron 搭建一个桌面应用[转]</h1>
<p>当你冲这个标题点进来的时候，我猜你一定知道 React 是什么，更多详情请<a href="https://react.docschina.org">戳这里</a>，就不介绍React了，一个神般存在的前端框架。另外，浏览器和移动端横行的时代，为什么还需要桌面应用？我就不解释了，反正优点很多，做为技术多学一点总没错。</p>
<h2>Electron 简单介绍</h2>
<h3>是什么?</h3>
<p><strong><a href="https://link.juejin.im/?target=https://electronjs.org/docs/tutorial/about">官网</a></strong>​<strong>是这么介绍的：</strong></p>
<p><a href="https://link.juejin.im/?target=https://electronjs.org/">Electron</a>is an open source library developed by GitHub for building cross-platform desktop applications with HTML, CSS, and JavaScript. Electron accomplishes this by combining <a href="https://link.juejin.im/?target=https://www.chromium.org/Home">Chromium</a>and <a href="https://link.juejin.im/?target=https://nodejs.org/">Node.js</a>into a single runtime and apps can be packaged for Mac, Windows, and Linux.</p>
<p><strong>简单翻译一下就是：</strong></p>
<p>​<a href="https://link.juejin.im/?target=https://electron.atom.io/">Electron</a>是一个由 GitHub 开发的开源库，通过将 <a href="https://link.juejin.im/?target=https://www.chromium.org/Home">Chromium</a>) 和<a href="https://link.juejin.im/?target=https://nodejs.org/">Node.js</a>组合并使用 HTML，CSS 和 JavaScript 进行构建 Mac，Windows，和 Linux 跨平台桌面应用程序。</p>
<p><strong>隐藏意思：</strong></p>
<p>让前端开发者快乐简单拥抱桌面应用！</p>
<div>
<!-- more -->
</div>
<h3><strong>原理是?</strong></h3>
<p>上面已将说了，<a href="https://link.juejin.im/?target=https://electron.atom.io/">Electron</a>通过将 <a href="https://link.juejin.im/?target=https://www.chromium.org/Home">Chromium</a>和 <a href="https://link.juejin.im/?target=https://nodejs.org/">Node.js</a>组合到单个 runtime 中来实现的。</p>
<p><strong>node.js:</strong></p>
<p>如果你不知道 node.js，那还等什么快<a href="https://link.juejin.im/?target=https://nodejs.org/en/">戳这里</a>，看一看世界上最温柔可爱的语言。它借助于 Google 的 V8 引擎，<strong>Node.js</strong>是一个能够在服务器端运行 JavaScript 的开放源代码、跨平台 JavaScript 运行环境，更多解释请<a href="https://link.juejin.im/?target=https://zh.wikipedia.org/wiki/Node.js">戳维基百科</a>。</p>
<p><strong>Chromium:</strong></p>
<p>Chromium 或许你没听说过，但是你一定听说过 chrome 吧！Chromium 是 Google 的开源浏览器，是 chrome 背后的那个不太稳定更新快的兄弟版，详情<a href="https://link.juejin.im/?target=https://www.chromium.org/Home">戳这里</a>。</p>
<p><strong>组合:</strong></p>
<p>Electron 创建的应用使用网页作为其 GUI ,因此你可以将其当成由 JavaScript 控制的迷你精简版Chromium 浏览器。也可以将 Electron 当成 node.js 变体，只不过它更专注于桌面应用而非 Web 服务器。在 Electron 中, 把 <code>package.json</code>中设定的 <code>main</code>脚本的所在进程称为 <strong>主进程</strong>。这个进程中运行的脚本也可通过创建网页这种方式来展现其 GUI。 因为 Electron 是通过 Chromium 来显示页面,所以 Chromium 自带的多进程架构也一同被利用。这样每个页面都运行着一个独立的进程,它们被统称为 <strong>渲染进程</strong>。通常来说,浏览器中的网页会被限制在沙盒环境中运行并且不允许访问系统原生资源。但是由于 Eelectron 用户可在页面中调用 Node.js API，所以可以和底层操作系统直接交互。</p>
<h3><strong>优缺点？</strong></h3>
<p>总之，优点肯定大于缺点。</p>
<p><strong>优点:</strong></p>
<p>方便快捷的开发桌面应用，跨平台，对前端开发者友好，活跃的社区，丰富的api......</p>
<p><strong>缺点:</strong></p>
<p>性能肯定比不上原生的桌面应用，发布的包貌似有一点点大。</p>
<h3><strong>怎么开始?</strong></h3>
<p>如果不是假前端，那么你电脑肯定安装好了 git 和 node。</p>
<pre><code class="language-bash"># github上有一个 electron-quick-start 仓库克隆下来
git clone https://github.com/electron/electron-quick-start
# 进入文件夹
cd electron-quick-start
# 安装依赖包并运行
npm install &amp;&amp; npm start
</code></pre>
<p>然后，你桌面应用就创建成功了如下图所示！</p>
<p><img src="http://public.xuzhibin.com/blog/2018-11-29-142519.png" alt="" /></p>
<p>打开你的 electron-quick-start 文件夹，你的项目结构如下图：</p>
<p><img src="http://public.xuzhibin.com/blog/2018-11-29-142520.png" alt="" /></p>
<p>其中，main.js 是你的启动文件，index.html 是你的入口文件。</p>
<h2>React 结合 Electron</h2>
<p>上面简单的介绍了一下 Electron，下面介绍一下如何将 React 和 Electron 结合起来。</p>
<h3><strong>创建一个React项目</strong></h3>
<p>首先你得有一个 React 项目，由于太多繁琐的配置和懒惰的自己，我们这里就用 Facebook 提供的 create-react-app 来快速创建一个 knownsec-fed 项目。</p>
<pre><code class="language-bash"># 安装 create-react-app 命令,如果已将安装请忽略
npm install -g create-react-app
# 创建 knownsec-fed 项目
create-react-app knownsec-fed
# 启动项目( create-react-app 真的超级方便啊)
cd knownsec-fed &amp;&amp; npm start
</code></pre>
<p>于是，浏览器 <a href="http://localhost:3000/">http://localhost:3000/</a> 就会出现着如下图界面，一个 react 项目创建成功：</p>
<p><img src="http://public.xuzhibin.com/blog/2018-11-29-142521.png" alt="" /></p>
<h3>添加 Electron 包</h3>
<pre><code class="language-bash"># 在knownsec-fed 目录下安装 Electron 包
npm install -save electron
</code></pre>
<h3>相关配置</h3>
<h4><strong>配置 main.js</strong></h4>
<p>knownsec-fed 根目录(不是 src 目录)下面新建 main.js 文件,这个文件和 electron-quick-start 中的官方默认 main.js 几乎一模一样，只修改了加载应用这入口这一个地方：</p>
<pre><code class="language-javascript">// 引入electron并创建一个Browserwindow
const {app, BrowserWindow} = require('electron')
const path = require('path')
const url = require('url')

// 保持window对象的全局引用,避免JavaScript对象被垃圾回收时,窗口被自动关闭.
let mainWindow

function createWindow () {
//创建浏览器窗口,宽高自定义具体大小你开心就好
mainWindow = new BrowserWindow({width: 800, height: 600})

  /* 
   * 加载应用-----  electron-quick-start中默认的加载入口
    mainWindow.loadURL(url.format({
      pathname: path.join(__dirname, 'index.html'),
      protocol: 'file:',
      slashes: true
    }))
  */
  // 加载应用----适用于 react 项目
  mainWindow.loadURL('http://localhost:3000/');

  // 打开开发者工具，默认不打开
  // mainWindow.webContents.openDevTools()

  // 关闭window时触发下列事件.
  mainWindow.on('closed', function () {
    mainWindow = null
  })
}

// 当 Electron 完成初始化并准备创建浏览器窗口时调用此方法
app.on('ready', createWindow)

// 所有窗口关闭时退出应用.
app.on('window-all-closed', function () {
  // macOS中除非用户按下 `Cmd + Q` 显式退出,否则应用与菜单栏始终处于活动状态.
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('activate', function () {
   // macOS中点击Dock图标时没有已打开的其余应用窗口时,则通常在应用中重建一个窗口
  if (mainWindow === null) {
    createWindow()
  }
})

// 你可以在这个脚本中续写或者使用require引入独立的js文件.   
</code></pre>
<h4>配置 package.json</h4>
<pre><code class="language-javascript">{
  "name": "knownsec-fed",
  "version": "0.1.0",
  "private": true,
  "main": "main.js", // 配置启动文件
  "homepage":".", // 
  "dependencies": {
    "electron": "^1.7.10",
    "react": "^16.2.0",
    "react-dom": "^16.2.0",
    "react-scripts": "1.1.0"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject",
    "electron-start": "electron ." // 配置electron的start，区别于web端的start
  }
}   </code></pre>
<h4>启动 Electron</h4>
<pre><code class="language-bash"># 启动react项目
npm start
# 启动electron
npm run electron-start</code></pre>
<p>支持热调试，当你修改代码后，桌面应用也将会重新更新。</p>
<p><img src="http://public.xuzhibin.com/blog/2018-11-29-142523.png" alt="" /></p>
<h3><strong>打包</strong></h3>
<h4>打包 react 项目</h4>
<p>首先修改 <code>main.js</code>, 因为现在你要将 react 项目打包在 build 文件夹下面，所以加载应用处改成如下！当然也可在某个配置文件里面配置是否属于开发，此处用if判断一下从未进行选择执行哪段加载应用代码。但是这里为了简便，暂且使用直接修改的方式：</p>
<pre><code class="language-javascript">// 加载应用----react 打包
mainWindow.loadURL(url.format({
  pathname: path.join(__dirname, './build/index.html'),
  protocol: 'file:',
  slashes: true
}))
// 加载应用----适用于 react 开发时项目
// mainWindow.loadURL('http://localhost:3000/');</code></pre>
<p>默认情况下，homepage 是 <a href="http://localhost:3000，build">http://localhost:3000，build</a> 后，所有资源文件路径都是 /static，而 Electron 调用的入口是 file :协议，/static 就会定位到根目录去，所以找不到静态文件。在 <code>package.json</code>文件中添加 homepage 字段并设置为&quot;.&quot;后，静态文件的路径就变成了相对路径，就能正确地找到了添加如下配置：</p>
<pre><code class="language-javascript">"homepage":"."</code></pre>
<p>然后就开始打包 react：</p>
<pre><code class="language-bash">npm run-script build</code></pre>
<p>此时，根目录下面将多出一个build文件夹。</p>
<h3>打包 electron</h3>
<p><strong>常用打包插件</strong></p>
<ul>
<li><strong><a href="https://link.juejin.im/?target=https://github.com/electron-userland/electron-builder">electron-builder</a></strong></li>
<li><strong><a href="https://link.juejin.im/?target=https://github.com/electron-userland/electron-packager">electron-packager</a></strong></li>
</ul>
<p><strong>安装electron-packager</strong></p>
<pre><code class="language-bash"># knownsec-fed目录下安装electron-packager包
npm install electron-packager --save-dev
# 安装electron-packager命令
npm install electron-packager -g</code></pre>
<p><strong>electron-packager命令介绍</strong></p>
<pre><code>  electron-packager &lt;location of project&gt; &lt;name of project&gt; &lt;platform&gt; &lt;architecture&gt; &lt;electron version&gt; &lt;optional options&gt;</code></pre>
<ul>
<li>location of project: 项目的本地地址，此处我这边是 ~/knownsec-fed</li>
<li>location of project: 项目名称，此处是 knownsec-fed</li>
<li>platform: 打包成的平台</li>
<li>architecture: 使用 x86 还是 x64 还是两个架构都用</li>
<li>electron version: electron 的版本</li>
</ul>
<p>于是，根据我这边的情况在 <code>package.json</code>文件的在 scripts 中加上如下代码：</p>
<pre><code class="language-javascript">"package": "electron-packager ~/knownsec-fed/build knownsec-fed --all --out ~/ --electron-version 3.0.10```

**开始打包**

```bash
npm run-script package</code></pre>
<p><strong>提醒</strong></p>
<p>由于打包的时候会把浏览器内核完整打包进去，所以就算你的项目开发就几百k的资源，但最终的打包文件估计也会比较大。</p>
<h2>其它</h2>
<p>此文章未涉及 Electron 具体的技术，只是简单的介绍了一下 react + electron 的一个配置及打包的流程。或许以后会写关于 Electron 的技术细节。Electron 有着非常强大的 api，其背后涉及的技术也非常多。</p>
<p><strong>友情链接</strong></p>
<ul>
<li><a href="https://link.juejin.im/?target=https://github.com/electron/electron">Electron github</a></li>
<li><a href="https://link.juejin.im/?target=https://electronjs.org/docs">Electron 英文文档</a></li>
<li><a href="https://link.juejin.im/?target=https://www.gitbook.com/book/yuzhigang/electron/details">Electron 中文手册</a></li>
<li><a href="https://link.juejin.im/?target=https://github.com/electron-userland/electron-packager">electron-packager github</a></li>
<li><a href="https://link.juejin.im/?target=https://electronjs.org/apps">基于Electron构建的app</a></li>
<li><a href="https://link.juejin.im/?target=https://github.com/chentsulin/electron-react-boilerplate">electron-react-boilerplate github</a></li>
</ul>]]></description>
    <pubDate>Thu, 29 Nov 2018 09:19:50 +0800</pubDate>
    <dc:creator>jabin</dc:creator>
    <guid>http://xuzhibin.com/?post=8</guid>
</item>
<item>
    <title>广东人真是太太太太太好玩了</title>
    <link>http://xuzhibin.com/?post=9</link>
    <description><![CDATA[<h1>广东人真是太太太太太好玩了</h1>
<p><img src="http://public.xuzhibin.com/blog/2018-11-28-075521.jpg" alt="" /></p>
<div>
<!-- more -->
</div>
<p><img src="http://public.xuzhibin.com/blog/2018-11-28-075530.jpg" alt="" /></p>
<p><img src="http://public.xuzhibin.com/blog/2018-11-28-075531.jpg" alt="" /></p>
<p><img src="http://public.xuzhibin.com/blog/2018-11-28-075532.jpg" alt="" /><img src="http://public.xuzhibin.com/blog/2018-11-28-075533.jpg" alt="" /></p>
<p><img src="http://public.xuzhibin.com/blog/2018-11-28-75534.jpg" alt="" /></p>
<p><img src="http://public.xuzhibin.com/blog/2018-11-28-075535.jpg" alt="" /></p>
<p><img src="http://public.xuzhibin.com/blog/2018-11-28-075536.jpg" alt="" /></p>
<p><img src="http://public.xuzhibin.com/blog/2018-11-28-075537.jpg" alt="" /><img src="http://public.xuzhibin.com/blog/2018-11-28-075538.jpg" alt="" /><img src="http://public.xuzhibin.com/blog/2018-11-28-075539.jpg" alt="" /></p>
<p><img src="http://public.xuzhibin.com/blog/2018-11-28-75540.jpg" alt="" /></p>
<p><img src="http://public.xuzhibin.com/blog/2018-11-28-075540.jpg" alt="" /></p>
<p><img src="http://public.xuzhibin.com/blog/2018-11-28-075541.jpg" alt="" /></p>
<p><img src="data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==" alt="" /></p>
<p><img src="data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==" alt="" /></p>
<p><img src="http://public.xuzhibin.com/blog/2018-11-28-075542.jpg" alt="" /></p>
<p><img src="http://public.xuzhibin.com/blog/2018-11-28-075543.jpg" alt="" /></p>
<p><img src="http://public.xuzhibin.com/blog/2018-11-28-075544.jpg" alt="" /><img src="http://public.xuzhibin.com/blog/2018-11-28-075545.jpg" alt="" /><img src="http://public.xuzhibin.com/blog/2018-11-28-075546.jpg" alt="" /></p>
<p><img src="data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==" alt="" /></p>
<p><img src="http://public.xuzhibin.com/blog/2018-11-28-075547.jpg" alt="" /></p>
<p><img src="data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==" alt="" /></p>
<p><img src="http://public.xuzhibin.com/blog/2018-11-28-075548.jpg" alt="" /></p>
<p><img src="http://public.xuzhibin.com/blog/2018-11-28-075549.jpg" alt="" /></p>
<p><img src="http://public.xuzhibin.com/blog/2018-11-28-075551.jpg" alt="" /></p>
<p><img src="http://public.xuzhibin.com/blog/2018-11-28-75552.jpg" alt="" /></p>
<p><img src="http://public.xuzhibin.com/blog/2018-11-28-075552.jpg" alt="" /></p>
<p><img src="http://public.xuzhibin.com/blog/2018-11-28-075553.jpg" alt="" /></p>
<p><img src="http://public.xuzhibin.com/blog/2018-11-28-075555.jpg" alt="" /><img src="http://public.xuzhibin.com/blog/2018-11-28-75556.jpg" alt="" /><br />
<img src="http://public.xuzhibin.com/blog/2018-11-28-075556.jpg" alt="" /><img src="http://public.xuzhibin.com/blog/2018-11-28-075557.jpg" alt="" /></p>
<p><img src="http://public.xuzhibin.com/blog/2018-11-28-075558.jpg" alt="" /></p>
<p><img src="http://public.xuzhibin.com/blog/2018-11-28-075559.jpg" alt="" /></p>]]></description>
    <pubDate>Wed, 28 Nov 2018 09:19:55 +0800</pubDate>
    <dc:creator>jabin</dc:creator>
    <guid>http://xuzhibin.com/?post=9</guid>
</item>
<item>
    <title>gogs开启ssh支持</title>
    <link>http://xuzhibin.com/?post=10</link>
    <description><![CDATA[<h1>gogs开启ssh支持</h1>
<p>已经通过docker安装了gogs，http能正常使用，ssh不能使用</p>
<h1>gogs配置app.ini</h1>
<pre><code class="language-bash">[server]
DOMAIN           = xxx
HTTP_PORT        = 3000
ROOT_URL         = http://xxx:13000/
DISABLE_SSH      = false
SSH_DOMAIN       = xxx:10022
SSH_PORT         = 22
START_SSH_SERVER = false
SSH_LISTEN_PORT  = 10033
SSH_ROOT_PATH    = /home/git/.ssh
OFFLINE_MODE     = false
REWRITE_AUTHORIZED_KEYS_AT_START = false</code></pre>
<h1>docker</h1>
<p>ssh的配置文件路径<br />
/app/gogs/docker/sshd_config<br />
通过下面命令可以获得</p>
<pre><code class="language-bash">ps aux</code></pre>
<h1>设置目录权限</h1>
<pre><code class="language-bash">chmod 0777 /data/git/.ssh
chmod 0600 /data/git/.ssh/authorized_keys</code></pre>
<h1>在后台/管理面板执行</h1>
<p>重新生成 '.ssh/authorized_keys' 文件（警告：不是 Gogs 的密钥也会被删除）</p>
<h1>重启ssh服务</h1>
<pre><code class="language-bash">$ service ssh restart
$ exit</code></pre>
<h1>重新登录</h1>
<pre><code class="language-bash">ssh -p 10022 git@xxx</code></pre>
<h1>git clone格式</h1>
<pre><code>ssh://git@xxx:10022/jabin/myproject.git</code></pre>
<h1>copy ssh-key</h1>
<pre><code class="language-bash">pbcopy &lt; ~/.ssh/id_rsa.pub</code></pre>]]></description>
    <pubDate>Wed, 15 Aug 2018 09:20:01 +0800</pubDate>
    <dc:creator>jabin</dc:creator>
    <guid>http://xuzhibin.com/?post=10</guid>
</item>
<item>
    <title>mac下安装pyside2</title>
    <link>http://xuzhibin.com/?post=11</link>
    <description><![CDATA[<h1>mac下安装pyside2</h1>
<p>环境：mac已经安装了python3.5，pip3.5<br />
IDE:PyCharm</p>
<h1>安装pyside2</h1>
<pre><code class="language-bash">pip3.5 install --index-url=http://download.qt.io/snapshots/ci/pyside/5.9/latest/ pyside2 --trusted-host download.qt.io</code></pre>
<h1>简单实例</h1>
<pre><code class="language-python">#!/usr/bin/python
# -*- coding: utf-8 -*-

# 1st.py

import sys
from PySide2 import QtGui
from PySide2 import QtWidgets

app = QtWidgets.QApplication(sys.argv)

wid = QtWidgets.QWidget()
wid.resize(250, 150)
wid.setWindowTitle('Simple')
wid.show()

sys.exit(app.exec_())</code></pre>
<p><img src="http://public.xuzhibin.com/blog/2018-11-28-081016.png" alt="" /></p>
<div>
<!-- more -->
</div>
<h1>面向对象写法</h1>
<pre><code class="language-python">#!/usr/bin/python
# -*- coding: utf-8 -*-

import sys
from PySide2 import QtGui
from PySide2 import QtWidgets

class Example(QtWidgets.QWidget):

    def __init__(self):
        super(Example, self).__init__()

        self.initUI()

    def initUI(self):

        self.setGeometry(300, 300, 250, 150)
        self.setWindowTitle('Icon')
        self.setWindowIcon(QtGui.QIcon('icon.png'))

        self.show()

def main():

    app = QtWidgets.QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()</code></pre>]]></description>
    <pubDate>Wed, 08 Aug 2018 09:20:07 +0800</pubDate>
    <dc:creator>jabin</dc:creator>
    <guid>http://xuzhibin.com/?post=11</guid>
</item>
<item>
    <title>家庭数据中心</title>
    <link>http://xuzhibin.com/?post=12</link>
    <description><![CDATA[<h1>家庭数据中心</h1>
<p>私人数据越来越多（如照片），网盘越来越小，并且不是关闭就是被墙。决定搭建自己的家庭数据中心。<br />
<img src="http://public.xuzhibin.com/blog/2018-11-28-080111.jpg" alt="WechatIMG156" /></p>
<h1>计划&amp;预算</h1>
<ul>
<li>硬件：群晖218+（加一条8g内存），希捷酷狼4T*2，玩客云，希捷移动硬盘2T（玩客云用），4T（群晖用）各一个，小米盒子国际版，斐讯k2p路由器（刷官改rom）</li>
<li>预算：8k</li>
<li>目的：数据备份，家庭影视<br />
其实黑群也可以，价格更便宜。最好4盘位，2盘位还是少了点。</li>
</ul>
<div>
<!-- more -->
</div>
<h1>家庭网络改造</h1>
<p>通过 搬瓦工 安装ss，并在k2p设置ss服务和frp服务</p>
<ul>
<li>可以无缝访问google</li>
<li>小米盒子（原生android tv）可以访问youtube</li>
<li>家庭网络设备可以通过frp对外访问</li>
</ul>
<h1>群晖外网访问</h1>
<p>全球访问，frp速度更快，并且黑群也能用</p>
<ul>
<li>quickconnect</li>
<li>frp</li>
</ul>
<h1>数据备份（多种备份方式，稳如磐石）</h1>
<h2>Drive</h2>
<p>多平台同步数据</p>
<h2>DS Photo、Moments</h2>
<p>多平台同步照片</p>
<h2>Cloud Sync</h2>
<p><img src="http://public.xuzhibin.com/blog/2018-11-28-080112.png" alt="WX20180422-170201@2x" /></p>
<ul>
<li>同步下载百度网盘资源</li>
<li>同步下载Dropbox资源</li>
<li>将照片同步上传一份至onedrive和腾讯云cos（免费额度50G），即使本地硬盘挂了，也有网络备份</li>
</ul>
<h2>Hyper Backup</h2>
<ul>
<li>定期将Drive数据和photo数据备份至移动硬盘。</li>
</ul>
<h2>快照</h2>
<ul>
<li>重要文件定期快照，随时恢复</li>
</ul>
<h1>家庭影视</h1>
<ul>
<li>玩客云负责下载电影（24小时下载电影）</li>
<li>手动通过smb将玩客云下载的电影移动到群晖的移动硬盘（群晖空间不大，只有4T，影视资源存至移动硬盘）</li>
<li>手机安装ds vedio、vlc；电视安装kodi、vlc；</li>
<li>kodi通过局域网共享方式，可以将群晖的影视目录，照片目录，音乐目录，玩客云的影视目录加载进来，以后开机就可以直接看；</li>
<li>电视可以用VLC播放局域网视频资源</li>
<li>手机可以通过ds vedio直接看（外网也能访问），局域网可以vlc</li>
</ul>
<h1>家庭照片</h1>
<ul>
<li>手机可以用ds photo，Monents同步上传照片，也可以全球查看。</li>
<li>电视可以通过kodi查看</li>
</ul>
<h1>web station</h1>
<p>部署web服务，默认安装的php缺少很多模块，基本上当作静态站点使用（静态blog可以使用hexo，也可以使用MWeb生成）</p>
<h1>Docker 服务扩展</h1>
<p><img src="http://public.xuzhibin.com/blog/2018-11-28-080113.png" alt="WX20180422-170122@2x" /></p>
<h2>迅雷远程下载</h2>
<p>可以通过迅雷远程下载文件。</p>
<h2>lnmp</h2>
<p>可以部署运行php程序。</p>
<h2>gogs</h2>
<p>部署git服务，sqlite数据库，部署方便，占资源少。</p>
<h1>Virtual Machine Manager</h1>
<p>安装虚拟机，装了一个windows 2016，群晖需要8G内存以上才能安装。</p>
<h1>Antivirus Essential</h1>
<p>之前中过毒，安装一个毒软定期检查</p>
<h1>Active Backup for Server</h1>
<p>自动备份服务器文件，Linux需要安装rsync服务，windows只能备份局域网的smb</p>
<h1>硬盘扩展</h1>
<p>利用iSCSI扩展局域网windows硬盘空间，对于win系统非常好用。</p>
<h1>Time Machine</h1>
<p>备份mac系统必备，比买apple服务便宜很多。</p>
<h1>断电保护</h1>
<p>准备买个bk650，暂时资金不够，而且很少断电，还没买。</p>]]></description>
    <pubDate>Sun, 22 Apr 2018 09:20:12 +0800</pubDate>
    <dc:creator>jabin</dc:creator>
    <guid>http://xuzhibin.com/?post=12</guid>
</item>
</channel>
</rss>