青鱼 发布的文章

goLang之禅

近日再学golang
略看《A Tour of Go》
仔细看标准库代码
体会Ken等大师所认知的世界,领悟世界的真谛。

凡事都应简单,但不能过于简单 ————Albert Einstein

根据 Robert Hundt(2011 年 6 月,详见引用 28)的文章对 C++、Java、Go 和 Scala,以及 Go 开发团队的反应(详见引用 29),可以得出以下结论:

Go 和 Scala 之间具有更多

  • 的可比性(都使用更少的代码),而 C++ 和 Java 都使用非常冗长的代码。
  • Go 的编译速度要比绝大多数语言都要快,比 Java 和C++ 快 5 至 6 倍,比 Scala 快 10 倍。
  • Go 的二进制文件体积是最大的(每个可执行文件都包含 runtime)。(时间纵看,是以空间换软件复杂度,现代来说 太值了!)
  • 在最理想的情况下,Go 能够和 C++ 一样快,比 Scala 快 2 至 3 倍,比 Java 快 5 至 10 倍。
  • Go在内存管理方面也可以和 C++ 相媲美,几乎只需要 Scala 所使用的一半,是Java的五分之一左右。

内嵌类型的方法和继承

当一个匿名类型被内嵌在结构体中时,匿名类型的可见方法也同样被内嵌,这在效果上等同于外层类型 继承了这些方法:将父类型放在子类型中来实现亚型。这个机制提供了一种简单的方式来模拟经典面向对象语言中的子类和继承相关的效果,也类似 Ruby中的混入(mixin)。

type Engine interface {
    Start()
    Stop()
}

type Car struct {
    Engine
}

Go的这种设计,能更自然地表示世界,没有多继承的复杂、没有单继承的局限、不需要像PHP那样 单继承+trait补充
万物关系从来不只是继承,还有更多的组合。越是准确直接地表达世界,代码越是整洁。

本地开发测试、服务器运行的一个方案

本文目的是分享一个开发便捷、运行简便、工作优雅的开发方案。
本文适用于使用IDE写代码、看代码的RD及QA。对于热衷Vim等编辑器的同学,可能不适用。
本地指个人笔记本,服务器指的是开发运行的机器。

本地开发服务器运行.png

1.开发便捷:利用IDE的强大功能就好

2.运行简便:服务器(开发机)上的环境是直接可用的,所以将本地代码快捷地同步到服务器上运行,本地开发并提交版本控制。
什么方式?SFTP/FTP/SMB等都可以,服务器上只要运行相关服务器,本地配置认证、目录映射,本地代码变动,手动或自动地将代码上传。如何在Webstorm/Phpstorm中设置连接FTP

3.工作优雅:举例说,本地开发分支A,服务器运行调试,开发完成(提交代码)或开发至一半(git stash暂存工作进度),本地切换分支B,开发下一个功能... 此刻服务器上代码的版本控制,就是不干净的,所以在本地切分支A->B时,同时处理好服务器的代码,清理不干净的代码、同样切换A->B,以git为例

git clean -df
git reset --hard
git pull
git checkout --track origin/B

彻底解放工作中的烦事?

工作中,我们都有烦恼:人事、事务
人事您处理,这里且不说。
有什么事务,它重复、复杂、混乱、低效,让您费时、费力、伤脑筋?
可以匿名向问卷诉苦,问卷背后有方法(系统化、信息化、优化)解决您的问题。
https://www.wenjuan.com/s/j2Ef2u

remote_addr及X-Forwarded-For及用户真实IP及内网安全

先缕一下背景,计算机网络,连在网络中的机器都有一个(或多个)IP地址,提供Web服务的机器,常有一个便于人们记忆的域名,通过DNS解析到一个(或多个)IP地址。有的网站流量大,需要不止一台机器提供服务,但域名只有一个,只能指向一台机器,怎么办呢?

代理服务器负载均衡(简称LB),提升静态网页的访问速度,增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性

互联网产品做大了,再做它个开放平台,搞完用户,搞合作伙伴。对外提供内网服务,开放平台服务器(简称OP)实现认证,代理调用内网服务。
以下,OP、LB、Server均为Nginx

remote_addr_proxy.png

Web服务器,一些场景,根据来源IP地址,决定服务与否。若是内网接口,只服务内网机器,拒绝服务来自外网的请求。
遇到的问题是,当client c通过OP请求内网接口时,Server解析客户端IP为client c的IP,其为外网IP 遂拒绝了服务。此时,我们希望Server拿到的客户端IP为OP的内网IP,这样就能正常为OP代理的客户服务了。怎么做呢?

HTTP协议虽然定义了Client-Ip请求头,但不是安全的,服务器的做法是取TCP连接的对端IP作为client ip,在Nginx中,解析为变量$remote_addr,不架设代理、负载均衡时,直接拿来用即可。但当在Server前代理时,应利用Nginx的ngx_http_realip_module中的real_ip_header指令,指定用哪个请求header的值来替换默认的$remote_addr。

假设
client a IP:12.34.56.78
OP IP: 34.56.78.90 及内网IP 10.22.33.44
LB IP: 10.23.34.45
这时,我们考察 X-Forwarded-For 的定义及格式,对于上图Server接收来自client c的请求时,X-Forwarded-For首先由OP设置为client c的IP,即

proxy_set_header X-Forwarded-For $remote_addr;

LB接收此header时,应再次设置

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

此时,到达Server的信息应该是:
$remote_addr: 10.23.34.45
X-Forwarded-For: 12.34.56.78,10.22.33.44

注意,Server知道Load Balance的存在,所以不关心$remote_addr的默认值,关心的是真正的请求IP,此时可设置
real_ip_header

set_real_ip_from  10.0.0.0/8;
real_ip_header    X-Forwarded-For;
real_ip_recursive off;

关于real_ip_recursive指令,官方文档:

If recursive search is disabled, the original client address that
matches one of the trusted addresses is replaced by the last address
sent in the request header field defined by the real_ip_header
directive. If recursive search is enabled, the original client address
that matches one of the trusted addresses is replaced by the last
non-trusted address sent in the request header field.

设置off时,Server得到的$remote_addr为10.22.33.44 即开放平台的IP,正常服务!

注:RFC 7239 定义了一个新的 Forwarded header,更完备地组织这些信息。

位操作

位操作高效解决问题

其中,
Sum of Two Integers
Use ^ and & to add two integers

int getSum(int a, int b) {
    return b==0? a:getSum(a^b, (a&b)<<1); //be careful about the terminating condition;
}

用^及& 实现 加法
看了好一会儿,才看懂
两个位串相加,结果可由两部分组成:不同的位 与 相同的位
不同的位,用^取得
相同的位,相加并进位,先&运算,再左移1位
此两部分相加,即得结果,递归下去即可。

注意边界情况,整型通常4字节32位,不断左移终使b为0,结束递归。
对于python/php等脚本语言,实现了非常大的整型范围,这样写法则不成了,需用mask限制32位

class Solution(object):
    def getSum(self, a, b):
        """
        :type a: int
        :type b: int
        :rtype: int
        """
        # 32 bits integer max
        MAX = 0x7FFFFFFF
        # 32 bits interger min
        MIN = 0x80000000
        # mask to get last 32 bits
        mask = 0xFFFFFFFF
        while b != 0:
            # ^ get different bits and & gets double 1s, << moves carry
            a, b = (a ^ b) & mask, ((a & b) << 1) & mask
        # if a is negative, get a's 32 bits complement positive first
        # then get 32-bit positive's Python complement negative
        return a if a <= MAX else ~(a ^ mask)

如上,Python3整型是无界的(无限大),想限定整型上限,如何能让其如C/Java一样表示补码?
为了理解最后一行代码的含义,我们可以假设场景,然后确定目的是什么。
假设C语言int占4位,python语言int占8位,mask为0xF
举例,我们得到的a若为 0b0101,它被预期正常解释,算法结束;若a为0b1011,根据此算法的隐含条件,我们想让它被解释成负数,就得让它符号扩展到 0b11111011

~(a ^ mask)

0b1011 => 0b0100 => 0b11111011