linux下/proc/pid/思维发散

/proc/pid 是反应进程实际使用的环境资源使用情况,记住是实际

1、/proc/pid/limits

Too many open files相信这种错误很多人都遇到了,总以为自己设置的ulimit没错,结果问题发生了。

2、/proc/pid/fd

很多时候我们的开发服务程序写归档日志,写文件,socket句柄,在这里你能看到关于所有IO句柄的新增和释放情况。

3、/proc/pid/exe

可执行程序驻留,可以是一份copy,有没有玩过程序启动后,把原始执行文件删除掉!有点像早现的木马程序。

这能解决版本纠纷问题,你懂的。

4、/proc/pid/maps

可以看到可执行外挂库的地址情况,包括动态库dopen的。

5、/proc/pid/cwd

你可以看到执行程序的执行目录

6、/proc/pid/cpuset

cpu 亲缘性分析

7、/proc/pid/coredump_filter

生成 crash dump文件的参数

8、wait



关于多进程设计的思考

我们为什么需要考虑多进程?

  • 解决单进程的IO处理、计算或存储负载瓶颈的问题。

  • 解决单点故障的问题


    就拿我碰到的多进程案例为例:

        用户聊天消息通道

        分布式存储并发写入、多机存储

        hadoop mapreduce 并行计算

        主备问题


    这些设计我都采用zookeeper+kv DB去解决。

关于客服系统的业务ID设计

ID 设计 的核心表设计的关键,我们分析下几种业务场景【用户行为、坐席行为】

1、用户会话ID

2、坐席班次ID

3、用户与坐席、其他虚拟设备的接触ID

4、以及在这些ID里面的状态变化


设计原则:弱化设备事件,强化人的相关操作与事件

在线客服系统核心业务设计分析

客服系统核心业务设计分析:

通话

    所有通话

    我的通话

    未接来电

    我的未接来电

消息

    所有记录

    我的记录

客户

    所有客户

    我的客户

    客户配置-定制化客户资料字段

业务(订单、登记)

    所有业务

    我的业务

    业务配置-定制化业务字段

工单

    

质检

    质检模板

    质检任务

    质检结果

问卷与调查

    问卷

    满意度调查

管理

    统计-呼入、呼出、坐席KPI、满意度统计

    质检-模版、质检结果

    监控-坐席监控、话务监控、整体监控

    批量外呼

知识库-外挂

面板(话务电话条、消息交互窗、待办与历史服务、提醒)

交流-类围脖的开放式交流评论

[研发生态]持续集成之ant makefile 模版

关注 jenkins: 持续的软件版本发布/测试项目\监控外部调用执行的工作,当然这样的工具太弱了,才用(puppet,chef)自动化分布式运维+自定义脚本或程序才是非常强大的。

ant build.xml 版本发布build.xml 模板

<?xml version="1.0"?>
<project default="KscMonitor">
	<property name="src.dir" location="src"></property>
	<property name="current.dir" location="./WebRoot/WEB-INF/"></property>
	<property name="lib.dir" location="./WebRoot/WEB-INF/lib/"></property>
	<property name="build.dir" location="build"></property>
	<property name="build.jar" location="${build.dir}/jar"></property>
	<property name="build.war" location="${build.dir}/war"></property>
	<property name="build.war.classes" location="${build.war}/WEB-INF/classes"></property>
	<property name="build.war.lib" location="${build.war}/WEB-INF/lib"></property>
	<property name="build.classes" location="${build.dir}/classes"></property>
	<property name="build.test.classes" location="${build.dir}/test/classes"></property>
	
	<path id="compile-path">
		<fileset dir="${lib.dir}" includes="**/*.jar"></fileset>
	</path>
	
	<path id="test-compile-path">
		<path refid="compile-path"></path>
		<pathelement location="${build.classes}"/>
	</path>
	
	<path id="test-run-path">
		<path refid="test-compile-path"></path>
		<pathelement location="${build.dir}/test/classes"/>
	</path>
	
	<target name="clean">
		<delete dir="${build.dir}"></delete>
		<!--
		<delete dir="${lib.dir}"></delete>
		-->
	</target>
	
	<target name="init" depends="clean">
		<mkdir dir="${build.dir}"/>
		<mkdir dir="${build.jar}"/>
		<mkdir dir="${build.war}"/>
		<mkdir dir="${build.war.classes}"/>
		<mkdir dir="${build.war.lib}"/>
		<mkdir dir="${build.classes}"/>
		<mkdir dir="${build.dir}/test/classes"/>
		<copy todir="${build.war}/WEB-INF">
			<fileset dir="${current.dir}" includes="web.xml"></fileset>
			<fileset dir="${current.dir}" includes="kscmonitor.conf"></fileset>
		</copy>
	</target>
	
	<target name="compile" depends="init">
		<javac srcdir="${src.dir}" destdir="${build.classes}" classpathref="compile-path">
			<compilerarg value="-Xlint:unchecked"/>
		</javac>
	
		<copy todir="${build.classes}">
			<fileset dir="${src.dir}" excludes="**/*.java"></fileset>
		</copy>
			
	</target>
	
	<target name="war" depends="compile">
		<copy todir="${build.war.classes}">
			<fileset dir="${build.classes}"></fileset>
		</copy>
		<copy todir="${build.war.lib}">
			<fileset dir="${lib.dir}"></fileset>
		</copy>
		<copy todir="${build.war}">
			<fileset dir="./WebRoot" includes="**/*" excludes="WEB-INF/*"></fileset>
		</copy>
		<war destfile="${build.dir}/KSCMonitor.war" webxml="${build.war}/WEB-INF/web.xml">
			<fileset dir="${build.war}" />
			<lib dir="${build.war.lib}" />
			<classes dir="${build.war.classes}" />
		</war>
	</target>
</project>


makefile 模板- 子模块:

####################64Bit Mode####################
ifeq ($(shell uname -m),x86_64)
CC=gcc
CXX=g++
ifeq ($(coverage), yes)
CXXFLAGS=-g \
  -pipe \
  -W \
  -Wall \
  -coverage \
  -fPIC
COV=-lgcov
else
CXXFLAGS=-g \
  -pipe \
  -W \
  -Wall \
  -fPIC
COV=
endif
CPPFLAGS=-D_GNU_SOURCE \
  -D_USE_PBRPC \
  -D_DEBUG \
  -D__STDC_LIMIT_MACROS \
  -D__VERSION_ID__=\"1.0.0.0\" \
  -D__BUILD_HOST__=\"`whoami`@`hostname`\" \
  -D__GIT_INFO__=\"not_in_svn_repo\"
INCPATH=-I../
DEP_INCPATH=-I../common/output/include \
  -I../protocol/output/include \
  -I../lib/pandora/output/include \
  -I../third-party/zookeeper-3.4.6/output/include \
  -I../third-party/sofa-pbrpc/output/include \
  -I../third-party/protobuf-2.4.1/output/include \
  -I../third-party/snappy-1.1.1/output/include \
  -I../third-party/zlib-1.1.1/output/include
SRCS := $(wildcard *.cpp)
OBJS := $(patsubst %.cpp, %.o, ${SRCS})
LIBOBJS := $(filter-out main.o , $(OBJS))

.PHONY:all
all:libdataserver.a dataserver
	@echo "[PHENIX:BUILD][Target:'all']"
	@echo "make all done"

.PHONY:ccpclean
ccpclean:
	@echo "[PHENIX:BUILD][Target:'ccpclean']"
	@echo "make ccpclean done"

.PHONY:clean
clean:ccpclean
	@echo "[PHENIX:BUILD][Target:'clean']"
	rm -rf libdataserver.a
	rm -rf ./output/lib/libdataserver.a
	rm -rf dataserver
	rm -rf ./output/bin/dataserver
	rm -rf $(OBJS)
	rm -rf output
	rm -rf *.gcno

.PHONY:dist
dist:
	@echo "[PHENIX:BUILD][Target:'dist']"
	tar czvf output.tar.gz output
	@echo "make dist done"

.PHONY:distclean
distclean:clean
	@echo "[PHENIX:BUILD][Target:'distclean']"
	rm -f output.tar.gz
	@echo "make distclean done"

libdataserver.a:$(LIBOBJS)
	@echo "[PHENIX:BUILD][Target:'libdataserver.a']"
	ar crs libdataserver.a $(LIBOBJS)
	mkdir -p ./output/lib
	cp -f --link libdataserver.a ./output/lib

dataserver:$(OBJS)
	@echo "[PHENIX:BUILD][Target:'dataserver']"
	$(CXX) $(OBJS) -Xlinker "-(" \
  ../protocol/output/lib/libprotocol.a \
  ../common/output/lib/libcommon.a \
  ../lib/pandora/output/lib/libpandora.a \
  ../third-party/protobuf-2.4.1/output/lib/libprotobuf-lite.a \
  ../third-party/protobuf-2.4.1/output/lib/libprotobuf.a \
  ../third-party/protobuf-2.4.1/output/lib/libprotoc.a \
  ../third-party/snappy-1.1.1/output/lib/libsnappy.a \
  ../third-party/zlib-1.2.8/output/lib/libz.a \
  ../third-party/sofa-pbrpc/output/lib/libsofa-pbrpc.a \
  ../third-party/zookeeper-3.4.6/output/lib/libzookeeper_mt.a\
  -lcrypto \
  -lpthread \
  -lrt ${COV} \
  ../third-party/gperftools-2.1/output/lib/libprofiler.a \
  ../third-party/gperftools-2.1/output/lib/libtcmalloc_minimal.a\
  -Xlinker "-)" -o dataserver
	mkdir -p ./output/bin
	cp -f --link dataserver ./output/bin

%.o : %.cpp
	@echo "[PHENIX:BUILD][Target:'dataserver/$@']"
	$(CXX) -c $(INCPATH) $(DEP_INCPATH) $(CPPFLAGS) $(CXXFLAGS)  -o $@ $<

endif #ifeq ($(shell uname -m),x86_64)

makefile  模板-All:

export ROOT := $(shell pwd)
SUB_DIRS := ${ROOT}/protocol ${ROOT}/common ${ROOT}/nameserver ${ROOT}/dataserver
PROTOCOL_DIR := ${ROOT}/protocol
COMMON_DIR := ${ROOT}/common
DATASERVER_DIR := ${ROOT}/dataserver
NAMESERVER_DIR := ${ROOT}/nameserver
PB_DIR=${ROOT}/third-party/protobuf-2.4.1/output/

.PHONY:all
all:protocol common nameserver dataserver
	@echo "[PHENIX:BUILD][Target:'all']"
	@echo "make all done"

.PHONY:protocol
protocol:
	@echo "[PHENIX:BUILD][Target:'protocol']"
	@${PB_DIR}/bin/protoc -I=${PROTOCOL_DIR} --cpp_out=${PROTOCOL_DIR} ${PROTOCOL_DIR}/common.proto
	@${PB_DIR}/bin/protoc -I=${PROTOCOL_DIR} --java_out=${PROTOCOL_DIR} ${PROTOCOL_DIR}/common.proto
	@${PB_DIR}/bin/protoc -I=${PROTOCOL_DIR} --cpp_out=${PROTOCOL_DIR} ${PROTOCOL_DIR}/name_server.proto
	@${PB_DIR}/bin/protoc -I=${PROTOCOL_DIR} --java_out=${PROTOCOL_DIR} ${PROTOCOL_DIR}/name_server.proto
	@${PB_DIR}/bin/protoc -I=${PROTOCOL_DIR} --cpp_out=${PROTOCOL_DIR} ${PROTOCOL_DIR}/data_server.proto
	@${PB_DIR}/bin/protoc -I=${PROTOCOL_DIR} --java_out=${PROTOCOL_DIR} ${PROTOCOL_DIR}/data_server.proto
	@${PB_DIR}/bin/protoc --proto_path=${PB_DIR}/include -I=${PROTOCOL_DIR} --java_out=${PROTOCOL_DIR} ${PROTOCOL_DIR}/client.proto
	${MAKE} -C ${ROOT}/protocol

.PHONY:common
common:
	@echo "[PHENIX:BUILD][Target:'common']"
	${MAKE} -C ${COMMON_DIR}

.PHONY:nameserver
nameserver:protocol common
	@echo "[PHENIX:BUILD][Target:'nameserver']"
	${MAKE} -C ${NAMESERVER_DIR}

.PHONY:dataserver
dataserver:protocol common
	@echo "[PHENIX:BUILD][Target:'dataserver']"
	${MAKE} -C ${DATASERVER_DIR}

.PHONY:test
test:common_test nameserver_test dataserver_test
	@echo "[PHENIX:BUILD][Target:'test']"
	@echo "make test done"

common_test:protocol common
	@echo "[PHENIX:BUILD][Target:'common_test']"
	${MAKE} -C ${COMMON_DIR}/test

nameserver_test:protocol common nameserver
	@echo "[PHENIX:BUILD][Target:'nameserver_test']"
	${MAKE} -C ${NAMESERVER_DIR}/test

dataserver_test:protocol common dataserver
	@echo "[PHENIX:BUILD][Target:'dataserver_test']"
	${MAKE} -C ${DATASERVER_DRIR}/test


.PHONY:clean
clean:
	@echo "[PHENIX:BUILD][Target:'clean']"
	${MAKE} -C ${PROTOCOL_DIR} clean
	${MAKE} -C ${COMMON_DIR} clean
	${MAKE} -C ${NAMESERVER_DIR} clean
	${MAKE} -C ${DATASERVER_DIR} clean
	${MAKE} -C ${COMMON_DIR}/test clean
	${MAKE} -C ${NAMESERVER_DIR}/test clean
	${MAKE} -C ${DATASERVER_DIR}/test clean


程序员的20个瓶颈工程实践

翻译内容转自:http://blog.csdn.net/maray/article/details/8351823

* Database (数据库)

  1. 数据规模超出了最大内存限制 —–服务器采购规划、考虑mmap映射、或索引机制实现。
  2. 大查询和小查询 —- 
  3. 写写冲突 —- cas 原子化,版本号实现
  4. 大表join超占内存 —–

* Virtualization (虚拟化)
  1. 共享磁盘,抢磁道,磁头各种抖 —- 设计好线程模型,最好单线程单磁头,现代机械硬盘一般多磁头
  2. 网络IO波动 —  预估好QPS和测试防护,大文件吞吐分片处理等等

* programming(编程)
  1. 线程:死锁、相对于事件驱动来说过于重量级、调试、线程数与性能比非线性
  2. 事件驱动编程:回调的复杂性、函数调用中如何保存状态(how-to-store-state-in-function-calls)
  3. 缺少profile工具、缺少trace工具、缺少日志工具 —— gperftool 、gtest、cplusplus log
  4. 单点故障、横向不可扩展 ——— zookeeper 
  5. 有状态的应用 ——– 状态机map预加载,redis 会话管理
  6. 搓设计:一台机器上能跑,几个用户也能跑,几个月后,几年后,尼玛,发现扛不住了,整个架构需要重写。———-持续优化
  7. 算法复杂度 
  8. 依赖于诸如DNS查找等比较搞人的外部组件(Dependent services like DNS lookups and whatever else you may block on.)
  9. 栈空间 —- 加内存、控制栈空间,使用轻量的线程、纤程,比如golang 、erlang 


* Disk (磁盘)
  1. 本地磁盘访问 ——- 使用优化的本地api ,比如sendfile mmap 等
  2. 随机磁盘IO ——-  使用合适的文件系统 ,根据场景 选择好譬如xfs 或ext4 等文件系统,增加访问文件的并发能力。
  3. 磁盘碎片 —– 小文件凑大block 组织,比如object storerage file system
  4. 当写入的数据块大于SSD块大小时SSD性能下降 —- 最好数据分片,凑整。


* OS (操作系统)
  1. Fsync flushing,Linux缓冲区耗尽(linux buffer cache filling up) —- 控制好fsync 时机和pagecache flush的时间。
  2. TCP缓冲区过小 —- 调整 sysctl.conf  配置
  3. 文件描述符数限制 —– 预设值ulimit , network fd reused
  4. 电源管理(Power budget) —– UPS


* Caching (缓存)
  1. 不使用memcached  ——  那就是用redis了,或者本服务自己实现。
  2. HTTP中,header,etags,不压缩(headers, etags, not gzipping)
  3. 没有充分使用浏览器缓存功能 –比如一些个缩略图,Cookie 
  4. 字节码缓存(如PHP)—– 
  5. L1/L2缓存. 这是个很大的瓶颈. 把频繁使用的数据保持在L1/L2中. 设计到的方面很多:网络数据压缩后再发送,基于列压缩的DB中不解压直接计算等等。有TLB友好的算法。最重要的是牢固掌握以下基础知识:多核CPU、L1/L2,共享L3,NUMA内存,CPU、内存之间的数据传输带宽延迟,磁盘页缓存,脏页,TCP从CPU到DRAM到网卡的流程。


* CPU
  1. CPU负载  — 检查软硬中断情况
  2. 上下文切换。一个核上线程数过多,linux调度器对应用不友好,系统调用过多— cpu亲缘性设计,top 检测
  3. IO等待->所有CPU都等起 
  4. CPU缓存。(Caching data is a fine grained process (In Java think volatile for instance), in order to find the right balance between having multiple instances with different values for data and heavy synchronization to keep the cached data consistent.)—– 读写弱一致性问题
  5. 背板总线的吞吐能力 — HBA \SCSI\RAID 卡等


* Network (网络)
  1.  网卡的最大输出带宽,IRQ达到饱和状态,软件中断占用了100%的CPU ——- 网卡设备故障,网络吞吐过大,使用 atop检查
  2. DNS查找  
  3. 丢包 —- 服务器问题,交换机buffer 溢出
  4. 网络路由瞎指挥  — 环路、隔离不当
  5. 网络磁盘访问 
  6. 共享SAN(Storage Area Network)
  7  服务器失败 -> 服务器无响应


* Process (过程)
  1. 测试时间 — 基本是代码编写时间的1.5倍
  2. 开发时间 — 团队能力评估、培训等
  3. 团队规模 — 3-5 是最佳团队
  4. 预算 — 团队建设、差旅、图文、加班等
  5. 码债(不良代码带来的维护成本)


* Memory (内存)
  1. 内存耗尽 -> 杀进程,swap —-做好设计预估和模拟测试,尽早发现内存泄露和内存喷井
  2. 内存不足导致的磁盘抖动 —- 做好设计预估和模拟测试,尽早发现内存泄露
  3. 内存库的开销 — java 使用LinkedHashMap 实现LRU 对象池,c或c++ 尽量尽量是gperftool
  4. 内存碎片 —-Java 的时候你需要用到jstat 、jstack、MemoryAnalyzer插件、jmap ,C或c++ 尽量使用tcmalloc 避免arena


业务计数 日志 数据分析

    在设计实现后台服务时,为了方便以后对一些业务日志进行数据分析,我们需要对后台服务的日志打印定规范,同时需要对业务操作进行计数。

后台服务常使用atomic变量+report thread 实现。每个统计时间粒度做一次统计,打印日志后即flash清除重新统计。

    临时或简单的数据处理可以使用shell、awk等命令工具实现。

    长期、大数据需要建数据仓库,并定时拉取到hadoop或 RDB 中。

    可视化可采用web + highchart 技术实现前端显示。

分布式系统常用名词

replicas 复制,动词

replication 副本,名词

master 描述服务级别的主

slave 描述服务级别的备

shallow 影子

standby 站在旁边,准备行动,替换上来。

primary 比如在object storeage中描述主block

seconds 比如在object storeage中描述副block

part 比如EC编码后的part

companion  伙伴

compact  压紧,比如清理已标记删除的object文件

Heatbeat 心跳

fail over 失效转移,比如有slave备份服务

fail restart 失效拉起,比如某个服务crash挂了后,依然能拉起。

fail fast 快速失败

fault-tolerant  失效容忍

Auto-Degrade 自动降级

常用shell脚本笔记

数组处理:

declare -a sha
> com.log
while read line
do
    sha=($line)
    blockid=${sha[0]}
    for i in {1..3}
    do
    wget -O  ${sha[0]} ${sha[1]}"__"$i
    size=$(ls -l ${sha[0]}  | awk '{print $5}')
    if [ "$size" == "0" ]; then
        rm -f $blockid
        continue
    else
        echo ${sha[0]}" "${sha[1]}"__"$i >> com.log
        sha1=$(sha1sum $blockid | awk '{print $1}')
         wget -O - --timeout=100  "http://172.16.100.197:9001/upload/?filename=$blockid&sha1=${sha1}&size=${size}" --post-file=./$blockid
         if [ $? -eq 0 ]; then
         printf "end $line OK\n"
         rm -f ./$blockid
         else
         printf "end $line FAIL\n"
         rm -f ./$blockid
         fi
        break
    fi
    done

done < $1

远端SSH执行:

#!/usr/bin/expect  --


if { [llength $argv] != 2} {
	puts "usage: $argv0 ip \"command \[params\]\""
	exit 1
}


set maxRetry 1
for {set retryNum 0} {$retryNum<$maxRetry} {incr retryNum} {

spawn  /usr/bin/ssh [lindex $argv 0] [lindex $argv 1]

set timeout 80
expect {


 
	"yes/no)?" {
  
		send "yes\r"

		expect eof

		break

	}
  
	timeout {continue}
	eof {continue}

}
}

scp快速执行:

#!/usr/bin/expect --

puts "pcp.sh..."
if { [llength $argv] < 2} { 

    puts "usage: $argv0 ip filename"  
    exit 1
}
set success 0

set maxRetry 5
for {set retryNum 0} {$retryNum<$maxRetry} {incr retryNum} {

    spawn  /usr/bin/scp -r [lindex $argv 1] [lindex $argv 0]:/home/raojianlong

    set timeout 600
    expect { 

        "password:" {    	
            puts "input passwd"
            send "[lindex $argv 3]\r"	
            set timeout 600
            puts "try $retryNum"
            expect { 
                timeout {continue}
                eof {
                    set success 1
                    break
                }
            }
        }

        "yes/no)?" {
            puts "input yes"
            send "yes\r"
            expect "password:" {
                send "[lindex $argv 3]\r"
                set timeout 600
                expect { 
                    timeout {continue}
                    eof {
                        set success 1
                        break
                    }
                }
            }
        }

        timeout {continue}
        eof {
            set success 1
            break
        }
    }
}

puts "pcp sucess..."
if { $success==0 } {
    exit 1
}

安装脚本范式:

。。。

fun_main()
{
    start_id=${2%%-*}
    end_id=${2##*-}
    printf $1" from %s to %s ,confirm Y/N?:" $start_id $end_id
    read answer
    if [ "$answer" != "Y" ];then
        exit 1
    fi
    case "$1" in
        install)
        install $start_id $end_id
        ;;
        start)
        start $start_id $end_id
        ;;
        stop)
        stop $start_id $end_id
        ;;
        clear)
        clear $start_id $end_id
        ;;
    esac


}