一种通用的百亿级数据清洗方案

最近两个月,一直在和刀哥两个人重构连尚读书这边的用户行为日志系统。到本周放量完所有的数据到新系统,基本算告一个段落。

目前的业务情况,大概是有新旧两套日志系统数据,日志规模(2018.11),新日志一天产生6000万条日志,旧日志一天产生4000万条日志数据,合计1亿条上报日志,这些日志数据,都是合并上报的,根据统计,大概一条上报日志,会产生50条最终日志数据。所以最终的日志量,超过了50亿条(写这篇博客时,2019.1,已经超过70亿条)。

根据业务特点,预计的高峰期是10个小时(按40000秒计算), 100000000 / 40000 = 2500条/秒。整个系统每秒要完成 2500条上报日志的收集。然后要转化为 2500 * 50 = 125000条/秒的最终结果日志数据。晚上21 ~ 22点的最高峰,处理量还要预留x4,估计会处理10000条的收集日志数据,完成生产500000条/秒最终结果日志数据。

最终结果日志数据文件的单条大小在1 ~ 2 kbyte之间,多数为1 kbyte

最终结果日志数据,需要存储在本地硬盘+大数据的Kafka集群(9台机器)两边做容灾。

如此大规模的数据,不管是收集,清洗,本地存储,还是入库,都是非常有挑战的一项工作,更何况是重构。。。

一、旧的架构情况,使用的机器规模大概是20台机器.

注释:

1、Bear服务是这边之前的同事用Golang + Leveldb写的一个服务,可以用来接收HTTP请求传输的数据到Leveldb,然后再把对应的数据,发送到指定的HTTP 地址(转发数据)或者是发送到指定的Kafka集群,可以起到数据的缓存作用

2、之前得到的同事的反馈,都说这个Bear服务的性能很高,不存在问题

旧架构存在的问题

1、无法追踪单条数据的处理情况,因为数据没有任何的标号,导致要反查或者是顺查数据,基本没法

2、Bear只会把数据存储在Leveldb里面,外层没有日志,再加上没有源码,无法做任何修改(我也不知道为啥没源码啊)

3、之前的同事反馈说Bear的性能很高,不存在性能问题,但是我们实际观察发现,问题最大的就是这个Bear,一个是接收性能不行,另外一个就是数据转发性能不行,不管是接收HTTP数据,还是转发数据到HTTP或者Kafka集群,Bear都给不出来量,所以导致经常出现拥堵的情况,需要不停的多开Bear服务,其性能有严重的问题

4、本地没有数据,无法做数据重放。不管是收集日志,还是最终日志,我们这边完全没任何原始数据,一旦入了Kafka集群后,我们就无能为力了,无法校对数据,无法重放,无法追踪处理流程

5、因为使用Bear做数据缓存,他只支持HTTP请求的数据清洗,导致只能走php-fpm,然后他的转发性能又不行,所以导致整个系统的数据清洗能力极低

二、新的架构情况,使用的机器规模为12台 + 3 组Redis实例

优点

1、不管是收集的原始日志数据还是处理以后的最终日志数据,我们都有存储,随时可以重放

2、每条日志加了不会重复的logid,可以根据logid追踪到任何一条数据的流转过程和处理结果,并且大数据那边可以根据logid去重数据

3、不管是收集端的API日志服务器,还是Redis,还是消费服务器,都是可以任意的横向的扩展的,而且不影响任何第三方,性能可以直线上升

4、日志数据压缩,采用的是pigz的并行压缩,每天凌晨压缩前一天的日志数据文件,在目前的日志规模下,在一个小时内,可以压缩完成所有的日志,对业务和机器负载不会带来任何影响,而且数据的压缩比率,在1:20以上

5、因为采用了脚本主动拉取的模式,所以只要消费服务器足够,理论上任何数据都会在3s内被处理,达到实时效果

6、业务采用了脚本的模式,执行效率相比原来的Nginx + php-fpm的模式,性能提升了几十倍,而且因为不走HTTP协议了,所以内网的带宽使用也成倍的下降,不到原来的一半

7、因为使用了Logstash的批量提交模式,数据入Kafka的性能,提升了几十倍

8、因为启用了Logstash的永久队列,基本上保障了数据的不丢失,经过对比,和Kafka里面统计出来的数据,误差在百万分之几的级别

9、在入Logstash时,采用了失败就扔Redis队列再用另外的消费脚本入可用的其他Logstash的方式,保障说即使本地的Logstash宕机,数据依然可以正常的入Kafka集群

10、消费脚本进程,采用了supervisor来做管理,新、旧版消费日志脚本,单机各开100个脚本,主要 supervisor 需要采用 3.3以上的版本,3.3以下的版本,对于管理几百个进程,会有问题

11、各段都可以方便的知道性能瓶颈,不管是Filebeat的收集端,Redis队列端,还是Logstash端,都提供了良好的监控数据,可以即时了解系统的工作状态。

三、重构完成后,新旧系统的服务器机器负载对比

旧系统单机

新系统

消费服务器的负载
Redis负载

目前,单日清洗的数据量,已经超过70亿条,按现在的机器负载预估,这5台机器,预计处理清洗150亿条日志数据,没有任何问题。

优化Filebeat+Logstash的性能

最近一直在重构新公司的日志传输系统,因为业务量较大,目前的单日日志条数已经超过了30亿条,而且业务有明显的高峰期。所以日志收集传输系统,必须要满足明显的波峰性能要求。方案还是以Filebeat + Logstash为主,Logstash直接入kafka, Filebeat从磁盘读取文本文件(json格式)。

优化完成后,单filebeat + 单logstash可以处理 30000条/秒的日志. 单filebeat + 多logstash可以处理 40000条/秒的日志.

日志大小为1.2kbyte.

环境信息:

2台服务器, 32core, 200GB内存, SSD硬盘, 千兆网络内网互联

Filebeat 6.5.2

/usr/bin/filebeat -c /data/filebeat.yml

Logstash 6.5.2

/usr/share/logstash/bin/logstash -f /etc/logstash/logstash-file.conf --path.settings /etc/logstash --path.data /data/tmp/logstash/data --path.logs /data/tmp/logstash/logs -w 8

优化后的配置文件信息如下:

filebeat.yml

关键参数:

scan_frequency

harvester_buffer_size

queue.mem.*

filebeat.inputs:
- type: log

  # Change to true to enable this input configuration.
  enabled: true
  encoding: utf-8

  # Paths that should be crawled and fetched. Glob based paths.
  paths:
    - /data/tmp/data/testlogstash3.log
    #- c:\programdata\elasticsearch\logs\*

# Filebeat以多快的频率去prospector指定的目录下面检测文件更新比如是否有新增文件如果设置为0s则Filebeat会尽可能快地感知更新占用的CPU会变高。默认是10s。
  scan_frequency: 1s
  # 如果设置为true, Filebeat从文件尾开始监控文件新增内容把新增的每一行文件作为一个事件依次发送而不是从文件开始处重新发送所有内容。
  tail_files: false
  harvester_buffer_size: 104857600

# backoff选项指定Filebeat如何积极地抓取新文件进行更新。默认1s. backoff选项定义Filebeat在达到EOF之后再次检查文件之间等待的时间
  backoff: 1s
# 在达到EOF之后再次检查文件之前Filebeat等待的最长时间
  max_backoff: 10s

  close_inactive: 6h
  clean_inactive: 72h
  ignore_older: 70h
  close_timeout: 6h
  fields:
    log_name: newdata

- type: log

  # Change to true to enable this input configuration.
  enabled: true
  encoding: utf-8

  # Paths that should be crawled and fetched. Glob based paths.
  paths:
    - /data/topicdata/*.hequandata

# Filebeat以多快的频率去prospector指定的目录下面检测文件更新比如是否有新增文件如果设置为0s则Filebeat会尽可能快地感知更新占用的CPU会变高。默认是10s。
  scan_frequency: 1s
  # 如果设置为true, Filebeat从文件尾开始监控文件新增内容把新增的每一行文件作为一个事件依次发送而不是从文件开始处重新发送所有内容。
  tail_files: false

# backoff选项指定Filebeat如何积极地抓取新文件进行更新。默认1s. backoff选项定义Filebeat在达到EOF之后再次检查文件之间等待的时间
  backoff: 1s
# 在达到EOF之后再次检查文件之前Filebeat等待的最长时间
  max_backoff: 10s

  close_inactive: 6h
  clean_inactive: 72h
  ignore_older: 70h
  close_timeout: 6h
  fields:
    log_name: olddata



#============================= Filebeat modules ===============================

filebeat.config.modules:
  # Glob pattern for configuration loading
  path: ${path.config}/modules.d/*.yml

  # Set to true to enable config reloading
  reload.enabled: false

#==================== Elasticsearch template setting ==========================

setup.template.settings:
  index.number_of_shards: 3
  #index.codec: best_compression
  #_source.enabled: false

#================================ General =====================================
filebeat.registry_file: /data/tmp/registry-logstash3.index

max_procs: 8

path.home: /etc/filebeat
path.config: /etc/filebeat
path.data: /data/filebeat/data
path.logs: /data/filebeat/logs

queue.mem.events: 409600
queue.mem.flush.min_events: 1024
queue.mem.flush.timeout: 2s


#================================ Outputs =====================================
output.logstash:
  enable: true
  hosts: ['10.28.3.8:5046','10.28.3.8:5047','10.28.3.8:5048','10.28.3.8:5049']
  loadbalance: true
  worker: 2
  bulk_max_size: 50000
  compression_level: 0


#================================ Logging =====================================

# Minimum log level. One of debug, info, warning, or error. The default log level is info
logging.level: info
logging.to_files: true
logging.files:
  path: /data/tmp
  name: filebeat-logstash3.log
  keepfiles: 7
  rotateeverybytes: 10485760
  interval: 24h
  permissions: 0644

logstash.conf配置文件

input {
    beats {
        port => 5046
    }
}

filter {
    grok {
        match => {
            "message" => "(?<kafkaname>\S+?)##########(?<kafkadata>.*)"
        }
        overwrite => ["message"]
    }
}

output {
    if[fields][log_name] == "newdata" or [fields][log_name] == "olddata" {
        file {
            path => "/data/tmp/logstash/logstash-kafkadata5046.log"
                codec => line {
                    format => "%{+YYYY-MM-dd HH:mm:ss}##########%{kafkadata}"
                }
        }
    }
}

logstash.yml配置文件

pipeline.workers: 15
pipeline.output.workers: 15
pipeline.batch.size: 5000
pipeline.batch.delay: 10

优化后的结果(单Filebeat + 单Logstash):

单条文本大小为 1.2kbyte

优化后的结果(单Filebeat + 4个Logstash):

单条文本大小为 1.2kbyte大小.

在Ubuntu 16.04 以及Windows下面编译生成门罗币(XMR)挖矿程序(xmr-stak)

门罗币作为2014年诞生的真正匿名性加密货币,其潜力巨大,挖矿难度也巨大,批量部署自己的矿机就涉及到编译自己的挖矿程序。
平台
ubuntu 16.04/14.04

apt-get install -y build-essential libtool autotools-dev autoconf pkg-config libssl-dev  git-core libboost-all-dev libqrencode-dev libminiupnpc-dev libevent-dev libsodium-dev build-essential libtool autotools-dev autoconf automake libssl-dev libboost-all-dev libdb-dev libdb++-dev pkg-config libevent-dev git-core cmake libmicrohttpd-dev libssl-dev cmake build-essential libhwloc-dev
https://github.com/fireice-uk/xmr-stak.git
cd xmr-stak  # 可以找到里面donate的地方,将算力捐赠调整为0%
mkdir build
cd build
cmake .. -DCUDA_ENABLE=OFF -DCPU_ENABLE=ON -DOpenCL_ENABLE=ON  # 只支持CPU&AMD
cmake .. -DCUDA_ENABLE=ON -DCPU_ENABLE=ON -DOpenCL_ENABLE=OFF # 只支持CPU&NVIDIA
cmake .. -DCUDA_ENABLE=OFF -DCPU_ENABLE=ON -DOpenCL_ENABLE=OFF # 只支持CPU

因为自己手边都是nvidia的显卡矿机,所以下面添加部署Nvidia CUDA支持的指令步骤
https://developer.nvidia.com/cuda-downloads
在上面的网页里面,有nvidia官方的各平台编译说明
因为我自己是ubuntu 16.04的平台,所以下面的步骤针对ubuntu 16.04平台

https://developer.nvidia.com/cuda-downloads?target_os=Linux&target_arch=x86_64&target_distro=Ubuntu&target_version=1604&target_type=debnetwork
wget -c "http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1604/x86_64/cuda-repo-ubuntu1604_9.1.85-1_amd64.deb"
dpkg -i cuda-repo-ubuntu1604_9.1.85-1_amd64.deb
apt-key adv --fetch-keys http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1604/x86_64/7fa2af80.pub
apt-get update
apt-get install cuda
ldconfig

平台
Windows x64

https://developer.nvidia.com/compute/cuda/9.1/Prod/local_installers/cuda_9.1.85_windows


cd xmr-stak

"C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\Tools\VsMSBuildCmd.bat"
set CMAKE_PREFIX_PATH=C:\xmr-stak-dep\hwloc;C:\xmr-stak-dep\libmicrohttpd;C:\xmr-stak-dep\openssl

set CUDA_TOOLKIT_ROOT_DIR=C:\cuda91\dev
set CUDA_NVCC_EXECUTABLE=C:\cuda91\dev\bin
set CUdA_INCLUDE_DIRS=C:\cuda91\dev\include
set CUDA_CUDART_LIBRARY=C:\cuda91\dev\lib
mkdir build
cd build

cuda8 => unknown

cuda9
cmake -G "Visual Studio 15 2017 Win64" -T v141,host=x64 -DCUDA_TOOLKIT_ROOT_DIR=C:/cuda91/dev -DOpenCL_ENABLE=OFF ..
cmake -G "Visual Studio 14 2015 Win64" -T v140,host=x64 -DCUDA_TOOLKIT_ROOT_DIR=C:/cuda91/dev -DOpenCL_ENABLE=OFF ..

cmake --build . --config Release --target install


Visual Studio 2017 Community
blob:https://www.visualstudio.com/26d7f816-38d5-4ace-a55d-249bd2f056d4

在Ubuntu 16.04 x64下面编译比特币源码生成钱包

在Ubuntu 16.04 x64下面编译比特币源码
准备

apt-get install -y build-essential libtool autotools-dev autoconf pkg-config libssl-dev  git-core libboost-all-dev libqrencode-dev libminiupnpc-dev libevent-dev libsodium-dev build-essential libtool autotools-dev autoconf automake libssl-dev libboost-all-dev libdb-dev libdb++-dev pkg-config libevent-dev git-core cmake libmicrohttpd-dev libssl-dev cmake build-essential libhwloc-dev


#apt-get install -y libqt5gui5 libqt5core5 libqt5dbus5 qttools5-dev qttools5-dev-tools libprotobuf-dev protobuf-compiler

wget -c 'http://download.oracle.com/berkeley-db/db-4.8.30.NC.tar.gz'
tar xvf db-4.8.30.NC.tar.gz
cd db-4.8.30.NC/build_unix/ && ../dist/configure --enable-cxx --with-pic --prefix=/usr/local/db4/ && make -j4 && make install

vim /etc/ld.so.conf
/usr/local/db4/lib
ldconfig

编译纯命令行钱包

git clone https://github.com/bitcoin/bitcoin.git
cd bitcoin
bash autogen.sh
./configure LDFLAGS="-L/usr/local/db4/lib" CPPFLAGS="-I/usr/local/db4/include" --without-gui --with-incompatible-bdb
make  -j4

编译QT钱包

apt-get install -y libqt5gui5 libqt5core5 libqt5dbus5 qttools5-dev qttools5-dev-tools libprotobuf-dev protobuf-compiler libqt5-dev
git clone https://github.com/bitcoin/bitcoin.git
cd bitcoin
bash autogen.sh
./configure LDFLAGS="-L/usr/local/db4/lib" CPPFLAGS="-I/usr/local/db4/include" --with-gui --with-incompatible-bdb
make  -j4

在Linux下面编译cpu挖矿程序

今年比特币大火,进入又一个超级牛市,也逐渐的从极客圈进入公众的视野,虽然是2013年就开始买币的老韭菜,但是因为2016年买房,虽然2016年全部提现了,导致2017年没有资金买币,完美错过比特币这轮牛市。
但是没事儿啊,作为一个工程师,买不起币,咱还不能挖币么?
下面说说编译CPU挖币程序的步骤,因为很多币没有提供linux下面的挖矿程序,导致我们没法在早起挖到大量的币。
以ubuntu x64举例
准备工作

apt-get update
apt-get install openssl libssl-dev build-essential -y
apt-get install  libcurl4-openssl-dev -y

下载挖矿代码,以 www.vvpool.com 上面新推出的btv为例
btv官方提供的挖矿代码仓库为
https://github.com/bitcoinvote/cpuminer-multi
编译平台目标为【x86-64】

git clone https://github.com/bitcoinvote/cpuminer-multi.git
cd cpuminer-multi
./autogen.sh
./configure CFLAGS="-march=x86-64"
make -j4

则当前目录下面会有一个名字叫【minerd】的程序,copy到/usr/bin/或者/usr/local/bin目录下面

cp minerd /usr/bin/

生成自己的钱包地址,我的btv钱包地址为

15FTEBU2mb41UguPrk4BBS53R5LqYsQt8G

开启挖矿之旅

minerd -a cryptonight -o stratum+tcp://btv.vvpool.com:5700 -u 15FTEBU2mb41UguPrk4BBS53R5LqYsQt8G.10001 -p x -t 4

具体参数,使用 minerd –help可以看到
其他算法的币,流程类似~~~
如此简单~~~

Linux Mint 18(ubuntu 16.04)桌面版本系统安装完成后的初始化

永久修改dns服务器

vim /etc/resolvconf/resolv.conf.d/head
nameserver 119.29.29.29
nameserver 8.8.8.8
或者
vim /etc/network/interfaces
dns-nameservers 119.29.29.29 8.8.8.8
apt-get install fonts-wqy-zenhei fonts-wqy-microhei ttf-wqy-microhei ttf-wqy-zenhei openssl libssl-dev build-essential libevent-dev -y

安装java 8

apt-get install openjdk-8-jre-headless

安装nginx & mysql

apt-get install nginx
apt-get install apt-get install mysql-server-5.7 mysql-client-5.7

安装php7.1

add-apt-repository ppa:ondrej/php
apt-get update

apt-get remove php5-fpm php5-cli php5-dev -y

apt-get install php7.1 php7.1-cgi php7.1-cli  php7.1-dev php7.1-fpm php7.1-bcmath php7.1-bz2 php7.1-common php7.1-curl php7.1-gd php7.1-gmp php7.1-imap php7.1-json php7.1-mbstring php7.1-mcrypt php7.1-mysql php7.1-odbc php7.1-readline php7.1-soap php7.1-xml php7.1-xmlrpc php7.1-zip php7.1-opcache php-redis php-memcache php-memcached

安装event扩展支持workerman

pecl install event 
或
wget -c "https://www.openssl.org/source/old/1.0.1/openssl-1.0.1u.tar.gz"
wget -c http://pecl.php.net/get/event-2.3.0.tgz


./configure --with-event-openssl --with-openssl-dir=/usr --with-libdir=lib/x86_64-linux-gnu/
make
make install

安装搜狗拼音输入法

apt-get install -f
dpkg -i /windows/epan/sogoupinyin_2.1.0.0086_amd64.deb

重启&设置输入法即可

ubuntu下shadowsocks启动报错

pip install shadowsocks

http://blog.csdn.net/blackfrog_unique/article/details/60320737
用vim打开文件:vim /usr/local/lib/python2.7/dist-packages/shadowsocks/crypto/openssl.py (该路径请根据自己的系统情况自行修改,如果不知道该文件在哪里的话,可以使用find命令查找文件位置)
跳转到52行(shadowsocks2.8.2版本,其他版本搜索一下cleanup)
进入编辑模式
将第52行libcrypto.EVP_CIPHER_CTX_cleanup.argtypes = (c_void_p,)
改为libcrypto.EVP_CIPHER_CTX_reset.argtypes = (c_void_p,)
再次搜索cleanup(全文件共2处,此处位于111行),将libcrypto.EVP_CIPHER_CTX_cleanup(self._ctx)
改为libcrypto.EVP_CIPHER_CTX_reset(self._ctx)
保存并退出
启动shadowsocks服务:service shadowsocks start 或 sslocal -c ss配置文件目录
问题解决

cp /windows/dpan/linux/linux-config/myown.service /lib/systemd/system/myown.service
systemctl start myown

终端字体
文泉驿等宽微米黑 12号

安装shutter

apt-get install  libgoo-canvas-perl
apt-get install shutter

键盘快捷键里面映射 【shutter -s 】为【Ctrl + Alt + A】

安装uget

add-apt-repository ppa:plushuang-tw/uget-stable
apt-get update
apt-get install uget

安装aria2

add-apt-repository ppa:t-tujikawa/ppa
apt-get update
apt-get install aria2

安装teamviewer

apt-get install -f
apt-get install /windows/epan/teamviewer_i386.deb

安装vlc

add-apt-repository ppa:videolan/master-daily
apt-get update
apt-get install vlc

安装cairo-dock

add-apt-repository ppa:cairo-dock-team/ppa 
apt-get update
apt-get install cairo-dock cairo-dock-plug-ins
cairo-dock

Ubuntu 14.04升级到php7.1等版本

命令如下

add-apt-repository ppa:ondrej/php
apt-get update

apt-get remove php5-fpm php5-cli php5-dev -y

apt-get install php7.1 php7.1-cgi php7.1-cli  php7.1-dev php7.1-fpm php7.1-bcmath php7.1-bz2 php7.1-common php7.1-curl php7.1-gd php7.1-gmp php7.1-imap php7.1-json php7.1-mbstring php7.1-mcrypt php7.1-mysql php7.1-odbc php7.1-readline php7.1-soap php7.1-xml php7.1-xmlrpc php7.1-zip php7.1-opcache php-redis php-memcache php-memcached -y

service php7.1-fpm restart

浅谈创业公司的技术问题系列之二

前面写了 浅谈创业公司的技术问题系列之一 这一篇文章,很多朋友加我微信,说真是字字见血啊,因为很多人都不幸的踩中其他的2、3条,真是苦逼透顶了。哈哈,确实,在没有靠谱的技术头目的情况下,“老板”自己要hold住一个不懂的东西,而且又是搞代码这一块儿的事情,确实不容易。不过呢,今天不说这个,今天说其他的,说一下“技术的边界”(或者说是技术的局限性或者甚至往大了说是做事的边界也行)。

ps:先吐糟一下,最近AlphaGo大战李世石啊,很多人不懂装懂或者是吹牛逼都说人工智能怎么样厉害、怎么样牛逼,其实现阶段,人工智能就是处于弱智阶段或者是没有智阶段,担心个屁,那些搞这一行的也不要吹牛逼,你牛逼,先把汽车自动驾驶搞定了再说,连复杂的地上交通线都识别不了怎么开最安全,还智能、进化,扯什么淡呢?

说回原题,2011年吧,做互联网这一行的,又特别是腾讯系的吧,广泛流传的一句话就是所说马化腾说的:“产品就是这样儿,不要跟我说在技术上办不到”。这一句话,被很多的产品经理、高管当做圣谕来回应技术说这个很难、改动很大、需要很多时间之类的评估。现在吧,随着互联网+的深入,很多传统公司也在招互联网人才,将自己的业务互联网化,然后就喝了这样的鸡汤,所以所有这类喝了这个鸡汤的人都把这个学到了,认为没有什么是技术做不到的。

我认同这个吗?从语义上说,说实话,我还真得认同。

但是,现在我们能去火星吗?我们能够用一根杠杆撬动地球吗?我们能够永生吗?小米抢新手机能不排队吗?淘宝双11订单提交页面能够不挂吗?

咦~~~怎么办不到呢?

其实,我们都相信,上面列举的这些,我们都可以做到,只是需要一个前提,我们连续投入经费,让这些技术人员搞个5年、10年、100年,肯定都实现了。但是,谁来投入?谁等得起?

这就是边界,技术的边界,事物的边界。

马化腾要一个完全自己从零开发的操作系统,腾讯能够做到吗?告诉你,腾讯真能做到,当腾讯把自己的股票全换成钱来做投入,搞个10年、8年的,肯定做得出来。但是他舍得投入吗?等得起吗?

也许有人说你说的东西太大了,实际不会出现要开发操作系统,也没有人想要用杠杆撬动地球,真的吗?

那我把他缩小。

当开发一个App、WEB产品时,技术告诉你,因为其中的一个“小”又“不重要”的功能feature得把现有的几乎所有重要的数据库都折腾一遍、而且折腾的时间可能会导致开发周期延期几周、或者是牵扯进来更多的人时,你觉得你跨越边界了吗?

做什么东西,是要考虑投入产出比的,做销售的,要考虑毛利润率、净利润率,做技术的,当然就要考虑工时与人力投入产出比。

什么?你是理想的追求者?不在乎?那算我白说。

多考虑投入产出比吧,不要去追求牛逼或者是装逼,不要去跨越边界,这个才是做实事的心。

其实很多事情,大家各尽其职就可以干得很好了,但是不好意思,多数情况下是很多是本职都没有干好,导致事情搞烂,更不要说追求理想了。

浅谈创业公司的技术问题系列之一

最近2年多在多备份(www.dbfen.com)创业,跟很多创业公司的同事聊得很多、见得也很多,对很多创业公司遇到的技术问题,写一个归纳总结吧,也算是对自己过往的一个回顾,更希望能够帮到部分新的创业人士更好的了解互联网的技术到底是个什么鬼。

首先介绍一下我自己的经历,以表示我写这篇文章不是纯粹吹牛,而是真实经历。我个人简历比较的复杂,早年做过VC++(MFC)、写过超级复杂的Shell脚本、用C++写过高性能网络服务(NoSQL数据库)、搞过PHP框架、写过各种Python脚本、也写过Java、也折腾过Android,对各种技术,基本上都有比较长的使用时间(C++ 六年以上,PHP 五年以上,Java 两年以上,Python 六年以上);做过的业务更是五花八门,有传统的PC端桌面软件开发、有传统的系统集成项目、有中国最早的O2O项目、有电商平台、IaaS云平台、SaaS云平台、游戏等等,现在比较常见的业务,基本上都有过工作经历;职位也从普通的工程师做到CTO了,也可以说得上见多识广了吧。

:文中可能会说到某些编程语言的问题,事先声明我对编程语言无偏见,只是就事论事,我不喜欢参与“哪个编程语言更好”这样的争论。

下面从几个方面聊起吧

1、互联网项目的技术是否能够决定一个产品的成败?
答案在多数情况下是否定的,很多互联网公司,一开始技术是很烂的,即使发展到一定阶段了,还是非常的烂。举两个例子,不知道大家有印象没,2011年、2012年京东做大促的时候,网站都会打不开,最有名的就是刘强东拿把刀到会议室,说“网站还是打不开,下不了单,就把技术砍了”,但是京东还是做大了,这是一个例子;另外一个例子就是曾经呆过的TOP5的游戏平台,内部技术更不要说了,在我看来是不及格的,但是他们现在越做越大。可见技术在多数情况下是不能决定项目成败的,除非你是非常高大上的科技项目,否则一般来说互联网项目的发展还是重在运营和产品本身的竞争力上面。当然,这不是说做一个新项目一开始就可以接受很烂,这个完全看你团队的实力,有实力的,前期还是建议招好一点儿的技术团,做好一点儿,免得后面补交更多的学费。
建议:多数互联网项目,应该更重视运营、市场、销售,重视盈亏平衡,这个才是根本。

2、技术的选型重要吗?
非常非常非常重要,重要的事情说三遍,良好的技术选型,可以大大的节省开发人力,推进项目进度,节省公司的运营成本。我见识过非常多的项目因为技术选型导致的项目进度拖延了。举几个例子吧。有两个不同业务的公司,某天因为某个需求,其中的“资深”工程师对领导说golang写基础服务有多牛逼,自己刚好也会写,然后领导一拍板同意,自己的一些服务就用这个做了,后来写这个服务的同事离职了,然后就没有然后了,为什么呢?因为公司内部除了离职的这个人外,找不到其他人会golang,而目前社招很难招到写golang的工程师,内部培养?别扯这个淡了,这是第一个。另外一个就是某司,听信某些技术大牛的建议,模仿大公司的架构,在自己业务引入了复杂的分层机制,没错,就是大家最近听得很多的、非常火热的“微服务”,恩,一个小的网站,一天不到10W的PV吧,写了30多个微服务,然后?就没有然后了,问到我怎么解决,我说除了推翻重来或者维持现在的开发继续搞以外,我也找不到解决办法。
建议:创业团队的技术选型,应该只选对的不选逼格高的,选择的技术方案应该符合满足当前或未来半年的需求,好招人、好培养人、人力成本低、方案具有简单可维护性,把持住这些,再差都有一层的。

3、做技术的人贵吗?
一点儿不贵,比较一下生活成本吧,深圳、北京房价最近10年翻了10倍,物价翻了5-10倍,收入有翻10倍吗?大家心里都有数。加上供需失衡、人员培养周期长,做互联网相关技术的,比其他行业的薪水高就再正常不过了,对比起生活成本,现在这些人的薪水真不贵,税倒是真贵。
建议:有条件,到成都、长沙、重庆、西安去建研发中心吧。

4、大公司的技术高管出来带创业团队就靠谱吗?
不一定,不好意思,我也有很多BAT或者是其他大公司的朋友、同事、同学,我自己也在大公司呆过,这个靠谱不靠谱跟这个人是大公司还是小公司出来的还真没有关系,也没有感觉到大公司出来的多数就是靠谱的这个事实,事实是很多大公司出来的技术高管出来带技术团队反而带不好,我身边还真有好几个这样的例子,都是做到腾讯事业群开发总监出来的,带的技术团队做的东西乱七八糟,为什么?原因很简单:一个造轮子的人是造不出来一辆汽车的。大公司做的技术分工很细,他里面的高管当然也就细了,比如运维总监、工程总监,看起来都是level非常高的人,但是实际上,他们是不适合带业务开发团队的,因为他们根本从来没有做过业务,基本上是不知道怎么选择合适当前业务的技术,还是需要靠学,而且由于技术人员的一种思维局限性或者是思维惯性,导致他们非常难扔掉之前引以为傲的东西,比如他之前是写C++的,那么他在做一个技术选型的时候,不管怎样,都会带上这个东西要用C++写,多数人是不会想这个东西用C++写合适与否这个问题的。
这是一个大问题,我已经见过好几例踩进这个坑里面的案例了。
建议:选择带领团队做过从0到1业务的,而不是某一个小块的;选择不是非常技术化或者非常open的人选做你的技术leader吧。

5、创业公司的技术人员要全面技能还是单一技能?
答案当然是前者,只要你的项目不是需要非常高深技术的。创业公司要做的事情是比较多的,特别是早期,人少事儿多,一般都是希望有问题就能够顶上,所以需要的是全而不是专。这也从一个侧面印证了大公司出来的人在创业早期可能并不适合创业项目,因为太专了,特别是在里面做了好几年的,人贵又不适合,真是悲了个催。这个问题,我跟很多兄弟公司的技术负责人都聊过,多数都是同样的看法。
建议:选择技术全面的,合适的,主动性强的,有责任心的

6、人员招募是多招几个差的还是招精干的?
当然是精干的,差的写的东西问题多,可能是1/4的时间在干活,3/4的时间在解决各种bug,还要忍受客户的骂声,到处都不满意,何必呢?
建议:早期的话,一定要记住,原则一定是把3个差的工资拿来请2个精干的,能够保质保量,少很多麻烦,又省心,何乐而不为?

7、技术到底是干嘛的?
对多数互联网项目来说,技术是来实现产品的,是来服务客户的,是一个支持型的工种。仅此而已。

你的团队做到这些了吗?遇到哪些问题?欢迎抛出来一起讨论。

本文作者微信:stamhe
本文最初发表在 www.stamhe.com 上,转载请注明出处,