Nginx源码分析之启动过程

nginx的启动过程代码主要分布在src/core以及src/os/unix目录下。启动流程的函数调用序列:main(src/core/nginx.c)→ngx_init_cycle(src/core/ngx_cycle.c)→ngx_master_process_cycle(src/os/)。nginx的启动过程就是围绕着这三个函数进行的。

main函数的处理过程总体上可以概括如下:

Nginx负载均衡

目录

本文最新更新于2016.11.01

一 特点

1.1 应用情况

Nginx做为一个强大的Web服务器软件,具有高性能、高并发性和低内存占用的特点。此外,其也能够提供强大的反向代理功能。俄罗斯大约有超过20%的虚拟主机采用Nginx作为反向代理服务器,在国内也有腾讯、新浪、网易等多家网站在使用Nginx作为反向代理服务器。据Netcraft统计,世界上最繁忙的网站中有11.48%使用Nginx作为其服务器或者代理服务器。基于反向代理的功能,Nginx作为负载均衡主要有以下几点理由:

  1. 高并发连接
  2. 内存消耗少
  3. 配置文件非常简单
  4. 成本低廉
  5. 支持Rewrite重写规则
  6. 内置的健康检查功能
  7. 节省带宽
  8. 稳定性高

Async源码分析

最近在使用到node js的async库的时候,对其waterfall的实现感觉很奇妙,于是看了一下源码:

    async.waterfall = function (tasks, callback) {
        callback = callback || function () {};
        if (!_isArray(tasks)) {
          var err = new Error('First argument to waterfall must be an array of functions');
          return callback(err);
        }
        if (!tasks.length) {
            return callback();
        }
        var wrapIterator = function (iterator) {
            return function (err) {
                if (err) {
                    callback.apply(null, arguments);
                    callback = function () {};
                }
                else {
                    var args = Array.prototype.slice.call(arguments, 1);
                    var next = iterator.next();
                    if (next) {
                        args.push(wrapIterator(next));
                    }
                    else {
                        args.push(callback);
                    }
                    async.setImmediate(function () {
                        iterator.apply(null, args);
                    });
                }
            };
        };
        wrapIterator(async.iterator(tasks))();
    };
 

技术的成长

最近因为一件事情,让自己突然对自己产生了巨大的怀疑。工作一年多,仔细想想貌似真的只是在积累项目经验,而在技术深度上却一直停滞不前。这其中确也有因为之前做产品没有太多空闲时间的缘故,但更多的还是自己一直不得章法。对nginx源码的学习,一拖再拖,想成为这方面的专家却也不知道努力挤出时间或者说没有好的方法让自己合理安排出时间。

毕业的时候自己选择这里,就是想安心的做技术,以求在技术上得到长足的进步。现在却发现在做着一些没那么有技术含量的东西,像某人所说:上学的时候给我一定的时间也能够做出来。虽然我觉得上学的时候,大部分进公司做的东西也能做出来(除非是那种需要基于一定的环境像大数据、高并发才能做的)。但其实我明白,那句话的意思主要强调的是应该潜心去研究一门技术,比如hadoop、storm等,成为一个领域的专家。这也的确是自己的软肋,也的确该好好加强。

Nginx源码分析之基本数据结构

引言

nginx实现中有很多结构体,一般命名为ngx_xxx_t。这些结构体分散在许多头文件中。src/core/ngx_core.h中把几乎所有的头文件都集合起来。也因此造成了nginx各部分源代码的耦合。但实际上nginx各个部分逻辑划分还是很明确的,整体上是一种松散的结构。

作者之所以重复造了这些轮子,无非是为了追求高效。查看这些数据结构的源码,的确是设计的比较精巧,也保证了对内存足够小的占用以及各种操作的高效。

谈谈系统架构这个东西

架构这个词在很多人看来都是很高大上的一个东西。事实上,搞架构的这些人却也都是些大神,至少都是在这个领域浸淫N久的专家级人物。现在很火的全栈工程师这个概念,就是架构师的另一种表现形式。

之于架构,其含义无非是从技术细节跳出来自上而下宏观地看待系统的一个思维,就好比建筑设计一样。架构师的角色和建筑设计师在某种意义上是相同的。在微博上看到蔡学镛分享过这么一个架构设计流程的图,从中或多或少能看出架构设计一个大概的流程。

arch-1

首当其冲的,肯定是需要对整个系统的业务进行拆分,进行业务设计,目的就是要捋清楚系统是干什么的,能提供什么功能,对系统的需求要做到详尽的分析和考虑。不过这部分,在我参与过的一些项目看来,尤其是对现在普遍使用的敏捷开发流程来说,无需考虑的太面面俱到,但至少不能太窄或者偏离正轨,后续的开发过程会不断的反馈回来进行调整。

接下来,系统的业务明确之后,交互设计和领域建模便可以同时执行。当然,这里我是觉得交互设计和架构师是没啥关系的,顶多就是两者要相辅相成。而领域建模这个就显得很重要了。领域建模是业务设计的主要逻辑,把现实中的业务转化成抽象的对象,这个确实是能力的体现了。我觉得这一部分很多出色的架构师相比其他人突出的一个很关键的地方。

技术模块设计则是在理解了系统的业务需求之后,对整体的一个技术框架上的设计。这里对于技术架构,我一直有一个分不太清楚的东西,就是软件架构和系统架构。说到底,这两者都是软件层面的含义,所不同的是前者到了代码层面,而系统架构则是到了软件层面。软件架构是位于系统架构之上的。一个系统,使用了Spring、Hibernater然后用了MVC设计模式,这就是软件架构;一个系统分成负载均衡模块、Link模块、队列模块、数据模块、推送模块等等则就是系统架构。再往下就应该是部署架构了,比如系统部署了几个结点、结点之间的关系、网络的规划结构、系统的高可用、可扩展等等。当然对于一个系统来说,数据的设计是可以拿出来重点进行的,毕竟对于互联网应用来说,数据 is all,系统的很多性能、效率问题是和数据的存储设计有密切关系的。

到最后,业务之上的这些设计会反作用于业务,将系统的关键点反馈回来,从而对业务进行调整,进而再推进整个架构的流程。现在很火的敏捷开发,某种角度看来就是一个不断迭代、反馈的过程,是传统架构设计的一种演化形式。

谈到架构,那么如何才能具有架构能力呢?借鉴在知乎上看到一个回答:

  • 视野开阔,知道可以直接用哪个开源项目来满足这样那样的需求。多数时候其实我们并不需要重复造轮子。视野窄的架构师会放着捷径不走,不断让团队重复造轮子,直至把项目拖死。
  • 精通设计模式,但又不泛用。不设计过度,不在各种细节问题上需求蔓延。所有架构设计都是为了满足产品需求的,不满足需求或者过度设计都是菜鸟行为。
  • 把系统拆分成多个子系统或模块,模块之间尽量松耦合,使得原先只能串行的开发任务,可以并行开展,也就是说良好的设计可以通过投入更多人力来缩短工期。反之拙劣的设计需要一个人维护一大坨代码,无法通过加人并行开发来缩短工期。
  • 能清楚地知道系统的瓶颈在什么地方,不断地定位技术难度、研发进度、性能、内存等各方面的瓶颈,不断调整骨干力量解决瓶颈,在风险爆发之前就消除隐患。
  • 行业经验带来的直觉和预见性,可以预先需求可能产生怎样的变化,提前把可扩展性、后向兼容性设计好。但仍然不要过度设计

以上对架构的一些理解,很多地方自认还是有点迷糊。在进行系统设计的时候,也经常摸不着头脑,把不同层次的东西混为一谈。记得蔡学镛大神之前还分享过一张图片,对架构讲的挺透彻的。不明白的时候看看这个,会有种茅塞顿开的感觉。

arch-2

《白帽子讲Web安全》读书笔记

最近一直在忙着易信公众平台的开发工作,一直没能抽出空来总结一下。周末终于有了一些空闲,就把这本书的笔记写了一下。

整本书四篇十八章,包括世界观安全、客户端脚本安全、服务端应用安全以及互联网公司安全运营四大部分。

一、世界观安全

  1. 黑帽子和白帽子这两个概念,前者指的是利用安全技术进行破坏的哪一类黑客,后者则指的是工作在反黑客领域的安全技术专家。
  2. 安全问题的本质是信任的问题。并且安全是一个持续的过程,并不存在所谓的银弹。
  3. 安全三要素:机密性、完整性、可用性
  4. 一个安全评估的过程可以分为4个阶段:资产等级划分、威胁分析、风险分析、确认解决方案。其中威胁分析的一种建模方法是微软提出的STRIDE模型;风险分析则是DREAD模型,Risk = Probability * Damage Potenial。
  5. 白帽子并发有以下几个原则:Secure By Default原则;纵深防御原则(Defense in Depth);数据与代码分离原则;不可预测性原则。

杂感一篇

最近两部关于青春的片子《致青春》和《中国合伙人》,对于前者这种爱情的东西,从某个时间段开始,我早已不再关注。后者讲述的奋斗、梦想,却是我特别想看一看的。虽然我知道成功学这东西,完全是一群成功了的人在吹嘘当年自己有多苦逼,后来变得多NB。但是他们的成功却的确能触动自己心里的那根神经,唤起自己当初的激情。

十几年前,自己无意之中说出的一句话,到现在也算一直坚持了下来。虽然没有功成名就,但到现在还是不至于令自己失望的。平淡的日子往往让自己忘了自己当初的梦想,也忘了走向它的这条路。今天看《中国合伙人》这部影片又像当初看《社交网络》一样让自己全身瞬间充满了能量,同时也让自己拷问着自己:还坚持当初的梦想吗?正在为梦想努力吗?努力有收获吗?其实,现实中大多数人在说自己梦想的时候都能侃侃而谈,而真正能付诸于努力的人却寥寥可数。为梦想而努力,结果不一定是成功,但没有为此而努力过,那也许会成为一辈子最大的憾事。

电影里三个人的友情是让我感触颇深的另一个地方。人的一生会不停地结交到各种朋友,但最后真正能称得上朋友的人其实就那么几个人。和他们在一起,你会很确定不管你怎么样,他们都不会嫌弃你;不管你跟他们说了什么话,他们也不会介意。心情不好的时候,一个电话,他们不管有多忙也会立马赶到你的身旁。其实,以前的自己挺自私的,有点像孟晓峻,自从经历了某些事情之后,我才体会到友情是多么的珍贵,也才弥足珍惜现在的朋友们。

无题

5.11-5.12,176公里,千岛湖镇-汾口-千岛湖镇,环湖一周。相信这将会是我未来永远难忘的一段经历。

开始的计划是5.11中午从千岛湖镇出发,历经96公里前往汾口,18:00左右到达目的地。没想到走了大约20公里之后遇到了各种上坡路,尤其一段一公里的大上坡,让我们实在无法保持速度。全身各种疼,大腿完全是无知觉地在做机械运动,有无数次想放弃的冲动。如此艰难的挣扎,造成的后果就是从枫树岭开始的20公里山路只能摸黑前进,中间好几次撞到石头差点栽到地上。所幸的是有一辆自行车是有车灯的,不然还真不知道如何前行。最后到达汾口的时候已经是晚上快9点了。虽然远远晚于原定计划,但顺利到达目的地的喜悦还是让我们挺开心的。

5.12的路程相对来说是比较容易的,一路都是大缓坡,咬咬牙就都过了。中间在界首农庄吃了顿午饭。之后连续10个隧道,一路都还是挺舒服的。下午4点多,终于回到了出发点。算是完成了这次环千岛湖骑行。

这一段行程,真的感觉是对自己的一种历练+超越。在很多次想要放弃的时候,我都告诉自己,人只有超越自己、超越极限,才能成为一个无比强大的个体。和别人比较是没有任何意义的,能够战胜自己的人才是最优秀的。

PS:一路上各种哈雷机车,那叫一个帅气。。。据说是哈雷机车110周年纪念日,全国的机车爱好者都过来环湖庆祝。望而兴叹,啥时候自己也能成为一个哈雷机车车友呢?

Android异步加载图片

对于Android中的异步加载图片,自己总结了两种方式,如下:

1.

/*
 * 异步读取图片,需要传递三个参数:Imageview imageView,String imagePath,int maxNumpixels
* @author Bryant
/
public class AsyncLoadImage extends AsyncTask<Object, Object, Void> {
@Override
protected Void doInBackground(Object… params) {

    try {  
        ImageView imageView=(ImageView) params[0];  
        String path=(String) params[1];  
        int maxNumOfPixels = (Integer)params[2];

        Bitmap bm = CompressPicture.compress(path,maxNumOfPixels);

        publishProgress(new Object[] {imageView, bm});  
    }catch (Exception e) {  
        e.printStackTrace();  
    }  

    return null;
}  

protected void onProgressUpdate(Object... progress) {  
    ImageView imageView = (ImageView) progress[0];  
    Bitmap bm = (Bitmap) progress[1];
    if(bm != null){
        imageView.setImageBitmap(bm); 
    }

}  

}

/**
 * 图片异步加载
 * @author Bryant
 *
 */
public class AsyncImageLoader {
    private Map> imageCache=new HashMap>();
    private int maxNumPixels;
    
    public Bitmap loadBitmap(final String imagePath,int maxNumPixels,final ImageCallback callback){
        this.maxNumPixels = maxNumPixels;
        
        if(imageCache.containsKey(imagePath)){
            SoftReference softReference=imageCache.get(imagePath);
            if(softReference.get()!=null){
                return softReference.get();
            }
        }
        final Handler handler=new Handler(){
            @Override
            public void handleMessage(Message msg) {
                callback.imageLoaded((Bitmap) msg.obj, imagePath);
            }
        };
        new Thread(){
            public void run() {
                Bitmap bitmap=loadImageFromPath(imagePath);
                imageCache.put(imagePath, new SoftReference(bitmap));
                handler.sendMessage(handler.obtainMessage(0,bitmap));
            };
        }.start();
        return null;
    }
    
    protected Bitmap loadImageFromPath(String imagePath) {
        try {
            return CompressPicture.compress(imagePath, maxNumPixels);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public interface ImageCallback{
        public void imageLoaded(Bitmap imageBitmap,String imagePath);
    }
}

经过实际使用,AsyncImageLoader的效率比较高,但是调用比较麻烦。 调用示例:

private AsyncImageLoader imageLoader = new AsyncImageLoader();
imageLoader.loadBitmap(imagePath,maxNumPixels, new ImageCallback() {
    public void imageLoaded(Bitmap imageBitmap, String imagePath) {
        imageView.setImageBitmap(imageBitmap);
    }
}); 

AsyncLoadImage调用较简单,调用示例如下:

new AsyncLoadImage().execute(new Object[]{imageView,imagePath,maxNumPixels});