微信中jssdk使用中分享的页面,有invalid signature的提示,需要关注以下两点

1. 确认url是页面完整的url(请在当前页面alert(location.href.split(‘#’)[0])确认),包括’http(s)://’部分,以及’?’后面的GET参数部分,但不包括’#'hash后面的部分。最主要的就是域名无后缀时,必须添加’/',如http://qq.com/

2. nonceStr最好是16位的字符,自己开始一直不是16位,一直就invalid signature了。

帮助文档中没有提nonceStr的规范制度,折腾了半天都不对,校验地址

http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign

对于分布式在线服务,一个请求需要经过系统中多个模块,上百台机器的协作完成单次请求,典型场景就是Search Engine的一次用户检索,单靠人力无法掌握整个请求中各个阶段的性能开销,更无法快速的定位系统中性能瓶颈。Google Dapper文章描述了广泛用于Google内部服务的Trace Infrastruce—Dapper(原文地址见这里,译文地址见这里),文章本身的很易懂,没有复杂、精巧的实现机制(好像也是g公司publish出来的文章的特点),有一些分布式在线服务经验的程序员都可以很好的理解(英文版),这里就只抽一些点出来记录。而Zipkin是Twitter开源出来的一个Trace系统组件,实现中就参考了Google Dapper,项目主页见http://twitter.github.io/zipkin/

Google Dapper

目标: 无所不在的持续跟踪(ubiquitous deployment,and continuous monitoring),只有无所不在和持续,才能保证所有的问题都能被跟踪到,因为服务也是7*24的。为了做到这两点,Dapper对于这个Tracing组件,拆分出如下几个目标。

阅读全文…

, , ,

实际的生产环境中,经常会由于机器故障、机房掉电、网络异常、软件bug等原因,造成整个系统中某台机器、某些集群异常,无法提供稳定的服务;而系统也可能因为某些突发事件、外部攻击等原因,出现流量瞬间的大幅度增长,超过系统承载能力。因此,在系统设计时,需要充分的考虑系统的优雅降级、流量控制等。最近阅读了不少相关的文档,本文进行了整理,列举了一些构建大规模分布式服务的design principle如下。

Design Target

在设计初期,就需要充分考虑可扩展性、系统的可用性、运维和管理的便捷性以及成本,几点说明如下:

  • Scalability : Resource usage increase linearly(or better!) with load
  • Availability : Resilience to partial failure, Graceful degradation, Recoverability from failure
  • Manageability : Simplicity, Maintainability, Diagnostics
  • Cost : Machine cost and Operation cost

阅读全文…

工作中碰到一个内存分配导致的多线程server性能问题,网上翻到一个文档讨论多线程场景下的malloc性能——<malloc() Performance in a Multithreaded Linux Environment>,2000年的,有点旧,提到了多thread的时候,由于竞争单个堆分配器,导致malloc时间增长的问题。

写了小程序,使用同步模型,预分配固定个数的work thread,使用一种自定义的内存池(slab方式管理的内存池,当单次申请的内存大于4MB的时候,直接调用系统级的malloc)。循环1kw次的malloc模拟了下,统计每个线程的1kw总共耗时,结合文档中的Benchmark 1 Test的Result,有以下的几点可以供在平常开发多线程server时借鉴。

  1. work thread中尽可能的避免调用系统级的malloc,陷入内核态后等待时间很长。特别是在多线程场景下,由于竞争单个堆分配器,导致多线程下malloc巨慢无比。 (场景3):
  2. slab内存池使用要很小心,由于大于了预定义max_size后会调用系统级别的malloc,需要明确自己的使用场景会最大单次申请多大内存。如果某个场景下会经常超过max_size时,就特别要注意slab。测试场景2随机有1/1000的概率会超过4M。(场景2)。从结果看,线程越多,整个处理时间增长也很快,特别是当线程数超过Cpu的核数12后,增长迅速(猜测这个与malloc系统调用陷入内核态后,无法被随时抢占进行线程切换,导致处理时间变长,2.6后支持内核态抢占CONFIG_PREEMPT,但也不是任意时刻,线上机器编译参数好像也没开)。
  3. 场景1中1kw次malloc中,每个都小于4M,能够保证从slab内存池中分配,在线程增加的时候,性能没有明显变化,即使线程数超过了cpu核数,增加幅度也相对较小。结合server工作模型的特点(检索),一次query算一个task,完成后可以清理所有检索中allocate的object/memory,通过提供全局的nofree的一次性clear mempool来管理内存,有整体性能收益,也降低基础组件的设计实现难度。可以考虑在设计基础组件时,都是通过宿主程序统一传递内存池的方式。

结合测试结果,多线程server性能突增的场景原因的推测:绝大多数情况下,虽然我们开了N个work threads,但其实大部分都是在闲置cond_wait状态;当压力增大时,同时处在工作状态的线程上涨,多个线程竞争系统级malloc的概率增大,导致性能突增。

场景1 :  统计每个线程申请1kw次的时间,每次申请的大小都 < 4M。

image001

场景2 :  统计每个线程申请1kw次的时间,1/1000的概率申请的大小> 4M(调用系统malloc)。

image002

场景3:统计每个线程申请1kw次的时间,每次的申请大小> 4M(调用系统malloc)。

image003

,

经常会在系统中使用gettimeofday获取当前系统时间,然后在另外一处再次调用该系统函数获取系统时间,来判断一段代码的执行时间。

但由于gettimeofday的精度问题,可能存在短暂的“时光倒流”(Time Backward),如下一段程序实验

int is_less(struct timeval a, struct timeval b)
{
    if(a.tv_sec < b.tv_sec) {
        return 1;
    }
    if(a.tv_sec == b.tv_sec && a.tv_usec < b.tv_usec) {
        return 1;
    }

    return 0;
}

int main(void)
{
    while(1) {
        struct timeval last;
        gettimeofday(&last, NULL);
        struct timeval now;
        gettimeofday(&now, NULL);
        if (is_less(now, last) == 1) {
            printf("now[%lu, %lu] < last[%lu, %lu]\n",
                now.tv_sec, now.tv_usec, last.tv_sec, last.tv_usec);
            break;
        }
    }
    return 0;
}

在运行了接近12个小时后,出现了一次Time backward

详细的信息可以参考下面这个blog说明,使用time(NULL)获取时间也一样会有这个问题,实现上time函数底层就调用的gettimeofday。

http://blog.habets.pp.se/2010/09/gettimeofday-should-never-be-used-to-measure-time

如下一个文件a.txt,需要把括号中的第三列数字算术上加1,并且实现文件的原地替换,类似sed -i的选项。

setbusinesstartpos(0, 0, 1)
setbusinesstartpos(1, 1, 2)

利用perl的正则表达式-e选项实现算术运算,-i来进行原地替换,如下命令

perl -pi -e ’s/startpos\((\d), (\d), (\d)\)/”startpos\(” .$1. “, ” .$2. “, ” .($3+1). “\)”/ge’ a.txt

题目描述:
Given an array of non-negative integers, you are initially positioned at the first index of the array.
Each element in the array represents your maximum jump length at that position.
Determine if you are able to reach the last index.
For example:
A = [2,3,1,1,4], return true.
A = [3,2,1,0,4], return false.

思路:

基本的动态规划题目,一个目标index是否能到达,取决于他前面所有的index中,是否存在一个i, 满足i可达,且A[i]的value大于i到index之间的距离,状态转移公式如下:

dp[n] = ∪dp[i] ,  ( i = 0 ~ n – 1 , A[i] >= n – i)

代码:

    bool canJump(int A[], int n) {
        if(n <= 1) return true;
        vector dp;
        dp.resize(n);
        for(int i = 0; i < n; i++) {
            dp[i] = false;
        }
        dp[0] = true;
        for(int i = 1; i < n; i++) {
            for(int j = 0; j < i; j++) {
                int distance = i - j;
                if(A[j] >= distance && dp[j]) {
                    dp[i] = true;
                    break;
                }
            }
        }

        return dp[n-1];
    }

自己尝试写的一个安卓的App,结合自身的经验,收集了大量的互联网、软件公司的面试题。也收集了一些面试中需要注意的事项和准备的东西。不过应该没人在手机上复习- -,纯粹练手的app

传送门如下:http://www.anzhi.com/soft_768748.html

和同事的联调时碰到一个诡异的问题,server端的业务逻辑层面没有任何异常,但返回结果给client端时,并没有发送完所有的数据,就直接发送了RST给client,导致client读取结果失败。注: client与server直接是短连接,server在write所有的数据后会直接close。

通过tcpdump截包对比之前旧版本正常的client端通信,发送server与旧版本的client通信时,三次握手 => client发送数据 => server发送响应数据 => 四次挥手。但与新版本client通信时,则直接是 三次握手 => client发送数据 => server发送响应数据(未完成) => server发送RST

借助强大的Google大神,以及万能Stackoverflow。原因如下:当close断开连接时,如果缓冲区中又未被读取的数据,则tcp不会发送正常的FIN包,而发送RST给对端。

简单测试一下,代码如下,client和server的主要代码如下:

/*
 * client
*/
void send_plain_buf(int fd, size_t buf_size)
{
char buf[buf_size];
memset(buf, 0, buf_size);
int ret = write(fd, buf, buf_size);
if(ret < 0) {
fprintf(stderr, "send failed, err[%m]\n");
return;
}
ret = read(fd, buf, 1);
if(ret == 0) {
fprintf(stderr, "client get FIN\n");
} else {
fprintf(stderr, "read ret[%d], err[%m]", ret);
}
return;
}

/*
 *server
*/

void recv_plain_buf(int fd, size_t buf_size)
{
char buf[buf_size];
memset(buf, 0, buf_size);
int ret = read(fd, buf, buf_size);
if(ret < 0) {
fprintf(stderr, "server recv failed, err[%m]\n");
return;
}
return;
}

测试一:client发送1个byte,server读取1个byte,tcpdump截包

21:35:43.829700 IP tc-im-nrd306.tc.baidu.com.22579 > tc-im-nrd301.tc.baidu.com.8654: S 3630522968:3630522968(0) win 5840 <mss 1460,sackOK,timestamp 1827311072 0,nop,wscale 7>
21:35:43.829706 IP tc-im-nrd301.tc.baidu.com.8654 > tc-im-nrd306.tc.baidu.com.22579: S 2472593503:2472593503(0) ack 3630522969 win 5792 <mss 1460,sackOK,timestamp 2429650378 1827311072,nop,wscale 7>
21:35:43.829846 IP tc-im-nrd306.tc.baidu.com.22579 > tc-im-nrd301.tc.baidu.com.8654: . ack 1 win 46 <nop,nop,timestamp 1827311073 2429650378>
21:35:43.829873 IP tc-im-nrd306.tc.baidu.com.22579 > tc-im-nrd301.tc.baidu.com.8654: P 1:2(1) ack 1 win 46 <nop,nop,timestamp 1827311073 2429650378>
21:35:43.829876 IP tc-im-nrd301.tc.baidu.com.8654 > tc-im-nrd306.tc.baidu.com.22579: . ack 2 win 46 <nop,nop,timestamp 2429650378 1827311073>
21:35:43.829888 IP tc-im-nrd301.tc.baidu.com.8654 > tc-im-nrd306.tc.baidu.com.22579: F 1:1(0) ack 2 win 46 <nop,nop,timestamp 2429650378 1827311073>
21:35:43.830035 IP tc-im-nrd306.tc.baidu.com.22579 > tc-im-nrd301.tc.baidu.com.8654: . ack 2 win 46 <nop,nop,timestamp 1827311073 2429650378>
21:35:43.830080 IP tc-im-nrd306.tc.baidu.com.22579 > tc-im-nrd301.tc.baidu.com.8654: F 2:2(0) ack 2 win 46 <nop,nop,timestamp 1827311073 2429650378>
21:35:43.830083 IP tc-im-nrd301.tc.baidu.com.8654 > tc-im-nrd306.tc.baidu.com.22579: . ack 3 win 46 <nop,nop,timestamp 2429650378 1827311073>

测试二:client发送2个byte,server读取1个byte,tcpdump截包

21:36:31.137496 IP tc-im-nrd306.tc.baidu.com.22580 > tc-im-nrd301.tc.baidu.com.8654: S 3686863514:3686863514(0) win 5840 <mss 1460,sackOK,timestamp 1827358388 0,nop,wscale 7>
21:36:31.137501 IP tc-im-nrd301.tc.baidu.com.8654 > tc-im-nrd306.tc.baidu.com.22580: S 2526723815:2526723815(0) ack 3686863515 win 5792 <mss 1460,sackOK,timestamp 2429697693 1827358388,nop,wscale 7>
21:36:31.137666 IP tc-im-nrd306.tc.baidu.com.22580 > tc-im-nrd301.tc.baidu.com.8654: . ack 1 win 46 <nop,nop,timestamp 1827358388 2429697693>
21:36:31.137671 IP tc-im-nrd306.tc.baidu.com.22580 > tc-im-nrd301.tc.baidu.com.8654: P 1:3(2) ack 1 win 46 <nop,nop,timestamp 1827358388 2429697693>
21:36:31.137676 IP tc-im-nrd301.tc.baidu.com.8654 > tc-im-nrd306.tc.baidu.com.22580: . ack 3 win 46 <nop,nop,timestamp 2429697693 1827358388>

21:36:31.137705 IP tc-im-nrd301.tc.baidu.com.8654 > tc-im-nrd306.tc.baidu.com.22580: R 1:1(0) ack 3 win 46 <nop,nop,timestamp 2429697693 1827358388>

在net/ipv4/tcp.c:1900行附近的代码如下:

/* As outlined in RFC 2525, section 2.17, we send a RST here because
* data was lost. To witness the awful effects of the old behavior of
* always doing a FIN, run an older 2.1.x kernel or 2.0.x, start a bulk
* GET in an FTP client, suspend the process, wait for the client to
* advertise a zero window, then kill -9 the FTP client, wheee...
* Note: timeout is always zero in such a case.
*/
if (data_was_unread) {
/* Unread data was tossed, zap the connection. */
NET_INC_STATS_USER(sock_net(sk), LINUX_MIB_TCPABORTONCLOSE);
tcp_set_state(sk, TCP_CLOSE);
tcp_send_active_reset(sk, sk->sk_allocation);
..

相关参考:

  1. RFC2525中的描述: http://tools.ietf.org/html/rfc2525#page-50
  2. 一个关于此问题的描述: http://cs.baylor.edu/~donahoo/practical/CSockets/TCPRST.pdf

一个数组中的元素被分为low, medium, high三类,实现一个排序算法,将该数组按照不同的类别进行排序。规则为low < medium < high.

Example:

Input:

The input array is ['g', 'n', 'e', 'c', 't', 'z', 'o', 'f'], and the elment sorted into 3 categories as below:

low: a-h
med: i-p
high: q-z

Output:

['c', 'e', 'g', 'f', 'n', 'o', 'z', 't']

function provided listed below, and its algorithm complexityis O(n).

bool islow(char c);
bool ismed(char c);
bool ishigh(char c);

Resolution:

You can sort any array with famous sorting algorithm, like bubblesort, insertsort, quicksort and etc. However, any sorting algorithm,  based on comparation of element, can’t do better than O(nlogn) without extra memory.

The element in the array has partitioned into 3 categories, which means this array only have three different element. Therefore, You do not need to care about the ranking of element in same categories.  So, Sorting the array could use 2 partition algorithm in quicksort. First, select an element in medium category as pivot, after partition, the left side of element in low category, and the right side is mixer of medium & high. Then, select a high one, partition the latter part of array. You will get the result.  and the complexity of algorithm is O(n).

Code:

阅读全文…