魅族16s中国版刷成国际版

前段时间浏览flyme国际版的时候发现魅族16s的国际版固件已经发布了,正好这周末没什么事,就顺手把手里的魅族16s刷成了国际版。在魅族论坛发现有些同学不会刷国际版,就把刷机教程放到这,希望对这些同学提供点帮助。

前段时间浏览flyme国际版的时候发现魅族16s的国际版固件已经发布了,正好这周末没什么事,就顺手把手里的魅族16s刷成了国际版。在魅族论坛发现有些同学不会刷国际版,就把刷机教程放到这,希望对这些同学提供点帮助。

手机刷成国际版后使用了两天,首先说一下这两天的使用感受。

第一、手机比以前清爽了许多,虽然国际版也有广告,但是比原版少了很多。

第二、自带Google全家桶,可以很方便的使用Google的服务(需要有翻墙环境)。

第三、虽然国际版的的版本号是Flyme 7.2.3.0G,但是原版7.3的一些特性如DC调光、彩色息屏显示国际版也有。

第四、国际版和原版固件的电量消耗没有明显的区别,正常使用1天应该不成问题。

第五、使用国际版对网络的要求比较高,需要网络能够科学上网。如果没有科学上网网络,刷机之后第一步的Google验证就很难跳过。

第六、国际版没有Meizu Pay,无法使用手机nfc充当公交卡。

第七、有些国内APP没有上传Google Play,魅族国际版的App Store收录的软件更少。所有安装一些国产APP只能单独下载安装或通过第三方软件商城安装。

使用情况介绍完了,以下是刷机方法。

一、注意事项

1、刷机需要root手机,root手机可能导致失去保修。

2、因为目前还没有root国际版固件的方法,刷到国际版固件后还没有刷回国内版的方法。

3、刷机前请保持手机电量充足,如果刷机过程中电量不足可能会导致手机变砖。

4、刷机会清空手机内的文件,刷机前请备份手机的内的重要内容,以防丢失。

二、刷机前的准备

1、申请root手机

现在可以通过魅族网站申请root魅族手机,网站如下:Root授权,根据网站提示root手机。

2、需要有能够科学上网的网络和Google账号,不具备这个条件很难跳过初始的Google验证。

3、下载flyme国际版固件到手机sdcard根目录,下载地址如下:Flyme 7.2.3.0G

4、安装Android端终端软件,我这里使用的是Termius,下载地址如下:Termius

添加本地控制台

4、下载国际版设备的proinfo文件放到手机sd卡根目录,地址如下:proinfo-global.img(sha256:d19ec1c6778e04214db0f4eecd2636f44dd391903509254e9c1d805fb7e6c8d3)。

准备就此完成,下面进入刷机阶段。

三、刷机步骤

1、打开之前安装的Terminus软件,进入Local Terminal。

2、在终端中输入以下命令获取root权限,手机会提示是否授权root权限,选择一直同意。

su 

3、输入已下命令备份手机原有的proinfo分区

dd if=/dev/block/by-name/proinfo of=/sdcard/proinfo-bak.img

4、将国际版proinfo文件刷入分区,请注意一定不要刷错分区,否则会导致手机变砖。

dd if=/sdcard/proinfo-global.img of=/dev/block/by-name/proinfo

5、确认国际版updae.zip 文件放入手机sdcard根目录,关闭手机,待手机关机后,同时按住手机音量上键和开机键使手机进入recovery模式,选择更新系统和清除手机数据,对固件进行更新。更新完成后会自动重启,此时就进入了国际版系统。

国际版系统需要能够科学上网和Google账户来进行手机验证,验证完成后就可以正常使用手机了。

微信赞赏码

Let’s Encrypt 申请泛域名证书

Let’s Encrypt是一个有名的免费SSL证书颁发机构,最近更新了ACME v2.0版本,支持泛域名SSL证书签发。

前言

Let’s Encrypt是一个有名的免费SSL证书颁发机构,最近更新了ACME v2.0版本,支持泛域名SSL证书签发。

https://letsencrypt.org/2017/07/06/wildcard-certificates-coming-jan-2018.html

我的域名使用的CoudXNS解析同样由它提供。对于使用CloudXNS解析的域名,已经有自动化的工具来获取并自动更新SSL证书,详见:https://github.com/Neilpang/acme.sh

泛域名证书(目前只支持签发测试版泛域名证书,证书不被浏览器信任)

下面是获取泛域名证书的过程(使用Debian 9系统):

1、安装acme.sh


git clone https://github.com/Neilpang/acme.sh.git .acme.sh

cd ./acme.sh
./acme.sh --install

2、获取证书


#这里输入你的API KEY 和SECRET KEY
export CX_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
export CX_Secret="jlsdflanljkljlfdsaklkjflsa"
#注意这里的证书服务器是ACME-v2版本的。
#使用*.example.com表示泛域名
# -dns后加上所使用dns服务商,这里是dns_cx
acme.sh --server https://acme-v02.api.letsencrypt.org/directory --issue -d example.com -d *.example.com -dns dns_cx

以上命令运行完毕后就会在当前名录下生成泛域名证书

3、目前支持的DNS服务商

  1. CloudFlare.com API
  2. DNSPod.cn API
  3. CloudXNS.com API
  4. GoDaddy.com API
  5. PowerDNS.com API
  6. OVH, kimsufi, soyoustart and runabove API
  7. nsupdate API
  8. LuaDNS.com API
  9. DNSMadeEasy.com API
  10. AWS Route 53
  11. aliyun.com(阿里云) API
  12. ISPConfig 3.1 API
  13. Alwaysdata.com API
  14. Linode.com API
  15. FreeDNS (https://freedns.afraid.org/)
  16. cyon.ch
  17. Domain-Offensive/Resellerinterface/Domainrobot API
  18. Gandi LiveDNS API
  19. Knot DNS API
  20. DigitalOcean API (native)
  21. ClouDNS.net API
  22. Infoblox NIOS API (https://www.infoblox.com/)
  23. VSCALE (https://vscale.io/)
  24. Dynu API (https://www.dynu.com)
  25. DNSimple API
  26. NS1.com API
  27. DuckDNS.org API
  28. Name.com API
  29. Dyn Managed DNS API
  30. Yandex PDD API (https://pdd.yandex.ru)
  31. Hurricane Electric DNS service (https://dns.he.net)
  32. UnoEuro API (https://www.unoeuro.com/)
  33. INWX (https://www.inwx.de/)
  34. Servercow (https://servercow.de)
  35. Namesilo (https://www.namesilo.com)
  36. InternetX autoDNS API (https://internetx.com)
  37. Azure DNS
  38. selectel.com(selectel.ru) DNS API
  39. zonomi.com DNS API
  40. DreamHost.com API
  41. DirectAdmin API

参考文章

泛域名SSL证书获取——Let’s Encrypt

acme.sh

将Google Analytics移到服务端

一般地,网站配置 Google An­a­lyt­ics 的常见方式是在网站前端引用 Google Analytics 的 trackercode,然后获取 analytics.js 并开始统计用户行为。由于国内访问Google不顺畅,这种方式使用Google  Analytics造成国内的访问缓慢。虽然通过使用大公司的 ga.js 的 CDN ,可以很大程度上加快加载 ga.js 文件的速度( ga.js 的更新频率很高,并不适合缓存到本地或服务器)。但无论如何还是要向 Google 发送一个请求来发送访客数据,所以取巧地使用 CDN 并不能从根本上解决问题。

Google Analytics

前言

一般地,网站配置 Google An­a­lyt­ics 的常见方式是在网站前端引用 Google Analytics 的 trackercode,然后获取 analytics.js 并开始统计用户行为。由于国内访问Google不顺畅,这种方式使用Google  Analytics造成国内的访问缓慢。虽然通过使用大公司的 ga.js 的 CDN ,可以很大程度上加快加载 ga.js 文件的速度( ga.js 的更新频率很高,并不适合缓存到本地或服务器)。但无论如何还是要向 Google 发送一个请求来发送访客数据,所以取巧地使用 CDN 并不能从根本上解决问题。

在 JerryQu 的 《本博客零散优化点汇总》 一文中提到他是如何处理 Google Analytics 的:

把统计逻辑挪到了服务端;自己生成用户唯一标识,获取访问页面的标题、URL、Referer,获取用户 IP 和浏览器 UA,随着每次访问发给 Google 的统计地址。服务端向 Google 发起的请求是异步的,用户端访问速度丝毫不受影响。

Google Analytics 的 官方文档 给出了相关介绍,Google 也提供了 Measurement Protocol

Google Analytics 异步方案

目前常见的是这两种方法:完整的后端方案和前端和后端搭配的方案。

前者通过配置 Nginx,使用 uid 模块和 proxy_pass 向后端转发请求;后者的方案则是通过 JS 发送请求给中转服务,再由中转服务器异步发送给 Google。对于前者的解决方案的实现可以阅读下述文章:

还有一种方案,就是在前端通过 JS 发起一个请求、生成用户端的信息带到请求的 URI 上,然后后端的有关程序监听这个请求,并异步发送给 Google。

对于这种解决方案,有人写了一个 Node.js(基于 ThinkJS) 的程序实现:《服务端使用 Google Analytics》

PHP异步方案

我想,没有 Node.js 支持的虚拟主机,又不是所有人都有独立的 VPS 的,也不是所有人都使用 Node.js 的。所以我根据这种思路,找到了个 PHP 版的。


<?php
// ********************
// * Author: stneng
// * Date: 2016.12.11
// * Introduction: https://u.nu/ytq
// *********************
    header("status: 204");
    header("Cache-Control: no-cache, max-age=0");
    header("Pragma: no-cache");

    $tid='';  // 在这里写 Google Analytics 给的 tid,形如:UA-XXXX-Y

    function create_uuid(){$str = md5(uniqid(mt_rand(), true));
        $uuid = substr($str,0,8) . '-';
        $uuid .= substr($str,8,4) . '-';
        $uuid .= substr($str,12,4) . '-';
        $uuid .= substr($str,16,4) . '-';
        $uuid .= substr($str,20,12);
        return $uuid;
    }

    if (!isset($_COOKIE["uuid"])) {$uuid=create_uuid();
        setcookie("uuid", $uuid , time()+368400000);
    }else{$uuid=$_COOKIE["uuid"];
    }

    if (function_exists("fastcgi_finish_request")) {fastcgi_finish_request(); // 对于 fastcgi 会提前返回请求结果,提高响应速度。
    }

    $url='v=1&t=pageview&';
    $url.='tid='.$tid.'&';
    $url.='cid='.$uuid.'&';
    $url.='dl='.rawurlencode(rawurldecode($_SERVER['HTTP_REFERER'])).'&';
    $url.='uip='.rawurlencode(rawurldecode($_SERVER['REMOTE_ADDR'])).'&';
    $url.='ua='.rawurlencode(rawurldecode($_SERVER['HTTP_USER_AGENT'])).'&';
    $url.='dt='.rawurlencode(rawurldecode($_GET['dt'])).'&';
    $url.='dr='.rawurlencode(rawurldecode($_GET['dr'])).'&';
    $url.='ul='.rawurlencode(rawurldecode($_GET['ul'])).'&';
    $url.='sd='.rawurlencode(rawurldecode($_GET['sd'])).'&';
    $url.='sr='.rawurlencode(rawurldecode($_GET['sr'])).'&';
    $url.='vp='.rawurlencode(rawurldecode($_GET['vp'])).'&';
    $url.='z='.$_GET['z'];
    $url='https://www.google-analytics.com/collect?'.$url;
    $ch=curl_init();
      curl_setopt($ch, CURLOPT_URL, $url);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      curl_exec($ch);
      curl_close($ch);

?>

将上述代码保存为 google.php,放在网站根目录。

当然你也可以命名为其它的,不过你需要修改下述提到的 script。

在页面中插入下述代码:

<script>!function(e,n,o){var t=e.screen,a=encodeURIComponent,r=["dt="+a(n.title),"dr="+a(n.referrer),"ul="+(o.language||o.browserLanguage),"sd="+t.colorDepth+"-bit","sr="+t.width+"x"+t.height,"vp="+e.innerWidth+"x"+e.innerHeight,"z="+ +new Date],i="?"+r.join("&");e.__beacon_img=new Image,e.__beacon_img.src="/google.php"+i}(window,document,navigator,location);</script>

上面这段代码是直接修改自 imququ.com 的 ana_js如下:


(function(window, document, navigator, location) {
var screen = window.screen;
var encode = encodeURIComponent;

var data = ['dt=' + encode(document.title),
'dr=' + encode(document.referrer),
'ul=' + (navigator.language || navigator.browserLanguage),
'sd=' + screen.colorDepth + '-bit',
'sr=' + screen.width + 'x' + screen.height,
'_=' + (+new Date)
];

var query = '?' + data.join('&amp;');

window.__beacon_img = new Image();
window.__beacon_img.src = '/ga.php' + query;
})(window, document, navigator, location);

这段 JS 代码完成了 URI 生成和发起请求两个操作。

后端 PHP 程序包含了 uuid 生成、cookie 校验和转发请求三个部分。

首先是用 md5 生成符合 Google Analytics 的唯一用户 uid,作为辨别不同用户的依据。
然后会从客户端的 cookie 来进行匹配,判断是否是回访的访客。如果客户端没有相关 cookie,这个请求就会把 uuid 写进用户端的 cookie 中。
然后就是解析 URI,通过请求采集请求的 URI 获取有关信息,然后组成 www.google-analytics.com/collect 适用的 URI。
最后就是服务端通过发起 cURL 请求 www.google-analytics.com,把统计的页面行为提交给 Google 即可。

转载修改自:Google Analytics 异步化方案

SmartOS的系统服务体系

SmartOS以及类illumos的OS,其服务体系采用的SMF机制,是一个具有依赖关系的服务网络。理解这些后台服务,需要从它们之间的依赖关系开始着手,通过查看Manifest定义文件,理解它们,以及试图尝试解决它们的问题。

前言

为什么要理解一个服务器OS的系统服务体系?

因为作为一个服务器OS,实际上与管理员与用户有关系的,能感受到的,主要就是这些跑在后台的服务。

打个比方,手机OS不刷不死心人,整天关心的就是后台都跑了多少服务,应该怎么杀。那么对比服务器OS折腾星人,不了解后台到底都是跑的些啥,显然不专业。(当然就不要想着杀了,会杀出问题来。)

所以,想要显摆自己有多精通一个服务器OS,不入门到精通这些后台服务是不行的。

SMF框架

SmartOS继承了illumos的衣钵,系统服务组织上,采用了一种叫做SMF的先进框架。因此我们要先理解什么是SMF?

从维基百科上可以找到SMF的页面,摘录并翻译如下

Service Management Facility (SMF)是Solaris操作系统引入的一项功能,它能创建可维护的,统一的服务与服务管理模型,它取代了init.d。

看到这里我相信大家都有一个呼声:

能不能说人话?

好吧说人话。

直白的说就是Solaris的那帮开发者(现在是illumos的开发者)看unix/linux的init.d十分不爽,就另行开发了一个系统取代之。这个系统称之为SMF,这个系统将解决一些在*nix系统服务里面积累多年的问题。

*nix系统服务到底有啥问题?

老实说,这不是一个很容易让人意识到其重要性的问题。因为大部分用户一辈子,需要处理这东西几率不高。

但是做为一个系统管理员是不可以不理会它的。

Unix系统,以及大部分的linux系统,使用的系统服务框架为init。简单的总结,init是*nix系统在内核启动之后,所启动的第一个应用程序,由它再来负责启动之后的所有的应用程序与服务。所以init做为一个程序,它的运作模式就定义了系统服务框架的机制。

形象的说,*nix系统的启动是这样的

  • 当按下机箱上电源键之后,机器会傻傻的直接执行储存在主板上的应用程序(即BIOS);
  • BIOS一根筋的检测完硬件之后,去启动主硬盘的引导区的那个引导程序。现在应用的最广泛的引导程序叫做grub(除开MacOS和Windows外);
  • grub会做一些初始化文件系统的脏活儿,读取一个配置文件,去启动真正想要的内核;
  • 内核在这个时候被载入内存启动了。跟前面步骤的那些应用程序执行完了就把自己杀掉不同,内核不会杀掉自己。它会把你的机器硬件弄成可以共享的形式,欢迎后面的应用程序来共享使用;
  • 然后内核就不直接过问具体的凡间事物(或者说user land),它会启动一个新的应用程序,来负责启动其他的应用程序。

最后那个应用程序就是init。

作为所有后面应用程序的入口,大家应该都意识到了,这是流量的入口啊,怎么管理好这个入口有大学问。比如怎么雁过拔毛,收收买路钱,甚至强迫别人内置几个广告的事情,这事情大家应该都心里有数,我明白的。

但是init是70年代就诞生的,那时候人心还挺淳朴,所以init也特别的头脑简单。

init定下了如下的规则

所有需要让我启动的程序,排成不同运行等级(run level)的队伍,按照队伍级别高低和名字顺序,一个一个来

有入口的地方就有江湖,谁先谁后怎么插队一直是人民群众特别关心的问题。在init的简单规则下,想插队,只能调高自己的等级,或者改个能排在前面的名字。

显然这一套能运作30多年就是个奇迹。

想一想,这一套至少会有这些问题

  • 等级划分太简单。*nix一般就6个运行等级,其中level 0和6有特殊含义,level 4被保留了。能用就1,3和5。特权阶级和非特权阶级通通挤在一起,有啥事儿不能听领导的再行动(即依赖关系)。
  • 一个一个来,那万一有人耍赖怎么办?比如网络方面的服务只要排在tcp/ip相关的服务后面即可以,但是文件系统排在更前面,它要是出点问题还要影响网络这边的事儿。
  • 都是用root来执行的。这个对一些关键服务还可以说,但是什么打印机啊之类的有必要么?人家黑了你打印机服务就顺带端掉了整个系统。
  • init启动过一次就不管了,之后这些服务就自生自灭,这可不好,至少得有个自动重启什么的增值服务吧。

回到SMF

SMF的发明者将*nix的问题总结了一下,创造了SMF这个init的替代者,它有如下特点:

  • 引入依赖关系。一个服务可以依赖另几个服务,满足不了条件就不起动或者暂停。
  • 引入权限控制。打印机服务这种让linus都抓狂的服务,就让它在低权限跑去吧。
  • 引入守护机制。死了帮你重启,重启不成就帮你暂停,以及暂停其他所有依赖这个服务。
  • 用基于xml的配置文件,取代了简单的使用init.rc*文件夹以及文件名来组织各个服务。这个不用解释,因为init的那一套只能说是太原始了。

扯这么多概念,整点实用的行不行?

行。

先来三板斧

查看系统当前运行的服务

输入svcs.


$ svcs
STATE          STIME    FMRI
...
online         Sep_22   svc:/system/svc/restarter:default
online         Sep_22   svc:/system/filesystem/autofs:default
online         Sep_22   svc:/system/system-log:default
online         Sep_22   svc:/network/smtp:sendmail
online         Sep_22   svc:/system/filesystem/local:default
online         Sep_22   svc:/network/ssh:default
online         Sep_22   svc:/system/dumpadm:default
online         Sep_22   svc:/network/loopback:default

类似这样的结果,主要也就是看个状态,online/offline/maintenance三种,看字面也知道除了online,多半都是不太好的结果,需要果断进行处理。

常用的处理的方式有

  • svcadm disable 禁用
  • svcadm enable 启用

查看有问题服务的日志文件

具体某个服务的日志文件,一般是位于/var/svc/log/.log里面。

例如svc:/system/filesystem/autofs:default的日志文件就在/var/svc/log/svc:/system/filesystem/autofs:default.log

出现什么问题的服务,多看看日志文件,才能定位问题。

查看服务的依赖与被依赖关系

既然存在依赖关系,那么查询出来总会对定位解决问题有好处,这方面的命令常用的有

  • svcs -d 查询服务依赖的所有服务
  • svcs -D 查询依赖服务的所有服务

举个例子


$ svcs -d milestone/multi-user
STATE          STIME    FMRI
disabled       Sep_22   svc:/network/smtp:sendmail
online         Sep_22   svc:/milestone/name-services:default
online         Sep_22   svc:/milestone/single-user:default
online         Sep_22   svc:/system/filesystem/local:default
online         Sep_22   svc:/network/rpc/bind:default
online         Sep_22   svc:/milestone/sysconfig:default
online         Sep_22   svc:/system/utmp:default
online         Sep_22   svc:/network/inetd:default
online         Sep_22   svc:/network/nfs/client:default
online         Sep_22   svc:/system/system-log:default

顺藤摸瓜去查找服务以及所有依赖的服务的问题,就是系统管理员通常要做的事情。

理解SmartOS的服务体系

明白了SmartOS所用的服务系统的机制,接下来就是具体的看看这个服务体系到底是怎样的。

实际上,在SMF的支撑下,SmartOS的服务体系发展的异常的强大。支持系统的,不再是一些独立的互不相干的服务,而是一张服务的网。

SmartOS的服务体系

上图即展现了这张网。实际上,它是截图自这个工具。它是一个互动的工具,可以用来形象的展现DogeOS的系统服务网络。

例如要查询一下svc:/milestone/single-user:default这个服务所依赖的全部服务,只需要在左边的下拉框里面找到这个FMRI就可以了。一目了然,我们就可以知道要保证其成功,需要一些什么样的服务作为先导。

实际上,所有带有milestone关键字的服务,是一种特殊的服务。它们实际上模拟了init系统里面的level的概念。在这个对应关系里,svc:/milestone/single-user:default就相当于init的level 1,是单用户模式,而svc:/milestone/multi-user:default就相当于init的level 3,是多用户模式。

还有一个问题

一个服务具体是如何定义的呢?

它实际上是由一个叫做SMF manifest的XML文件来定义的。这些文件主要位于/etc/svc/manifest目录中。这个目录中又按照不同的类别分成了若干个子目录。例如svc:/milestone/single-user:default实际上就位于milestone子目录中。透过名字上的联系,相信也很容易猜测到组织这些文件的一些习惯。

找到了定义服务的XML文件,再来解读它,就变得容易了。关于Manifest的具体怎么写,如何读懂它,可以参考这个规范。

Manifest通常会定义一些start/stop/restart的命令,其内容又通常会指向一个shell脚本,顺着这条线,我们就不难搞清楚这个服务到底做了一些什么事情。

总结

SmartOS以及类illumos的OS,其服务体系采用的SMF机制,是一个具有依赖关系的服务网络。理解这些后台服务,需要从它们之间的依赖关系开始着手,通过查看Manifest定义文件,理解它们,以及试图尝试解决它们的问题。

转自DogeOS/SmartOS的系统服务体系

SmartOS Diskless Booting与SMF

SmartOS 的diskless booting的架构是它的重要的特性之一,也是我们了解一个操作系统很好的切入点,我这里我们就通过介绍SmartOS的这个特性,以及SmartOS的启动过程来看它是如何实现的?以及SMF在这个启动过程中扮演了什么角色?

前言

SmartOS 的diskless booting的架构是它的重要的特性之一,也是我们了解一个操作系统很好的切入点,我这里我们就通过介绍SmartOS的这个特性,以及SmartOS的启动过程来看它是如何实现的?以及SMF在这个启动过程中扮演了什么角色?下面我们来一一介绍。

SmartOS Diskless Booting

SmartOS Diskless Booting实际上是将它的操作系统,安装在了ramdisk上(也就是内存中), 然后直接通过USB/CD/PXE来启动它,那这么做的好处是什么?

  • 系统更新简单: 每次重启即可。
  • 增加了磁盘的空间: 操作系统本身不占用磁盘空间, 某中程度上也增加了磁盘的性能。
  • 增加了安全性:大部分的系统文件是只读的,/root/etc目录每次重启都重置,/usr目录也是只读, 无法添加用户。对SMF服务的修改也是每次都重置。
  • 系统稳定性提高: 不会出现操作系统在磁盘,而磁盘坏掉导致整个OS无法启动。

那么SmartOS的global zone上哪些目录是可写的?


Filesystem             Size   Used  Available Capacity  Mounted on
zones                  2.0T   143M   1.8T     1%    /zones
zones/var              2.0T   4.0G   1.8T     1%    /var
zones/opt              2.0T    55K   1.8T     1%    /opt
zones/usbkey           2.0T   154K   1.8T     1%    /usbkey
/usbkey/shadow         1.8T   154K   1.8T     1%    /etc/shadow
/usbkey/ssh            1.8T   154K   1.8T     1%    /etc/ssh

这里列出的目录为可写, zones是使用了所有磁盘的一个大zpool, SmartOS会在启动的时候创建一些文件系统挂载上去。

SmartOS 启动过程

我们从按下机箱电源按钮说起, 看下图会比较清楚:

smartos 启动过程

  • 当按下机箱上电源键之后,机器会直接执行储存在主板上的BIOS应用程序;
  • BIOS检测完硬件之后,去启动主硬盘的引导区的那个引导程序。现在应用的最广泛的引导程序叫做GRUB;
  • GRUB会做一些初始化文件系统的活儿,读取一个配置文件(menu.lst),去启动真正想要的内核(platform/i86pc/kernel/amd64/unix)boot archive(platform/i86pc/amd64/boot_archive文件);
  • 内核在这个时候被载入内存启动了。跟前面步骤的那些应用程序执行完了就把自己杀掉不同,内核不会杀掉自己。它会把你的机器硬件弄成可以共享的形式,后面的应用程序来共享使用;
  • 然后内核会启动一个新的应用程序(/sbin/init, pid=1),来负责启动其他的应用程序。

接着看下图:

smartos smf 服务管理

  • init服务会启动svc.startd这个进程,用来启动和停止所有的SMF服务。

到这里Kernerl和boot_archive都已经加载, startd服务启动,我们看下systemfile的挂载情况:


Filesystem             Size   Used  Available Capacity  Mounted on
ctfs                     0K     0K         0K     0%    /system/contract
proc                     0K     0K         0K     0%    /proc
mnttab                   0K     0K         0K     0%    /etc/mnttab
swap                    43G   984K        43G     1%    /etc/svc/volatile
objfs                    0K     0K         0K     0%    /system/object
bootfs                   0K     0K         0K     0%    /system/boot
sharefs                  0K     0K         0K     0%    /etc/dfs/sharetab

以上这些文件系统的挂载由kernel完成。根据细节服务要看illumos源码,比如restarter/boot-config/svc.configd服务等。

到了这里我们必须要说一下SmartOS的运行级别。

SmartOS Run level

SmartOS提供了8个run level,如下:


0         - system running PROM monitor (ok> prompt)
s or S    - single user mode with critical file-systems mounted.(single user can access the OS)
1         - single user administrative mode with access to all file-systems.(single user can access the OS)
2         - multi-user mode. Multiple users can access the system. NFS and some other network related daemons does not run
3         - multi-user-server mode. Multi user mode with NFS and all other network resources available.
4         - not implemented.
5         - transitional run level. Os is shutdown and system is powered off.
6         - transitional run level. Os is shutdown and system is rebooted to the default run level.

正常情况下启动SmartOS运行的runlevel是3, 即多用户共享模式。我们可以通过who命令来查看当前的runlevel:


$ who -r
.       run-level 3  Jun 10 09:14     3      0  S 

当然你还可以通过init命令来切换当前的runlevel,比如你想切换到单用户模式: init s 即可。

对于传统的init服务的启动是按照不同的runlevel去执行对应的/etc/rc?.d/K* and /etc/rc?.d/S* 脚本, ?为运行级别, 这种方式在SmartOS中还是支持的,但主要为了兼容legacy的系统,并不推荐,目前使用的基于SMF的方式。那么是SMF是如何支持runlevel的?

实际上是通过category是milestone的smf来定义runlevel:


/etc/rcS.d => milestone/single-user:default #对应单用户模式
/etc/rc2.d => milestone/multi-user:default  #对应多用户
/etc/rc3.d => milestone/multi-user-server:default #对应多用户共享

在了解完SMF服务和runlevel的关系之后我们继续来看SmartOS的启动过程。从前面知道SmartOS默认启动在run level 3上,所以它会先运行完run level s和2的服务。下面我们先来分析run level s模式下smf服务的情况。

SmartOS 启动之: Run Level s

通过如下命令切换到run level s下面:


$ init s
$ svcs |grep milestone  #在run level s下面,启动了2个milestone服务
online          9:12:44 svc:/milestone/devices:default
online          9:14:17 svc:/milestone/single-user:default

这里提下/lib/svc/manifest/目录,这个目录中又按照不同的类别分成了若干个子目录, 定义主要的系统依赖的SMF服务。系统启动的时候startd服务会自动的根据依赖去加载这个目录中的SMF服务。

从这里我们看到milestone/devices服务是最先启动的,看看它依赖了什么服务。


svc:/milestone/devices
  svc:/system/device/local
    svc:/network/datalink-management #网络相关先放一边
  svc:/system/filesystem/usr
    svc:/system/boot-archive
        svc:/system/filesystem/root
            svc:/system/device/mpxio-upgrade #这个IO multipath的依赖是optional的
    svc:/system/scheduler
        svc:/system/filesystem/root 

这里通过svcs -d命令整理出来了依赖关系,我们看到了它最终依赖于filesystem/root这个服务, 那这个服务在启动的时候干了什么事情?通过/lib/svc/manifest/system/filesystem/root-fs.xml文件的定义找到/lib/svc/method/fs-root运行脚本,关键代码:


/sbin/mount -F ufs -o remount,rw,nologging /devices/ramdisk:a /
/usr/sbin/lofiadm -X -a /usr.lgz
/sbin/mount -F ufs -o ro /devices/pseudo/lofi\@0:1 /usr
#
# Update kernel driver.conf cache with any additional driver.conf
# files found on /usr, and device permissions from /etc/minor_perm.
#
/usr/sbin/devfsadm -I -P
libc_mount

实际上是将ramdisk上的文件系统mount到/, 通过lofiadm将usr.lgz文件(可执行文件和lib)做成块设备mount到/usr目录(read-only),最好将libc的标准库mount上来, 结果如下:


Filesystem             Size   Used  Available Capacity  Mounted on
/devices/ramdisk:a     262M   240M        22M    92%    /
/devices/pseudo/lofi@0:1
                       432M   377M        56M    88%    /usr
/usr/lib/libc/libc_hwcap1.so.1
                       432M   377M        56M    88%    /lib/libc.so.1
ctfs                     0K     0K         0K     0%    /system/contract
proc                     0K     0K         0K     0%    /proc
mnttab                   0K     0K         0K     0%    /etc/mnttab
swap                    43G   984K        43G     1%    /etc/svc/volatile
objfs                    0K     0K         0K     0%    /system/object
bootfs                   0K     0K         0K     0%    /system/boot
sharefs                  0K     0K         0K     0%    /etc/dfs/sharetab

接着我们往上追踪,找到_system/boot-archive_服务,/lib/svc/manifest/system/boot-archive.xml对应脚本/lib/svc/method/boot-archive看关键代码:


/sbin/bootadm update-archive -vnC 2> /dev/null 

这里只是更新了一下boot_archive, 我们接着看_filesystem/usr_服务/lib/svc/manifest/system/filesystem/usr-fs.xml 脚本/lib/svc/method/fs-usr, 关键代码:


mount /dev/fd
if smf_is_globalzone; then
    # svc.startd makes a backup of the repo on boot.  Since this is a
    # live-image, the backup takes up an unnecessary 4MB in memory, so remove
    # it now.
    rm -f /etc/svc/repository-*
fi

文件系统fd挂载到/dev/fd, 并在内存删除不必要的备份。 到这里_milestone/devices_服务启动完成, 看看系统中mount了什么:


Filesystem             Size   Used  Available Capacity  Mounted on
/devices/ramdisk:a     262M   240M        22M    92%    /
/devices/pseudo/lofi@0:1
                       432M   377M        56M    88%    /usr
/usr/lib/libc/libc_hwcap1.so.1
                       432M   377M        56M    88%    /lib/libc.so.1
fd                       0K     0K         0K     0%    /dev/fd # *** 新增加 ***
ctfs                     0K     0K         0K     0%    /system/contract
proc                     0K     0K         0K     0%    /proc
mnttab                   0K     0K         0K     0%    /etc/mnttab
swap                    43G   984K        43G     1%    /etc/svc/volatile
objfs                    0K     0K         0K     0%    /system/object
bootfs                   0K     0K         0K     0%    /system/boot
sharefs                  0K     0K         0K     0%    /etc/dfs/sharetab

接着看_milestone/single-user_服务,同样先整理下它的依赖关系:


$ svcs -d milestone/single-user:default #查看single-user服务的依赖, 实际上single-user也依赖devices服务
    online         Jun_10   svc:/system/cryptosvc:default
    online         Jun_10   svc:/network/loopback:default
    online         Jun_10   svc:/milestone/devices:default
    online         Jun_10   svc:/system/keymap:default
    online         Jun_10   svc:/system/filesystem/minimal:default
    online         Jun_10   svc:/system/sysevent:default
    online         Jun_10   svc:/system/manifest-import:default
    online         Jun_10   svc:/system/identity:node
    online         Jun_10   svc:/milestone/network:default

这里single-user服务的依赖非常深,这里就只看system相关的文件系统的服务,这样看的会清楚些,先看filesystem/minimal的依赖:


svc:/system/filesystem/minimal
  svc:/system/device/local       # 服务以启动完成
    svc:/network/datalink-management
  svc:/system/filesystem/usr     # 服务以启动完成
    svc:/system/boot-archive
    svc:/system/scheduler
  svc:/system/filesystem/smartdc  # 未完成
    svc:/system/filesystem/usr
      svc:/system/boot-archive
      svc:/system/scheduler 

从依赖来看,先分析_filesystem/smartdc_服务/lib/svc/manifest/system/filesystem/joyent-fs.xml找到脚本/lib/svc/method/fs-joyent,这里代码很多就不具体贴出来了,主要做了如下事情:

1、通过/usr/sbin/devfsadm -c disk命令创建/devices目录下所有磁盘设备文件并链接到/dev目录, 到这一步看看文件系统的挂载情况, 发现所有的磁盘设备都找到并挂载好了。


 Filesystem             Size   Used  Available Capacity  Mounted on
/devices/ramdisk:a     262M   240M        22M    92%    /
/devices/pseudo/lofi@0:1
                       432M   377M        56M    88%    /usr
/usr/lib/libc/libc_hwcap1.so.1
                       432M   377M        56M    88%    /lib/libc.so.1
fd                       0K     0K         0K     0%    /dev/fd
/devices                 0K     0K         0K     0%    /devices
/dev                     0K     0K         0K     0%    /dev

2、根据启动参数noimport看是否需要挂载zones pool的文件系统,如果需要则挂载如下设备:


Filesystem             Size   Used  Available Capacity  Mounted on
zones                  5.2T   524K       4.3T     1%    /zones
zones/cores/global      10G    19K        10G     1%    /zones/global/cores
zones/var              5.2T   5.9G       4.3T     1%    /var
zones/config           5.2T    66K       4.3T     1%    /etc/zones
zones/opt              5.2T    19G       4.3T     1%    /opt
zones/usbkey           5.2T   120K       4.3T     1%    /usbkey
/usbkey/shadow         4.3T   120K       4.3T     1%    /etc/shadow
/usbkey/ssh            4.3T   120K       4.3T     1%    /etc/ssh
swap                    44G    12K        44G     1%    /tmp
swap                    44G    12K        44G     1%    /var/run

下面我们分析_filesystem/minimal_服务,通过/lib/svc/manifest/system/filesystem/minimal-fs.mxl我们看到,这个服务什么都没做只是定义了依赖。到这里run level s就启动完成所有服务启动,看看目前文件系统状态:

SmartOS 启动之: Run Level 2

从上面run level 1来看,基本的OS服务已经都启动了,在run level 2上启动的主要服务如下:


$ init 2
$ svcs |grep milestone
online          9:12:44 svc:/milestone/devices:default
online          9:14:17 svc:/milestone/single-user:default
online          9:12:43 svc:/milestone/name-services:default # 新增
online          9:12:43 svc:/milestone/name-services:default # 新增
online          9:14:38 svc:/milestone/multi-user:default # 新增

这里我们照葫芦画瓢同样通过svcs -d 来查看服务依赖然后去看对应脚本就可以。

SmartOS 启动之: Run Level 3

最后到run level 3的服务如下:


$ init 3
$ svcs |grep milestone
online          9:12:44 svc:/milestone/devices:default
online          9:14:17 svc:/milestone/single-user:default
online          9:12:43 svc:/milestone/name-services:default
online          9:12:43 svc:/milestone/name-services:default
online          9:14:38 svc:/milestone/multi-user:default 
online          9:14:38 svc:/milestone/multi-user-server:default # 新增

这里就简单写下了,实在太长了,因为我没办法写短 🙂

SMF在SmartOS中扮演的重要角色

从上面对SmartOS的启动分析中我们可以看到,smf在其中的重要作用, 总结下SMF的提供的特性:

  • 引入依赖关系。一个服务可以依赖另几个服务,满足不了条件就不起动或者暂停。
  • 引入权限控制。打印机服务这种让linus都抓狂的服务,就让它在低权限跑去吧。
  • 引入守护机制。死了帮你重启,重启不成就帮你暂停,以及暂停其他所有依赖这个服务。
  • 用基于xml的配置文件,取代了简单的使用init.rc*文件夹以及文件名来组织各个服务。这个不用解释,因为init的那一套只能说是太原始了。

以上4点总结引用自李宇的blog, 他总结的非常好!最后想象下有了SMF这个东西,我们要定制一个基于Illumos内核的OS就不再像看起来那么的遥不可及,定义好run level和自己的服务依赖,专注在服务实现,把整个kernerl打包进去,build出ISO/USB/PXE的镜像。

转自SmartOS Diskless Booting与SMF

博客网络架构

为了方便以后的同学架设自己的博客系统,在此记录一下我的博客网络架构,供来访者参考。我的博客服务器放在了vultr的New Jersey节点,服务器采用debian 9,同时开启了TCP bbr 网络拥塞控制算法。为了进一步提高访问速度,利用CloudXNS的分地区解析的功能,分别在国内和国外增加了一套CDN系统。

前言

为了方便以后的同学架设自己的博客系统,在此记录一下我的博客架构,供来访者参考。

博客程序

本博客采用较为知名的开源博客程序wordpress架设,一开始用的博客自带的主题,但是后来发现自带的主题无法满足我的要求,于是就改用的自己编写的主题,目前采用的就是我自己编写的主题。当然,除了wordpress之外还有很多知名的开源博客程序,如Z-BlogJoomlaHexo等等,对其他博客程序感兴趣的同学可以了解一下。

服务器

我的博客目前使用的是vultr的VPS,配置为1CPU、512M内存、20G SSD,每月费用为$2.5,不过这种配置的VPS大部分都已经售罄,不太好申请。目前容易申请的最便宜的VPS是每月$5,配置为1CPU、1024M内存、25G SSD。如果对vultr感兴趣,可以通过下面的推广连接申请。

vultr

服务器操作系统用的是debian8,http程序使用的是nginx,采用php7.0,数据库使用mariadb,并采用redis做缓存。

https 证书采用的是Let’s Encrypt的证书,因为Let’s Encrypt的证书有效期为3个月,所以部署了自动化程序,每2.5个月重新申请证书。你在浏览器上看到的证书可能不是Let’s Encrypt的证书,那是因为我在服务器前端加了CDN系统,你看到的证书是CDN提供的证书。

域名

这个博客一开始使用的是smartserver.xyz这个域名,但是xyz域名在北京没办法备案,所以也没有办法部署国内的CDN系统,所以当时采用的是cloudflare 的CDN,但是因为众所周知的原因cloudflare在国内的访问速度并不理想,所以为了能用上国内的CDN就注册了z2os.com这个域名,并做了备案。

CDN

为了能让博客在国内和国外都获得良好的访问速度,所以我在国内和国外分别部署了一套CDN系统,目前z2os.com使用qcloud进行解析,qcloud支持域名分线路进行解析,正好利用这个功能实现国内用户解析到国内CDN,国外用户解析到国外CDN。

2017年8月24日更新:用了一段时间发现qcloud的云解析速度不太理想,所以就将z2os.com的解析迁移到了CloudXNS

国内CDN使用的是qcloud的CDN系统,国内的CDN也看过好多家,这么多家CDN厂家中目前只有qcloud有免费的https流量,其他的厂家要么是需要升级专业版才能使用https的CDN,要么是http有免费流量但是https需要收费。

国外的CDN使用的是cloudflare的CDN系统,对国外用户来说cloudflare的免费套餐简直是业绩良心,但是对我这种需要区分国内和国外进行解析的用户有一个缺点,cloudflare的免费套餐不支持cname模式,如果要使用免费套餐托管到cloudflare,但是托管到cloudflare之后就不能分线路解析了,真是鱼和熊掌不可兼得啊。有没有办法让cloudflare的免费套餐支持cname解析呢,这个问题困扰了我很久,直到我看到这篇博文:极客族免费提供支持SSL的CNAME版CloudFlare,一切问题就迎刃而解了。

最后放上我博客架构的示意图,方便各位理解,以后如果博客架构有什么调整我也会在这篇文章下更新。

博客架构

 

smartos教程四:安装SmartOS

Smartos是一个开源的Unix系列操作系统,从Solaris10分支出来,由Joyent公司开发。Smartos拥有非常强大而简便的虚拟化功能,非常适合用来做云计算。这篇文章我们就介绍一下怎么安装SmartOS。

前言

Smartos是一个开源的Unix系列操作系统,从Solaris10分支出来,由Joyent公司开发。Smartos拥有非常强大而简便的虚拟化功能,非常适合用来做云计算。这篇文章我们就介绍一下怎么安装SmartOS。

制作启动盘

因为SmartsOS启动的时候会将整个操作系统读取到内存,启动完毕后不在从启动盘读取文件,因此我们可以使用U盘、SD卡等移动存储设备制作启动盘。

现在我以Linux下将SmartOS安装到U盘为例进行讲解,其他操作系统可以参考官方文档:https://wiki.smartos.org/display/DOC/Creating+a+SmartOS+Bootable+USB+Key

首先去官网下载想要安装的版本。

下载地址:https://wiki.smartos.org/display/DOC/Download+SmartOS

下载完毕后解压

cd /tmp
wget https://us-east.manta.joyent.com/Joyent_Dev/public/SmartOS/smartos-latest-USB.img.bz2
tar xvjpf smartos-latest-USB.img.bz2

将U盘插入,查找U盘的设备路径,我的U盘路径为/dev/sdb

$ sudo fdisk -l
255 heads, 63 sectors/track, 60801 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x7ecb51e2

Device Boot Start End Blocks Id System
/dev/sda1 * 1 52 409600 27 Unknown
Partition 1 does not end on cylinder boundary.
/dev/sda2 52 18959 151870464 7 HPFS/NTFS
/dev/sda3 18959 30432 92158977 f W95 Ext'd (LBA)
/dev/sda4 30432 60802 243944472 7 HPFS/NTFS
/dev/sda5 18959 30432 92158976 83 Linux

Disk /dev/sdb: 7958 MB, 7958691840 bytes
255 heads, 63 sectors/track, 967 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000

Device Boot Start End Blocks Id System
/dev/sdb1 1 243 1951866 c W95 FAT32 (LBA)

将镜像刷到U盘中

cd /tmp
sudo dd if=smartos-latest-USB.img of=/dev/sdb bs=1024

设置分区激活状态

$ sudo fdisk /dev/sdb

Command (m for help): p

255 heads, 63 sectors/track, 967 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000

Device Boot Start End Blocks Id System
/dev/sdb1 1 243 1951866 c W95 FAT32 (LBA)

Command (m for help): a
Partition number (1-4): 1

Command (m for help): p

255 heads, 63 sectors/track, 967 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000

Device Boot Start End Blocks Id System
/dev/sdb1 * 1 243 1951866 c W95 FAT32 (LBA)

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.

WARNING: Re-reading the partition table failed with error 16: Device or resource busy.
The kernel still uses the old table. The new table will be used at
the next reboot or after you run partprobe(8) or kpartx(8)
Syncing disks.

安装与启动系统

将制作好的U盘插入物理机,并且让物理机通过U盘启动,从默认的GRUB选项就能进入安装界面了。

安装界面是命令行交互的界面,根据提示依次配置好主网卡、IP、网关、磁盘冗余级别、时间服务器、密码即可,没有什么复杂的配置。

配置完后需要重新启动,现在只能通过U盘来启动,依然从默认的GRUB选项进入,这时候操作系统会去检查写入磁盘的文件,发现已经安装了系统,就不会再次安装了,而是读取文件进行配置,然后进入系统。

smartos教程三:smartos虚拟化技术

SmarOS 是基于 Illumos 核心,之后大牛们还将KVM移植了进去。严格来说,SmartOS 并非Solaris,但也保留了一些Solaris的特性。Illumos 提供了一个通用内核和一些基础的系统工具。基于 illumos 的发行版软件都有一些很赞的体验.

前言

严格来说,SmartOS 并非Solaris,但也保留了一些Solaris的特性。所以说 SmartOS 和 Linux 是有一定区别的,这个学习需要一点时间,但是值得你去付出,因为 SmartOS 中很多杀手级特性都是 Linux 不具备的。

SmarOS 是基于 Illumos 核心(注:第一个字母是i,后面两个才是l),之后大牛们还将KVM移植了进去。而 Illumos 基于 OpenSolaris 项目的(已不复存在)。实际上,Oracle 收购 Sun 后,对 OpenSolaris 态度很冷淡,毫无兴趣,并关闭源码。大多数Sun最优秀的工程师转投入 Illumos 旗下。现在他们大多数都在 Joyent 和 Nexenta。具体的故事我就不详述了,有兴趣的可以看看这两篇文章:

Illumos

illumos

Illumos 提供了一个通用内核和一些基础的系统工具。基于 illumos 的发行版软件都有一些很赞的体验,这里提几个让人印象深刻,最具创新的distributions(参考链接):

  • OpenIndiana 那些有 Solaris 或 OpenSolarisis 背景的人可能比较熟悉这个东东。OpenIndiana 项目的目标是继续开发和发行 OpenSolaris。该项目隶属于 Illumos 基金会。由于 Oracle 宣布不再发行 OpenSolaris ,该项目被建立以为 OpenSolaris 继续其更新。
  • Nexenta CP 即Nexenta Community Platform,现在成为 Illumos 旗下的一款产品,改名叫 illumian 了,何去何从可以参考此链接。现在只能看到 NexentaStor 了,它是Nexenta 公司推出的基于 OpenSolaris OS 和 ZFS 等技术的一个 NAS 软件解决方案。如果你熟悉 Linux,尤其是 Debian 或 Ubuntu,那就会很快上手。ZFS文件系统(Zettabyte File System)是 NexentaStor 的亮点,它是一种基于 Solaris 的128位的文件系统,强健可靠、可伸缩、易于管理,突出了对数据完整性的保护。我之后还会专门写文章介绍 ZFS,不过网上也已经有很多类似的文章了。
  • SmartOS 是由 Joyent 提供的 community distro,可以认为是 SmartDataCenter 商业化产品的一部分。这次就要专门谈谈它及其独特的虚拟化技术。

其实illumos还出了一些很好的书,这些书现在网上都有电子版,链接是:http://illumos.org/books/ 。

SmartOS云平台

Joyent SmartOS与SmartMachine、SmartDataCenter以及物理机紧密集成,在各个层面保证云平台的安全性。与其他的云平台不同,SmartOS云平台的虚拟资源驻留在SmartOS中,而不是在虚拟机本身。这种包容性的虚拟化架构避免了Web应用层和操作系统之间接口的潜在漏洞。在网络层,Joyent的SmartDataCenter支持动态的虚拟局域网(vLAN),使客户在任何时候都可以有效隔离云平台上的不同用户。Joyent的安全保障架构图如下所示:

smartos安全保证

SmartOS简单可以解释为:“illumos-derived OS that is the foundation of both Joyentʼs public cloud and SmartDataCenter product”。 既然作为是illumos的衍生产品,那么它具备以下几个关键特性:

  • ZFS —— 企业级的写时复制(copy-on-write)文件系统,可提供诸如constant time snapshots,writable clones,built-in compression,checksumming,volume management 等众多功能。
  • DTrace: 用来在生产和试验性生产系统上找出系统瓶颈的工具,可以以对核心(kernel)和应用程序(user application)进行动态跟踪并且对系统运行不构成任何危险。支持原位(in situ)的数据聚合,用户级评估测量等。
  • 基于操作系统的虚拟化(Zones):完整的安全的虚拟操作系统实例,提供给多租户硬件级的性能。网络虚拟化(Crossbow):虚拟NIC架构,方便对网络带宽管理和资源控制。这里有论文链接。
  • KVM:Joyent技术专家已经将KVM移植到SmartOS中,支持硬件虚拟化,并加强了以上四项特性,具体可以参见此链接

 

Linux PID 1 和 Systemd

systemd 是 Linux 下的一款系统和服务管理器,兼容 SysV 和 LSB 的启动脚本。systemd 的特性有:支持并行化任务;同时采用 socket 式与 D-Bus 总线式激活服务;按需启动守护进程(daemon);利用 Linux 的 cgroups 监视进程;支持快照和系统恢复;维护挂载点和自动挂载点;各服务间基于依赖关系进行精密控制。

要说清 Systemd,得先从Linux操作系统的启动说起。Linux 操作系统的启动首先从 BIOS 开始,然后由 Boot Loader 载入内核,并初始化内核。内核初始化的最后一步就是启动 init 进程。这个进程是系统的第一个进程,PID 为 1,又叫超级进程,也叫根进程。它负责产生其他所有用户进程。所有的进程都会被挂在这个进程下,如果这个进程退出了,那么所有的进程都被 kill 。如果一个子进程的父进程退了,那么这个子进程会被挂到 PID 1 下面。(注:PID 0 是内核的一部分,主要用于内进换页,参看:Process identifier

SysV Init

PID 1 这个进程非常特殊,其主要就任务是把整个操作系统带入可操作的状态。比如:启动 UI – Shell 以便进行人机交互,或者进入 X 图形窗口。传统上,PID 1 和传统的 Unix System V 相兼容的,所以也叫 sysvinit,这是使用得最悠久的 init 实现。Unix System V 于1983年 release。

在 sysvint 下,有好几个运行模式,又叫 runlevel。比如:常见的 3 级别指定启动到多用户的字符命令行界面,5 级别指定启起到图形界面,0 表示关机,6 表示重启。其配置在 /etc/inittab 文件中。

与此配套的还有 /etc/init.d/ 和 /etc/rc[X].d,前者存放各种进程的启停脚本(需要按照规范支持 startstop子命令),后者的 X 表示不同的 runlevel 下相应的后台进程服务,如:/etc/rc3.d 是 runlevel=3 的。 里面的文件主要是 link 到  /etc/init.d/ 里的启停脚本。其中也有一定的命名规范:S 或 K 打头的,后面跟一个数字,然后再跟一个自定义的名字,如:S01rsyslogS02ssh。S 表示启动,K表示停止,数字表示执行的顺序。

UpStart

Unix 和 Linux 在 sysvint 运作多年后,大约到了2006年的时候,Linux内核进入2.6时代,Linux有了很多更新。并且,Linux开始进入桌面系统,而桌面系统和服务器系统不一样的是,桌面系统面临频繁重启,而且,用户会非常频繁的使用硬件的热插拔技术。于是,这些新的场景,让 sysvint 受到了很多挑战。

比如,打印机需要CUPS等服务进程,但是如果用户没有打机印,启动这个服务完全是一种浪费,而如果不启动,如果要用打印机了,就无法使用,因为sysvint 没有自动检测的机制,它只能一次性启动所有的服务。另外,还有网络盘挂载的问题。在 /etc/fstab中,负责硬盘挂载,有时候还有网络硬盘(NFS 或 iSCSI)在其中,但是在桌面机上,有很可能开机的时候是没有网络的, 于是网络硬盘都不可以访问,也无法挂载,这会极大的影响启动速度。sysvinit 采用 netdev 的方式来解决这个问题,也就是说,需要用户自己在 /etc/fstab 中给相应的硬盘配置上 netdev 属性,于是 sysvint 启动时不会挂载它,只有在网络可用后,由专门的 netfs 服务进程来挂载。这种管理方式比较难以管理,也很容易让人掉坑。

所以,Ubuntu 开发人员在评估了当时几个可选的 init 系统后,决定重新设计这个系统,于是,这就是我们后面看到的 upstart 。 upstart 基于事件驱动的机制,把之前的完全串行的同步启动服务的方式改成了由事件驱动的异步的方式。比如:如果有U盘插入,udev得到通知,upstart 感知到这个事件后触发相应的服务程序,比如挂载文件系统等等。因为使用一个事件驱动的玩法,所以,启动操作系统时,很多不必要的服务可以不用启动,而是等待通知,lazy 启动。而且事件驱动的好处是,可以并行启动服务,他们之间的依赖关系,由相应的事件通知完成。

upstart 有着很不错的设计,其中最重要的两个概念是 Job 和 Event。

Job 有一般的Job,也有service的Job,并且,upstart 管理了整个 Job 的生命周期,比如:Waiting, Starting, pre-Start, Spawned, post-Start, Running, pre-Stop, Stopping, Killed, post-Stop等等,并维护着这个生命周期的状态机。

Event 分成三类,signalmethod 和 hookssignal 就是异步消息,method 是同步阻塞的。hooks 也是同步的,但介于前面两者之间,发出hook事件的进程必须等到事件完成,但不检查是否成功。

但是,upstart 的事件非常复杂,也非常纷乱,各种各样的事件(事件没有归好类)导致有点凌乱。不过因为整个事件驱动的设计比之前的 sysvinit 来说好太多,所以,也深得欢迎。

Systemd

直到2010的有一天,一个在 RedHat工作的工程师 Lennart Poettering 和 Kay Sievers ,开始引入了一个新的 init 系统—— systemd。这是一个非常非常有野心的项目,这个项目几乎改变了所有的东西,systemd 不但想取代已有的 init 系统,而且还想干更多的东西。

Lennart 同意 upstart 干的不错,代码质量很好,基于事件的设计也很好。但是他觉得 upstart 也有问题,其中最大的问题还是不够快,虽然 upstart 用事件可以达到一定的启动并行度,但是,本质上来说,这些事件还是会让启动过程串行在一起。  如:NetworkManager 在等 D-Bus 的启动事件,而 D-Bus 在等 syslog 的启动事件。

Lennart 认为,实现上来说,upstart 其实是在管理一个逻辑上的服务依赖树,但是这个服务依赖树在表现形式上比较简单,你只需要配置——“启动 B好了就启动A”或是“停止了A后就停止B”这样的规则。但是,Lennart 说,这种简单其实是有害的(this simplification is actually detrimental)。他认为,

  • 从一个系统管理的角度出来,他一开始会设定好整个系统启动的服务依赖树,但是这个系统管理员要人肉的把这个本来就非常干净的服务依整树给翻译成计算机看的懂的 Event/Action 形式,而且 Event/Action 这种配置方式是运行时的,所以,你需要运行起来才知道是什么样的。
  • Event逻辑从头到脚到处都是,这个事件扩大了运维的复杂度,还不如之前的 sysvint。 也就是说,当用户配置了 “启动 D-Bus 后请启动 NetworkManager”, 这个 upstart 可以干,但是反过来,如果,用户启动 NetworkManager,我们应该先去启动他的前置依赖 D-Bus,然而你还要配置相应的反向 Event。本来,我只需要配置一条依赖的,结果现在我要配置很多很多情况下的Event。
  • 最后,upstart 里的 Event 的并不标准,很混乱,没有良好的定义。比如:既有,进程启动,运行,停止的事件,也有USB设备插入、可用、拔出的事件,还有文件系统设备being mounted、 mounted 和 umounted 的事件,还有AC电源线连接和断开的事件。你会发现,这进程启停的、USB的、文件系统的、电源线的事件,看上去长得很像, 但是没有被标准化抽像出来掉,因为绝大多数的事件都是三元组:start, condition, stop 。这种概念设计模型并没有在 upstart 中出现。因为 upstart 被设计为单一的事件,而忽略了逻辑依赖。

当然,如果 systemd 只是解决 upstart 的问题,他就改造 upstart 就好了,但是 Lennart 的野心不只是想干个这样的事,他想干的更多。

首先,systemd 清醒的认识到了 init 进程的首要目标是要让用户快速的进入可以操作OS的环境,所以,这个速度一定要快,越快越好,所以,systemd 的设计理念就是两条:

  • To start less.
  • And to start more in parallel.

也就是说,按需启动,能不启动就不启动,如果要启动,能并行启动就并行启动,包括你们之间有依赖,我也并行启动。按需启动还好理解,那么,有依赖关系的并行启动,它是怎么做到的?这里,systemd 借鉴了 MacOS 的 Launchd 的玩法(在Youtube上有一个分享——Launchd: One Program to Rule them All,在苹果的开源网站上也有相关的设计文档——About Daemons and Services

要解决这些依赖性,systemd 需要解决好三种底层依赖—— Socket, D-Bus ,文件系统。

  • Socket依赖。如果服务C依赖于服务S的socket,那么就要先启动S,然后再启动C,因为如果C启动时找不到S的Socket,那么C就会失败。systemd 可以帮你在S还没有启动好的时候,建立一个socket,用来接收所有的C的请求和数据,并缓存之,一旦S全部启动完成,把systemd替换好的这个缓存的数据和Socket描述符替换过去。
  • D-Bus依赖D-Bus 全称 Desktop Bus,是一个用来在进程间通信的服务。除了用于用户态进程和内核态进程通信,也用于用户态的进程之前。现在,很多的现在的服务进程都用 D-Bus 而不是Socket来通信。比如:NetworkManager 就是通过 D-Bus 和其它服务进程通讯的,也就是说,如果一个进程需要知道网络的状态,那么就必需要通过 D-Bus 通信。D-Bus 支持 “Bus Activation”的特性。也就是说,A要通过 D-Bus服务和B通讯,但是B没有启动,那么 D-Bus 可以把B起来,在B启动的过程中,D-Bus 帮你缓存数据。systemd 可以帮你利用好这个特性来并行启动 A 和 B。
  • 文件系统依赖。系统启动过程中,文件系统相关的活动是最耗时的,比如挂载文件系统,对文件系统进行磁盘检查(fsck),磁盘配额检查等都是非常耗时的操作。在等待这些工作完成的同时,系统处于空闲状态。那些想使用文件系统的服务似乎必须等待文件系统初始化完成才可以启动。systemd 参考了 autofs 的设计思路,使得依赖文件系统的服务和文件系统本身初始化两者可以并发工作。autofs 可以监测到某个文件系统挂载点真正被访问到的时候才触发挂载操作,这是通过内核 automounter 模块的支持而实现的。比如一个 open() 系统调用作用在某个文件系统上的时候,而这个文件系统尚未执行挂载,此时 open() 调用被内核挂起等待,等到挂载完成后,控制权返回给 open() 系统调用,并正常打开文件。这个过程和 autofs 是相似的。

下图来自 Lennart 的演讲里的一页PPT,展示了不同 init 系统的启动。

启动流程

除此之外,systemd 还在启动时管理好了一些下面的事。

用C语言取代传统的脚本式的启动。前面说过,sysvint 用 /etc/rcX.d 下的各种脚本启动。然而这些脚本中需要使用 awksedgrepfindxargs 等等这些操作系统的命令,这些命令需要生成进程,生成进程的开销很大,关键是生成完这些进程后,这个进程就干了点屁大的事就退了。换句话说就是,我操作系统干了那么多事为你拉个进程起来,结果你就把个字串转成小写就退了,把我操作系统当什么了?

在正常的一个 sysvinit 的脚本里,可能会有成百上千个这样的命令。所以,慢死。因此,systemd 全面用 C 语言全部取代了。一般来说,sysvinit 下,操作系统启动完成后,用 echo $$ 可以看到,pid 被分配到了上千的样子,而 systemd 的系统只是上百。

另外,systemd 是真正一个可以管住服务进程的——可以跟踪上服务进程所fork/exec出来的所有进程。

  • 我们知道, 传统 Unix/Linux 的 Daemon 服务进程的最佳实践基本上是这个样子的 (具体过程可参看这篇文章“SysV Daemon”)——
    1. 进程启动时,关闭所有的打开的文件描述符(除了标准描述符0,1,2),然后重置所有的信号处理。
    2. 调用 fork() 创建子进程,在子进程中 setsid(),然后父进程退出(为了后台执行)
    3. 在子进程中,再调用一次 fork(),创建孙子进程,确定没有交互终端。然后子进程退出。
    4. 在孙子进程中,把标准输入标准输出标准错误都连到 /dev/null 上,还要创建 pid 文件,日志文件,处理相关信号 ……
    5. 最后才是真正开始提供服务。
  • 在上面的这个过程中,服务进程除了两次 fork 外还会 fork 出很多很多的子进程(比如说一些Web服务进程,会根据用户的请求链接来 fork 子进程),这个进程树是相当难以管理的,因为,一旦父进程退出来了,子进程就会被挂到 PID 1下,所以,基本上来说,你无法通过服务进程自已给定的一个pid文件来找到所有的相关进程(这个对开发者的要求太高了),所以,在传统的方式下用脚本启停服务是相当相当的 Buggy 的,因为无法做对所有的服务生出来的子子孙孙做到监控。
  • 为了解决这个问题,upstart 通过变态的 strace 来跟踪进程中的 fork() 和 exec()或 exit() 等相关的系统调用。这种方法相当笨拙。 systemd 使用了一个非常有意思的玩法来 tracking 服务进程生出来的所有进程,那就是用 cgroup (我在 Docker 的基础技术“cgroup篇”中讲过这个东西)。cgroup主要是用来管理进程组资源配额的事,所以,无论服务如何启动新的子进程,所有的这些相关进程都会同属于一个 cgroup,所以,systemd 只需要简单的去遍历一下相应的 cgroup 的那个虚文件系统目录下的文件,就可以正确的找到所有的相关进程,并将他们一一停止。

另外,systemd 简化了整个 daemon 开发的过程:

  • 不需要两次 fork(),只需要实现服务本身的主逻辑就可以了。
  • 不需要 setsid()systemd 会帮你干
  • 不需要维护 pid文件systemd 会帮处理。
  • 不需要管理日志文件或是使用syslog,或是处理HUP的日志reload信号。把日志打到 stderr 上,systemd 帮你管理。
  • 处理 SIGTERM 信号,这个信号就是正确退出当前服务,不要做其他的事。
  • ……

除此之外,systemd 还能——

  • 自动检测启动的服务间有没有环形依赖。
  • 内建 autofs 自动挂载管理功能。
  • 日志服务。systemd 改造了传统的 syslog 的问题,采用二进制格式保存日志,日志索引更快。
  • 快照和恢复。对当前的系统运行的服务集合做快照,并可以恢复。
  • ……

还有好多好多,他接管很多很多东西,于是就让很多人不爽了,因为他在干了很多本不属于 PID 1 的事。

Systemd 争论和八卦

于是 systemd 这个东西成了可能是有史以来口水战最多的一个开源软件了。systemd 饱受各种争议,最大的争议就是他破坏了 Unix 的设计哲学(相关的哲学可以读一下《Unix编程艺术》),干了一个大而全而且相当复杂的东西。当然,Lennart 并不同意这样的说法,他后来又写一篇blog “The Biggest Myths”来解释 systemd 并不是这样的,大家可以前往一读。

这个争议大到什么样子呢?2014 年,Debian Linux 因为想准备使用 systemd 来作为标准的 init 守护进程来替换 sysvinit 。而围绕这个事的争论达到了空前的热度,争论中充满着仇恨,systemd 的支持者和反对者都在互相辱骂,导致当时 Debian 阵营开始分裂。还有人给 Lennart 发了死亡威胁的邮件,用比特币雇凶买杀手,扬言要取他的性命,在Youbute上传了侮辱他的歌曲,在IRC和各种社交渠道上给他发下流和侮辱性的消息。这已经不是争议了,而是一种不折不扣的仇恨!

systemd shewantsit

于是,Lennart 在 Google Plus 上发了贴子,批评整个 Linux 开源社区和 Linus 本人。他大意说,

这个社区太病态了,全是 ass holes,你们不停用各种手段在各种地方用不同的语言和方式来侮辱和漫骂我。我还是一个年轻人,我从来没有经历过这样的场面,但是今天我已经对这种场面很熟悉了。我有时候说话可能不准确,但是我不会像他样那样说出那样的话,我也没有被这些事影响,因为我脸皮够厚,所以,为什么我可以在如何大的反对声面前让 systemd 成功,但是,你们 Linux 社区太可怕了。你们里面的有精神病的人太多了。另外,对于Linus Torvalds,你是这个社区的 Role Model,但可惜你是一个 Bad Role Model,你在社区里的刻薄和侮辱性的言行,基本从一定程度上鼓励了其它人跟你一样,当然,并不只是你一个人的问题,而是在你周围聚集了一群和你一样的这样干的人。送你一句话—— A fish rots from the head down !一条鱼是从头往下腐烂的……

这篇契文很长,喜欢八卦的同学可以前往一读。感受一下 Lennart 当时的心态(我觉得能算上是非常平稳了)。

Linus也在被一媒体问起 systemd 这个事来(参看“Torvalds says he has no strong opinions on systemd”),Linus在采访里说,

我对 systemd 和 Lennart 的贴子没有什么强烈的想法。虽然,传统的 Unix 设计哲学—— “Do one thing and Do it well”,很不错,而且我们大多数人也实践了这么多年,但是这并不代表所有的真实世界。在历史上,也不只有systemd 这么干过。但是,我个人还是 old-fashioned 的人,至少我喜欢文本式的日志,而不是二进制的日志。但是 systemd 没有必要一定要有这样的品味。哦,我说细节了……

今天,systemd 占据了几乎所有的主流的 Linux 发行版的默认配置,包括:Arch Linux、CentOS、CoreOS、Debian、Fedora、Megeia、OpenSUSE、RHEL、SUSE企业版和 Ubuntu。而且,对于 CentOS, CoreOS, Fedora, RHEL, SUSE这些发行版来说,不能没有 systemd。(Ubuntu 还有一个不错的wiki – Systemd for Upstart Users 阐述了如何在两者间切换)

其它

还记得在《缓存更新的套路》一文中,我说过,如果你要做好架构,首先你得把计算机体系结构以及很多老古董的基础技术吃透了。因为里面会有很多可以借鉴和相通的东西。那么,你是否从这篇文章里看到了一些有分布式架构相似的东西?

比如:从 sysvinit 到 upstart 再到 systemd,像不像是服务治理?Linux系统下的这些服务进程,是不是很像分布式架构中的微服务?还有那个D-Bus,是不是很像SOA里的ESB?而 init 系统是不是很像一个控制系统?甚至像一个服务编排(Service Orchestration)系统?

分布式系统中的服务之间也有很多依赖,所以,在启动一个架构的时候,如果我们可以做到像 systemd 那样并行启动的话,那么是不是就像是一个微服务的玩法了?

嗯,你会发现,技术上的很多东西是相通的,也是互相有对方的影子,所以,其实技术并不多。关键是我们学在了表面还是看到了本质。

延伸阅读

 

转载自: Linux PID 1 和 Systemd | | 酷 壳 – CoolShell

静态资源公共库汇总

静态资源公共库是指一些服务商将我们常用的 JavaScript 库存放到网上,方便开发者直接调用,并且还对其提供 CDN 加速,这样一来可以让用户加速访问这些资源,二来还可节约自己服务器的流量。

前言

近期想着把博客优化一下,提高访问速度,所以搜集了一些常用的静态资源公共库,在此记录一下。

静态资源公共库是指一些服务商将我们常用的 JavaScript 库存放到网上,方便开发者直接调用,并且还对其提供 CDN 加速,这样一来可以让用户加速访问这些资源,二来还可节约自己服务器的流量。

百度静态资源公共库

地址:http://cdn.code.baidu.com/

收录超过180+开源库,并且这个数字正在不断增加,支持https,直接将http更改为https就可以使用。

腾讯网静态资源公共库

地址:http://libs.qq.com/

收录的资源比较少,可以支持https。

新浪云计算公共库

地址:http://lib.sinaapp.com/

收录的资源比较少,可以支持https。

七牛云存储开放静态文件

地址:http://staticfile.org/

收录的资源比较丰富,支持https。

又拍云JS库

地址:http://jscdn.upai.com/

只提供jQueryMOOTOOLSMODERNIZRDOJOEMBER这5个库,支持https。

Google 静态资源公共库

地址:https://developers.google.com/speed/libraries/

收录比较全面,支持https,但是由于被墙,国内不建议使用。

微软静态资源公共库

地址:https://docs.microsoft.com/en-us/aspnet/ajax/cdn/overview

收录比较全面,支持https,访问速度也不错,推荐使用。