Linode 上 VPS 重启后 MySQL 服务器挂了的恢复方法

做个备忘,省得每次遇见都得重新 Google 了。

这次 Linode 整体更新 XEN 的安全漏洞补丁之后,我的 VPS 重启之后,自己也没有注意,今天打开一下自己的博客站点,发现 WordPress 报了了一个「连接数据库出错」的问题,首页无法正常打开了。

之前也碰到过类似的问题,但是之前每次都是直接丢给我们可爱的耀华同学来搞定的,现在耀华同学不在身边,有的时候用起来就没有那么顺手了,所以捏,咱们还是得学会自己动手,丰衣足食啊。在询问了耀华同学咱们 MySQL 的错误日志在哪里无果之后,本想尝试直接使用耀华同学提供的通过 find 命令暴力查找了(事实证明这样可能可以找到,但是会比较麻烦),刚好看到网上有个默认地址提供了,直接 cd 到那个目录之后,看到一个长得很像的 error log 文件,打开一看,果了个然啊。打开看看错误日志里头的错误是啥,原来是 mysql 依赖的临时文件创建不成功,文件权限有问题,那么修改一下文件权限吧,修改好了文件权限之后,重启 mysql 服务,一切 OK。

那么我们来回顾一下整个流程是怎么样的。

  1. 发现 WordPress 报告 MySQL 数据库连接出错了,那么 ssh 到 VPS 上,执行一下 ps aux | grep mysql 命令,发现并没有 mysql 服务进程,可以肯定 mysql 服务没有成功启动;
  2. 那么接下来我们就要看看 mysql 服务为啥没有在此次 XEN 补丁升级后自动启动成功呢,找 error 日志来看吧,最终我们发现 rpm 默认安装的 mysql 错误日志路径在 /var/lib/mysql 目录下,跟 mysql 的核心数据库文件就在同一个目录,建议不要这么干,还是在 my.cnf 中好好地配置一下 mysql 的日志文件存放路径吧(由于我并非一个合格的服务器开发人员或维护人员,原谅我使用了默认配置);
  3. 找到这个名称为 li402-16.err(文件名格式为:[host-name].err)的错误日志文件,滚到最下面一行,看看错误是啥吧,/usr/libexec/mysqld: Can’t create/write to file ‘/dev/shm/ibinQuSV’ (Errcode: 13);
  4. 这下可以确认是因为不能往 /dev/shm 这个目录里头写入文件了,如果不是磁盘满了那么肯定就是权限不足,所以无法写入文件,但是这个目录其实是一个内存里头的临时文件目录,所以不会出现满了的情况,那么肯定的权限的问题;
  5. 接下来我们就应该给 mysql 用户分配 /dev/shm 目录的写权限就好了,由于我比较懒(实际上是不太会,这个会有安全隐患的),我直接把 /dev/shm 的权限修改为 777 了,建议还是自行严格地将写入权限分配给 mysql 用户吧;
  6. 然后通过 /etc/init.d/mysqld start 启动 mysql 服务;
  7. 再次打开博客站点首页,测试通过,OK 搞定了。

此事的原因很有可能是因为 VPS 重启之后,对于某些敏感文件目录,XEN 容器管理的原则就是将其恢复到默认的文件权限吧,不是很了解,但是直觉会是这样,也就是说以后碰到重启这样的情况再次出现 MySQL 启动错误,都应该先检查一下是否为临时文件写入权限的问题导致的。


喵的,这次 Linode VPS 硬件问题之后,机器再次重启了,泥煤的啊,突然发现,在这里的备忘压根达不到备忘的效果啊,VPS 挂了,博客打不开啊,你上哪儿看去呢?好像是个问题呢。

星巴克贩卖的是什么?

我一直都是一个愿意喝咖啡的人,虽然可能喝得最多的无非就是雀巢速溶三合一,剩下的也就是什么星巴克和 Costa(貌似中文名字叫咖世家)了,当然肯德基和麦当劳的早餐中的咖啡也是很重要的构成部分啦。

以我自己的口味和经历来讲的话,确实星巴克和 Costa 的咖啡比速溶的口味要好一些,但是前两者跟肯德基或麦当劳早餐中搭配的咖啡之间的区别就很小了。

速溶咖啡的那种浓重的香味和绵密的甜感对于任何喜欢甜食的人来说,我觉得都不是很好拒绝的东西,确实不难喝挺好喝的,如果非得要做个类比的话,我觉得可以把雀巢速溶三合一经典跟康师傅的红烧牛肉面做个类比。我个人喝完雀巢速溶经典三合一或者淘宝上卖得极好的越南中原 G7 速溶三合一之后,我在小便的时候都还能闻到咖啡的香精味道(也许有人会说我该去看医生了,好吧,谢谢好心人了。我在吃完烤羊肉的第二天小便时都能闻到羊骚味,所以咱们不要纠结这个问题了,好伐?),另外喝完之后呢,喉咙处会有一股甜腻的黏黏感。

那么星巴克或者 Costa 们呢?他们的咖啡就很好喝吗?我倒是并没有觉得有多么好喝,这些饮料类的东西对于我来说,我只是觉得它们比白水好喝,所以我更愿意喝罢了,其实我也很喜欢喝绿茶和红茶的,最次的茶叶都可以的,只要不是白水,我都挺能喝的。但是星巴克和 Costa 卖的咖啡香味确实更简单和真实,而且一般也不会给加那么重的糖和奶(而且还可以要求不加,当然速溶也有不带糖和不带奶的款)。我喝得最多的就是两款,美式和拿铁,美式就是最普通的咖啡粉冲水之后的形态,拿铁就是往美式里头加了奶和糖,很无聊的两款咖啡对吧。不过喝过之后确实不会出现上面我说到的小便还尼玛能感觉到味道的情况,也不会出现喉咙处那种黏黏的甜腻感,很直接的说法就是「这货可以当水喝能解渴,而速溶不能解渴,喝完了之后我还得喝水漱口」,差不多就是这个意思。

好吧,说完了这些屁话,感觉咖啡店里头卖的现磨鲜煮的咖啡确实好喝一些,品质稍高一些。但是我觉得这个不是星巴克和 Costa 们在中国城市中成功的主要因素,更不是广大消费者愿意去咖啡馆消费的主因。那么是什么让我们愿意去星巴克呢?

  1. 舒适感,当大家已经能够很轻松的吃饱穿暖了之后,很自然的就会要求吃得健康和穿得有格调,咖啡馆向来卖的就不只是一种饮品,更多的是售卖了一种舒适的体验。例如,我们随时走进营业的咖啡馆,随便找个座位坐下,通常咖啡馆里头的工作人员都不会主动过来问你需要喝点什么,你完全可以自己带瓶水坐在咖啡馆里头待上大半天甚至更长时间,这里是一个很轻松的环境,消费者与服务者之间更多的是一种相对来说更对等的朋友之间的对话,而不只是简单的服务与被服务的关系。这也就能解释为什么总有人会在咖啡馆里头一坐就是一整天,占着一张桌子就不走了,因为双方对于这种行为是默许的,甚至咖啡馆是更希望有一拨这样常驻在咖啡馆里头的人。这样才会让咖啡馆区别于卖冰淇淋和冷饮的小铺子,这样的咖啡馆有「人味」更能让人感到轻松自然;
  2. 自我满足,现代社会更多强调个人的满足和享受,前面提到的两点其实都是某种层次上的满足。在我们选择进入星巴克去买一杯咖啡,堂食或者外带,当我们走进了咖啡馆,自然就与没有走进咖啡馆的人分成了两类。鉴于星巴克的价格在中国的情况,并不是大部分人都能很轻松地每天进去喝一杯的,那么是不是有这种可能「进入咖啡馆的人通过买咖啡或者喝咖啡这件事情,从某种角度上能获得社会地位的一种认同」,好比有人会将「星巴克早餐」称为「你国中产早餐」一样的,这实际上确实从某种程度上很直接地说明了消费者的经济能力,这跟所有的游戏里头那个排行榜带给人们的快乐是一样的,人人都想比别人强一些,在咖啡馆里的人很自然地会获得一种简单又直接的超群的快感;
  3. 文化裹挟,咖啡是现代都市流行文化的一个重要组成部分,现代文艺作品里面咖啡馆的出场率实在是太高了,我们随便找两个现代背景的电视剧或电影,不论是美剧、韩剧、港剧、台剧还是大陆电视剧,不论是主流商业、喜剧、动作、罪案还是文艺电影,几乎随处可见的咖啡馆里主人翁闲着喝咖啡、分手喝咖啡、聚会喝咖啡、装逼喝咖啡,甚至在家早上起床之后第一件事情就是冲咖啡等等。社交媒体上那些达人们 Po 的那些美美哒的照片,简单粗暴一些的话,可以分为几大类:景区旅游风景修改自拍、商场百货 Shopping 自拍、家里头无聊素颜自拍、夜店或者 LiveHouse 演出现场自拍、户外大型活动自拍、咖啡馆闲趣自拍等等。看吧,咖啡已经不只是一个纯粹的简单的饮料了,对于现代都市人来说,这货扮演了很多的角色,而且几乎无孔不入。主流的平面媒体和电视媒体上,其实我们已经很少会看到关于咖啡品牌的广告了,为啥呢?这就是因为它真的已经是个普及率极高的东西了,大家已经不需要广告来告诉我们有这么个东西了,我们除了在电视或者网络视频上偶尔能看到类似于雀巢这种国际性品牌的战略性品牌广告以外,我们很少看到哪个咖啡品牌的广告了。而咖啡这个东西又被打上各种文艺的标签和印记,所以即便宣传和广告也只会在咖啡的个性和情调上进行挖掘,而咖啡馆这种有很强烈的店主个人审美和咖啡品味印记与之刚好形成极佳的互补,虽然星巴克和 Costa 并未呈现出很强烈的文艺风格,但是其整体的格调还是较一般的快餐店还是高出不少的。

想喝一杯好喝的咖啡,对于任何一个能喝出咖啡好坏的人来说,如果需要自己动手制作的话,需要耗费的时间和精力都是不容小觑的,特别对于都市一族来说时间成本更是难以承受。进入咖啡馆,享受一下咖啡馆里那种氛围,等待个几分钟,鲜煮的咖啡端上来,水温刚刚好,烘焙的咖啡香味浓而不腻,试问谁又不愿意为此掏点钱呢?谁还没个满足一下自己的小欲望?

Unity3D Editor 中加载移动平台的 AssetBundle 资源显示出错的解决方法

注意:本文的测试环境为 Mac OSX 、Unity 4.6.9,Unity 5 在 AssetBundle 上做了诸多调整,因未实际测试不保证测试效果会相同。


在 Unity3D 项目开发的过程中,我们肯定会遇到需要使用 AssetBundle 的时候,而且这货还确实应用之处满多的,今天咱们不展开聊 AssetBundle 能干嘛了 ,咱们把重点放到 Unity Editor 加载移动平台的 AssetBundle 资源之后,显示出现错误的问题。我们直接来看一下对比图,快速了解一下我们要解决的问题:

asset bundle-miss-shader assetbundle-with-shader

两个效果图一对比,我们马上就明白了,我们碰到的问题是左侧这个显示成粉色/紫色的这个图片呈现出来的,而右侧这个图呈现的就是我们想要的效果。

第一步,让我们来明确这个问题的定义:

  1. 首先需要说明的一点,这个问题只在 Unity Editor 下出现,在 iOS 和 Android 平台的设备上运行并不会出现这个问题,也就是该问题不影响游戏在移动设备真机上运行,只是让我们在开发的过程中感到很迷惑和无奈;
  2. 对于 Unity 系统 built-in 的那些 Shader 也不会出现这个问题,只针对我们自行编写的 Custom Shader 会出现这个问题;

第二步,让我们来确定如何重现这个问题,通常找到重现问题的方法也就找到了问题的根源所在了:

  1. 新建一个 Custom 的 Shader,咱们可以直接把 Unity 官方提供的 Shader 源码包给下载下来,然后直接修改其中的 Diffuse Shader,咱们不做任何其他改动,就简单的改两个 Property 的 Name 就好了;
  2. 将新建的 Custom-Diffuse Shader 应用于场景中某个 3D 对象的 Material 上,然后将该对象保存为 Prefab 文件;
  3. 将该 Prefab 文件打包成 AssetBundle 资源文件,打包选项为 BuildAssetBundleOptions.CollectDependencies|BuildAssetBundleOptions.CompleteAssets,编译目标设置为 Android 或者 iOS ;
  4. 新建一个空的 Unity 工程,将上一步中打包出来的 AssetBundle 文件放到 Assets/StreamingAssets 目录下,然后通过 WWW 或者通过读取文件内容字节数组后创建 AssetBundle,然后将该 AssetBundle 资源中的 Prefab 读取出来并实例化到场景中,最终我们看到的效果就是上面左侧图片呈现的情况。

第三步,找到重现的方法了,接下来就是探究问题根源了,我们可以先做几个假设,问自己几个问题:

  1. 如果不使用自己编写的 Shader,直接给 Prefab 中的 3D 对象设置一个 built-in 的 Shader,是不是就不会出现这个问题了?
  2. 如果自己编写的 Shader 中加入 Fallback “Diffuse” 代码片段之后,是否可以挽回这个显示成粉色/紫色的情况,转而使用 Unity built-in 的 Diffuse Shader 进行渲染呢?

经过测试之后,上面两个问题的答案如下:

  1. 使用 Unity built-in 的 Shader 确实不会出现丢失 Shader 导致显示错误的问题;
  2. 加入 Fallback “Diffuse” 代码片段后的 Custom Shader 不会出现丢失 Shader 之后显示成粉色/紫色的情况,但是会直接使用 Unity built-in Diffuse 的 Shader 进行渲染,跟我们在 Custom Shader 中编写的渲染逻辑半毛钱关系都木有。

至此,我们大体可以确定就是我们打包到指定 BuildTarget 平台上的 AssetBundle 中的 Prefab 资源中使用的 Shader 是成功被打包进去了,因为从上面的第二个问题中,我们能确定 Fallback 语句是生效的,如果我们想确认得更明确一些,我们可以把 Fallback 中指定的 Shader 更换为其他的 built-in 的 Shader 再试试看效果,相信我木有错滴。

既然我们现在已经确定了 Shader 是成功编译后打包进了 AssetBundle 中,那么我们可以看看直接读取 AssetBundle 资源然后初始化 Prefab 之后,这个出问题的 3D 对象使用的 Shader 是个什么情况,以及正常情况下的 Shader 应该是啥情况:

shader-in-assetbundle-for-ios shader-in-assetbundle-for-osx

上面两个图片是我们已经找到问题之后针对出现渲染错误和正确渲染两个情况打包的两个 Shader 在 Editor 中运行时通过点击 3D 对象的 Material 组件 Inspector 面板右侧的 Edit 按钮进入的 Shader 的 Inspector 面板。由此我们可以看到我们在 OSX 系统下的 Unity Editor 中使用针对 iPhone 平台打包的 AssetBundle 中的 Shader 在运行时有一个警告输出,而使用针对 OSX 平台打包的 AssetBundle 中的 Shader 就一切正常。

那么我们再来看看这个警告的信息是啥意思呗,No subshaders can run on this graphics card,这个信息也很明确,就是说在你当前的这个显卡上没法执行这个 AssetBundle 中打包的 Shader 中的 subshader。噢,原来如此,针对移动平台打包的 Shader 应该是针对移动设备显卡进行适配和优化的,因为它们通常都是基于 OpenGL ES 标准的,而 Windows 和 OSX 分别是机遇 Direct X 和 OpenGL 的,这也就说得通了。

但是我们还会问一个问题,那就是我明明已经将我的 Unity Editor 的 Build Setting 设置为了目标移动平台,例如 iOS 或者 Android 了啊,为啥加载 AssetBundle 中的 Shader 进行显示时,这个 Unity Editor 就不能按照在手机上的机制来加载这个 AssetBundle 中的 Shader 资源并进行渲染呢?好吧,你把我问住了,实际上我也并不知道为什么 Unity 没有这么做,跪了。那我们就放狗搜索一下吧,最终我找到了两篇不错的文章,咱们先来看 这篇点睛之文 ,这个讨论中有一个名字叫 superpig(超猪)的 Unity 官方的哥们写了以下两个回复:

Just to be clear: this is not one single bug.

The pink material stuff just means there was a problem setting up the material and/or shader. There’s a bunch of ways this can happen. Two of them include:

  • Loading bundles on one platform that were built for another. For example, if you build your bundles for iOS and then try loading them on PC, it won’t work because PC needs the Direct3D versions of the shaders and the bundle won’t contain those (because there is no Direct3D on iOS). To fix this you just need to make sure that the bundles you are loading were built for the platform you are loading them on.
  • Failing to load the bundle that contains your shader (or loading it after the one with the material in). As of Unity 5.0 the AssetBundle pipeline will calculate the dependencies between the bundles, but it won’t automatically load the bundles for you (because in general it has no idea where to get them from). To fix this you just need to load all the required bundles, and you need to do it in the correct order. The AssetBundleManager demo project on the Asset Store demonstrates how you can use the AssetBundleManifest to implement your own automatic dependency loading.

We can and will improve the error reporting around these scenarios, but in both cases there is no engine ‘bug’ per se – just a relatively unhelpful failure behavior.

So, if you are still facing this issue, and neither of the mistakes described above fix your problem, please file a bug report instead of assuming that somebody else has done it – because it is very likely that their problem is not the same as yours exactly, and their problem will get fixed, but yours will not because it’s actually a different case.

——————– 我是两个不同论坛回复内容的分割线 ——————

Switching the platform to Android won’t work. If your Editor is running on Windows, you need a Windows version of the bundle. If it’s Mac, you need a Mac version. It doesn’t matter which platform is your active build target platform.

我把重点的内容标红了一下,看完了这两段回复之后,我们终于搞清楚了 Unity 对于 AssetBundle 中编译打包的 Shader 是个什么处理机制了,这就因为着我们在 Unity Editor 中如果需要正确加载 AssetBundle 中 Shader 并进行渲染的话,我们就需要使用针对我们 Unity Editor 所在的宿主系统环境进行打包,例如我们使用的是 Windows 系统下的 Unity Editor 那么就需要使用针对 Windows 平台打包的 AssetBundle,对于 OSX 系统也是一样的。

至此我们就可以再赶紧验证一下看看素不素这个鬼样子的,建议在资源很少的工程中单独进行实现,因为我知道你们的 Unity Editor 现在肯定是在某个移动平台的 Build Setting 下的,这样贸然打包一个非移动平台的 AssetBundle 会直接触发 Unity Editor 整个的 Switch Platform 操作,我想你肯定不会想这样的,我们都已经被 Unity Editor 这个切换平台耗费过很多生命了。最终测试通过,确实如这位「超猪」先生所说的。


本文原本到这儿呢,就应该结束了,对不对捏?嗯,是的,但是我还有些话需要说,那就是我自己在碰到这个问题的时候我第一时间也放狗搜索了,找到了很多类似的解决方案,大部分都说可以通过在加载 AssetBundle 资源成功之后,将其中的 Material 资源读取出来,然后将这些 Material 使用的 Shader 重新设置一遍,然后就可以了(其实在放狗之前,我自己已经发现可以通过自己手动地在 Editor 中对这些显示出错的 Material 指定一下 Shader 就可以让其正确显示了)。那么这个问题的根源是啥呢?把这个归结为 Unity 的 Bug?显然,这样是一种很不负责任的做法,因为我只用了一个很简单的测试就把这个 Hack Fix 给推翻了,并且确定了这并非 Unity 的问题。

测试这个 Hack Fix 是否真正触及到问题的根源很简单。

首先,我们准备一个工程用于创建 AssetBundle 资源,名为 CreateAssetBundle,在这个工程里头我们只放我们需要打包的 Model、Texture、Material 和 Shader 等资源文件,然后创建一个使用了这些资源的 Prefab 文件,再将我们创建出来的 Prefab 文件打包成为 AssetBundle 文件,这样我们就准备好了一个可用的 AssetBundle 文件了,对伐。

接下来,我们创建一个新的空工程,只把上一步中打包出来的 AssetBundle 资源放到 Assets/StreamingAssets 目录下,然后我们读取这个 AssetBundle 资源,取出里头的 Prefab 资源,在场景中实例化一下,并且使用下面这段 Hack Fix 代码:

然后你会发现,WTF,根本就是然并卵嘛,说好的自行车呢?那么我们再来问问自己,这段代码最核心的是啥?

就是使用 Shader.Find (string name) 方法重新按照我们 Prefab 中指定使用的 Shader 名称在整个程序内容空间中查找了一次 Shader,然后如果成功找到的话,就将其重新设置给我们从 AssetBundle 中读出来的 Material 对象,对伐?那么为何网上那么多的人都说这个解决了他们的问题呢?而且然后就没有然后了呢?

咱们来想想我们为啥会碰到出现在 Editor 中出现加载了 iOS 或者 Android 平台的 AssetBundle 资源呢?也就是我们还是在开发的过程中,我们已经将某一部分资源针对移动平台打包了,这些资源中会把我们在工程中的 Shader 文件一并编译打包,但是我们的工程中的 Shader 文件并不会移除,所以在 Editor 中运行游戏时,当我们出现了因为 Editor Host 不支持针对移动平台编译的 AssetBundle 中的 Shader 渲染的情况时,我们通过了一个上面代码中的 Hack 的手段,使用了 Shader.Find 方法,而且这个方法查找到的就只是工程中未编译的 Shader,根本就不会去我们加载的 AssetBundle 中加载,实际上是在运行时将游戏中的 Materail 中使用的 Shader 偷换成了我们工程中的 Shader,而这些 Shader 并未编译成某个移动平台的,在 Editor Host 环境下肯定是可以正常渲染的,否则我们早都发现渲染不对了。这就是为何我需要创建一个新的空的工程来测试我们打包出来的 AssetBundle 资源,这样我们就可以保证我们在工程中不会有同名的 Shader,如此一来这个 Shader.Find 方法肯定是找不到同名的 Shader 了,因为我们这个工程就只有一个 AssetBundle 资源,由此我们就找到了整个问题的各个根源,同时也对网上很多解决方案中提出来的 Hack 方法也提出了疑问并做出了自己的解答。

不过话再说回来,如果为了省事避免维护多个不会使用到的平台的 AssetBundle(通常我们的游戏都只会在 Android 和 iOS 平台发布,实际上 Windows 和 OSX 平台下的 AssetBundle 就没有什么必要维护了),这个 Hack 还是可以用的,但是我们还是要搞清楚为啥这个东西是可用的,下次如果碰到类似的问题或者不是 Shader 的问题,至少也可以提供一个正确的思考方式和参考。

Alfred2 有道翻译 Workflow 不可用的解决方法

一直在使用的 Alfred2 有道翻译的 Workflow 今天突然就不能使用了,刚开始以为是网络的问题,多次确认之后排除了网络的原因。想着可能是有道翻译的 API 更新了,使用以前的 API 调用会失败,然后就想着看看这个 Workflow 中使用的是哪个 API,那么怎么查看这个 Workflow 究竟用的是哪个 API 呢?

我们一步步来吧,首先打开 Alfred2 的设置页面,选中 Workflows Tab 页:

Alfred2 Settings -> Workflows Tab然后双击标题为 yd 的 Script Filter,或者右键选中标题为 yd 的 Script Filter,然后选择 Configure 菜单项,进入 yd Script Filter 的配置界面:

Alfred2 Youdao Workflow Configure

然后我们会看到一些命令啥的,不要管它咯,直接点击右下方那个 Open workflow folder 按钮,打开这个有道翻译的 Workflow 资源存放目录,如下:

Alfred2 Youdao Workflow Folder

从上一个设置页面中,我们可以看到 translate.php 文件应该是真正干活的脚本,所以我们打开目录中的 translate.php 脚本文件,然后我们就可以看到这个脚本是如何通过访问有道的开放 API 来完成翻译的工作的。

translate.php

用红色标注出来的两个参数就是这个 Workflow 不再工作的原因,可能是因为有道翻译的这个 Workflow 使用的人太多,而大家都是直接从 alfredworkflow 上下载的,Workflow 中的 API Key 就是这个 Workflow 的作者当时自行申请的一个 Key,而有道对于每个 API Key 有一个每日访问次数限制为 1000,所以很有可能就是因为现在使用 keyfrom=SeekBetterMe&key=164530784 这两个参数的人太多导致 API 访问次数超限了,所以有道翻译已经不再返回查询结果了。

那么既然找到问题了,我们只需要自己申请一个新的给自己用的 API Key 就好了。找到 有道翻译 API 的首页

有道翻译 API 首页

点击我是开发者,进入调用数据接口页面,填写正确的网站信息,马上就可以获取一个专属于自己的 API Key,然后将其替换到 translate.php 文件中就可以了。

申请有道翻译 API Key

然后保存 translate.php 文件,重新呼出 Alfred2 有道翻译的 Workflow 就可以了。