Skip to main content

Posts

Golang http server performance tuning practice (Golang HTTP服务器性能调优实践)

  Golang 1.8后本身自带了pprof的这个神器,可以帮助我们很方便的对服务做一个比较全面的profile。对于一个Golang的程序,可以从多个方面进行profile,比如memory和CPU两个最基本的指标,也是我们最关注的,同时对特有的goroutine也有运行状况profile。关于golang profiling本身就不做过多的说明,可以从 官方博客 中了解到详细的过程。   Profile的环境 Ubuntu 14.04.4 LTS (GNU/Linux 3.19.0-25-generic x86_64) go version go1.9.2 linux/amd64  profile的为一个elassticsearch数据导入接口,承担接受上游数据,根据元数据信息写入相应的es索引中。目前的状况是平均每秒是1.3Million的Doc数量。   在增加了profile后,从CPU层面发现几个问题。 runtime mallocgc 占用了17.96%的CPU。 SVG部分图如下 通过SVG图,可以看到调用链为: ioutil.ReadAll -> buffer.ReadFrom -> makeSlice -> malloc.go  然后进入ReadAll的源码。 readAll()方法 func readAll(r io.Reader, capacity int64) (b []byte, err error) { buf := bytes . NewBuffer ( make ([] byte , 0 , capacity )) // If the buffer overflows, we will get bytes.ErrTooLarge. // Return that as an error. Any other panic remains.   defer func() { e := recover () if e == nil { return } if panicErr , ok := e .( error ) ; ok && p...

Operating System- Process and Thread Review

回顾总结 process and thread process是操作系统调度的基本单位,一个程序可以理解为一个进程。 thread是process的子process,是process调度的基本单位。   从调度角度理解process和thread   我们知道操作系统调度的时候是以process为单位的,即当我们的程序是单thread的process时,那在这个process获得cpu的时间片时,这个thread能够获得全部的这个时间片。在内核中,我们维护着一个process的table,来记录每个process的基本信息,根据不同的调度方式来使用这个信息或者不使用。   当一个process拥有多个thread时,如何调度thread呢?  当thread为内核态thread时。  当thread为用户态thread时。 混合实现不做讨论   两种情况则有不同的调度方式。当为内核态的thread时,即此时的thread可以称之为轻量级的process,这个时候内核来维护一个thread table和process table相似。同时操作系统来调度thread,就像调度process一样。当为用户态的线程时,那么操作系统感受不到多个thread的存在,因为此时操作系统调度的对象是process,一个process中有多少个thread他不关心,所以当一个process得到CPU时间片后,他会自己来调度thread。   了解他们两个基本工作方式后,应该清楚这两种线程的主要区别:调度者是谁?各个的优缺点是什么?在JAVA中使用的哪种thread?Golang中goroutine是如何对应到我们操作系统的调度单位上去的? 调度者。 内核态的thread:内核。 用户态的thread:process 内核态thread的优点:在单个thread进行syscall而阻塞 时(一个线程不可以即运行代码,又能进行syscall),操作系统可以切换到同process中或者其他process下一个可以执行的thread,而不必阻塞,然而用户态的thread在进行syscall时,整个process下的thread都会阻塞。用户态的thread优点是在进行thread切换时...

Sumary of traversal of binary tree. 二叉树遍历总结

Traversal of binary tree is very import when sloving the binary tree problem. Today I will try starting to record the traversal way I met in leetcode or somewhere else. Continuing update... 1. LevelOrder Traversal using Queue. This is a very common traversal case. We use it to record the width of the current level. Plus: Actually is a bfs search in a graph when you replace the left and right node to adjs of a vertex. public class Example { public List<Integer> levelOrderTraversal(TreeNode root) { if (root == null ) return null ; List<Integer> result = new ArrayList<>(); Queue<TreeNode> queue = new LinkedList<>(); queue.offer(root); while (!queue.isEmpty()) { int size = queue.size(); for ( int i = 0 ; i < size; i++) { TreeNode tmp = queue.poll(); System. out .println(tmp. val ); result.add(tmp. val ); if (tmp. left !...

消息系统设计要点

操作系统 消息传递作为进程间通信的重要一种,他提供了网络间进程通信的方式。但是相比于管程和信号量等,他具有不稳定性。 需要考的问题简单来说有这么几点 消息传递的不可靠性解决。在网络间传递时,A到B已经发送了消息,B可能没有收到,A要有一种机制可以知道B已经收到了消息。因此,B需要发送一个ACknowledge给A,来保证他已经收到。 消息传递的重复性。在A重复的发送了数据后,如果经过一定的时间后,A没有收到ACK,所以又重复发了一次相同的message,但是经过一段时间后,B收到了两个相同消息,如何进行区分?可以在发送的消息中加入连续的序列来表达不同的消息。 还有许多其他问题,这里直说两个比较普遍的问题。

Elasticsearch error when the field exceed limit 32kb

When we post data that the field exceed the limit, elasticsearch will reject the data which error: {"error":{"root_cause":[{"type":"remote_transport_exception","reason":"[cs19-2][10.200.20.39:9301][indices:data/write/index]"}],"type":"illegal_argument_exception","reason":"Document contains at least one immense term in field=\"field1\" (whose UTF8 encoding is longer than the max length 32766), all of which were skipped.  Please correct the analyzer to not produce such terms.  The prefix of the first immense term is You can handle this: 1. you can udpate the mapping part at any time PUT INDEXNAME/_mapping/TYPENAME { "properties" : { "logInfo" : { "type" : "string" , "analyzer" : "keyword" , "ignore_above" : 32766 } } } ignore_above means that we will only keep 32766 bytes 2...

Java ClassLoader 学习反馈

Classloader是Java运行时核心机制之一,它解决了我们的.class文件如何被jvm加载的问题。也就是我们的写的源码.java文件被编译成.class字节码后,如何被jvm加载解释。 Java在广义上有三种classloader BootstrapClassLoader 是JVM级别的classloader,使用c/c++来写的。详细解释如何来加载一个bootstrap级别的class文件,哪些class文件是bootstrapclassloader来加载的。 ExtClassLoader  是ExtensionClassLoader,他是AppClassLoader的 ‘父类’,这个父类不是指AppClassLoader extends ExtClassLoader,而是指ExtClassLoader来创建了AppClassloader,后面源码部分可以解释这个关系。 AppClassLoader 这是一般我们自己写的class的classloader,他加载了我们自己写的class,而且同时如果我们有自定义的classloader,那么他也是custom class loader的parent class loader. 他们的加载顺序也是从上往下,即 1->2 ->3。   到这里可能会产生疑问,他们加载的class有何不同?  AppClassLoader是上面说的,他会加载我们自己定义的class,即我们workspace的classpath下的class ExtClassLoader则是加载我们Jdk lib/ext 下的class BootstrapClassLoader是加载 rt.jar、resources.jar、charsets.jar和class等。  那么他们是如何找到lib下这些class文件呢? 答案是通过环境变量中的一些变量,而这些变量的定义也是通过我们设置的JAVA HOME等来取得。 源码中有这么两个地方解释了这个地方。 ==》 private static String bootClassPath = System.getProperty( "sun.boot.class.path" ); ==》...

并发读写外部依赖

在我们以task为粒度的分布式系统中,需要对数据做checkpoint,以保证task在重启的时候内存中未被消费完的数据可以保存到文件系统中以防止丢失。 在第一个版本中,我们的task默认使用了task的名字作为任务的ID,同时在做checkpoint时使用diskQueue也是使用相同的方式来生成。直到我们碰到一个需要更新task配置的需求后产生了问题。 为了解决任务更新的问题,我们task的做了使用时间戳作为版本管理,简单就是说:在更新一个任务的配置后,version会替换,这时候会生成一个新的task(旧的任务在消费完数据后会被cleanTask的任务给删除掉)来继续。 在过渡期的时候,即新旧task同时在运行的时候,我们做了重启操作,此时两个任务同时执行了checkpoint操作。而bug的原因是在于,task的ID和diskQueue的ID是不相同的!也就是说两个任务虽然new出两个diskQ,但是两个diskQ会同时向一个文件中写数据,这就导致了文件的损坏。 这里的反思是:对于一个Task任务,如果需要和外部的文件或者其他资源交互时,一定需要保证外部的依赖对于每一个task任务都是唯一的。这里以fileSystem为例子,一个task保证对应的是一个file or dir。两种方式:1.使用一个xxx.lock的方式,一个系统如果已经决定对该资源做write/read操作时,就建立一个lock。该系统内部的进程想要同时做操作时可以避免因为上述简单的ID BUG而造成的问题。同时其他系统可以辨识到该文件可能被其他应用程序使用中,他可以针对这种情况做一些预期内的操作。 Golang中突然想起一种方案,对于需要写文件或者其他资源访问时,使用一个 channel 来做串行处理。比如当多个不可预知的任务可能同时做一个写入文件操作时,任务可以将此次操作的metadata以一种特定的数据格式交给上层系统(我们定义的channel)来统一处理,因为channel的并发写入是绝对安全的。当然如果是需要对多个文件做写入操作时,我们可以使用这样一种方式: 一个channel对应下游有多个channel(而不是file对象),每个channel都定义一个唯一ID,作为suffix。每个channel写完的文件都有ID,比如A,B,C三个channel现在...

Scrapy ERROR :ImportError: Error loading object 'scrapy.telnet.TelnetConsole': No module named conch

原文: https://stackoverflow.com/questions/17263509/error-while-using-scrapy-scrapy-telnet-telnetconsole-no-module-named-conch/17264705#17264705 On Ubuntu, you should avoid using  easy_install  wherever you can. Instead, you should be using  apt-get ,  aptitude , "Ubuntu Software Center", or another of the distribution-provided tools. For example, this single command is all you need to install scrapy - along with every one of its dependencies that is not already installed: $ sudo apt - get install python - scrapy easy_install  is not nearly as good at installing things as  apt-get . Chances are the reason you can't get it to work is that it didn't quite install things sensibly, particularly with respect to what was already installed on the system. Sadly, it also leaves no record of what it did, so uninstallation is difficult or impossible. You may now have a big mess on your system that prevents proper installations from working as well (or maybe not...

linux下批处理

linux使用中发现我们可能开机要启动一系列程序. 所以写个批处理d文件很方便: 首先 到你用户d目录下: vim startup.sh #your dir cd /home/jason/Downloads/openkeeper-cli-1.1-x86_64 #your command as you do ok cd /home/jason/Downloads/goagent-goagent-52e1f7b/local/ python proxy.py ~                           Then chmod 777 startup.sh

Master-Worker模式 Python(转载)

转载来自: http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/001386832973658c780d8bfa4c6406f83b2b3097aed5df6000 分布式进程 810次阅读 在Thread和Process中,应当优选Process,因为Process更稳定,而且,Process可以分布到多台机器上,而Thread最多只能分布到同一台机器的多个CPU上。 Python的 multiprocessing 模块不但支持多进程,其中 managers 子模块还支持把多进程分布到多台机器上。一个服务进程可以作为调度者,将任务分布到其他多个进程中,依靠网络通信。由于 managers 模块封装很好,不必了解网络通信的细节,就可以很容易地编写分布式多进程程序。 举个例子:如果我们已经有一个通过 Queue 通信的多进程程序在同一台机器上运行,现在,由于处理任务的进程任务繁重,希望把发送任务的进程和处理任务的进程分布到两台机器上。怎么用分布式进程实现? 原有的 Queue 可以继续使用,但是,通过 managers 模块把 Queue 通过网络暴露出去,就可以让其他机器的进程访问 Queue 了。 我们先看服务进程,服务进程负责启动 Queue ,把 Queue 注册到网络上,然后往 Queue 里面写入任务: # taskmanager.py import random, time, Queue from multiprocessing.managers import BaseManager # 发送任务的队列: task_queue = Queue.Queue() # 接收结果的队列: result_queue = Queue.Queue() # 从BaseManager继承的QueueManager: class QueueManager(BaseManager): pass # 把两个Queue都注册到网络上, callable参数关联了Queue对象: QueueManager.register('get_task_queue', callable=lambda: tas...

为Tomcat配置Nginx

Nginx配置 server { listen mysite.com :80; #如:listen 80 server_name mysite.com; #如:localhost root /path/to/tomcat/webapps/mysite/ ; location / { proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Server $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://127.0.0.1: 8082 /; 这个地方的端口是Tomcat的端口号,如果你没有更改过tomcat的server.xml 那这个就是8080 } } Tomcat配置: 见之前一篇: http://sjasonzhang.blogspot.jp/2014/11/blog-post.html

Nginx install from source on cenos 6.5

ERROR: /configure: error: the HTTP rewrite module requires the PCRE library. You can either disable the module by using --without-http_rewrite_module option, or install the PCRE library into the system, or build the PCRE library statically from the source with nginx by using --with-pcre=<path> option. 安装依赖库 yum install -y httpd-devel pcre perl pcre-devel zlib zlib-devel GeoIP GeoIP-devel

ftp服务器返回的文件列表解析

EG: drwx------   3 user group            0 Dec  2 12:09 Java_server_proxy drwx------   3 user group            0 Dec  1 12:42 agent drwx------   3 user group            0 Nov 26 09:21 download drwx------   3 user group            0 Nov 27 07:18 gae-server drwx------   3 user group            0 Nov 28 16:11 openssl drwx------   3 user group            0 Nov 26 08:09 python -rw-------   1 user group        15672 Dec  2 12:00 Java_server_proxy.rar -rw-------   1 user group        18650 Dec  2 12:04 Java_server_proxy.zip #将空格规范后的文件列表 def parse_file_list(parsed_list,file_quantity):     all_file_name=""     all_file_create_data=""     all_file_size = ""     all_...

Python 使用socket实现ftp 客服端

之前先了解ftp协议,然后解释代码 连接到ftp服务器,得到一个socket(这是一个连接到ftp命令端口socket) 发送必要request 第一步 Connect到服务器后,ftp_socket.recv(1024) 到服务器的欢迎消息(1 中的socket),不要问为什么,ftp协议规定的,应该是。 *注意的是,后面ftp_socket每一次的请求后,都要recv一次,不管你是否全部接受到了都要recv一次,不然可能后面接受不到一些消息。个人觉着这可能是ftp协议的规定:每一次request,都会给client一个response。如果 client没有接受这个response,那么下次的request不会被服务器接受,所以client的recv就会卡住! 第二步就像代码中 直到 #LIST 都是用的命令端口。 而使用数据端口时,就是用命令端口   ftp_socket.send("PASV \r\n")     new_port = ftp_socket.recv(1024)      使用命令 PASV 请求一个动态的数据端口。 解释 我理解的动态数据端口: 即你每一次请求到一个数据端口后,你只能使用一次。比如: [ INFO] 2014-11-29 22:25:44,682 [admin] [127.0.0.1] SENT: 227 Entering Passive Mode (127,0,0,1,204,82)    这是ftp服务器端发送的请求(apache ftpserver),明显括号中是你的ip(我的是本机),然后两个数字。通过查询,你要请求的数据端口:(a,b,c,d,x,y)  new_port  = x*250+y 剩下的部分就很简单了。在代码中再有点解释(后面附server端log) 最后还应该用发送一个quit命令,告诉server 我的请求完毕了。这里忘了。 一点补充:看到server端log可以发现,服务器每一次的SEND  我们都应该recv一次 #download a folder's files  import socket class ParseUrl()...

学习服务器配置之路~~

第一个常见的小问题:MySQL安装 os : fedora 20 mysql: mysql-server(5.5) 所有假设你的系统是没有经过特殊配置的。 1: yum install mysql-server 2: mysql 报错:socket连接不上 3: service mysqld start   注意这步是 mysqld 不是mysql 这样就解决。网上的方法好像有点麻烦。 第二个小问题:解压一些文件(.tar.gz)时报错 http://itsfoss.com/how-solve-stdin-gzip-format/ 上面介绍的很清楚,总之要先确认你下载的文件类型。 第三个小问题。配置tomcat服务器 主要问题是比如我的域名是 cqupt.me 而你tomcat服务器的项目在/webapps/{your projectname} 这时你很蛋疼的要 cqupt.me:8080/{your projectname}/index.html。 如果要cqupt.me就可以完成。这样配置: 都是在tomcat下/conf/server.xml 第一步端口。简单 不废话 第二部。 <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true" xmlValidation="false" xmlNamespaceAware="false"> </Host> 在标签中间插入: <Context path=""  docBase="xbwl"  debug="0" reloadable="true"/> docBase="xbwl" xbwl 即为指定的项目。即({your projectname}_ 完整如下: <Host name="localhost" appBase="webapps" ...

基于Python的cs实例

Server 端: ... import socket s = socket.socket() host = socket.gethostname() port = 222; s.bind((host,port)) s.listen(5) while True:     c,addr = s.accept()     print('Got connection',addr)     c.send('thank you for connection'.encode('utf-8'))     c.close() Client端: import socket s = socket.socket() host = socket.gethostname() port = 222 s.connect((host,port)) print(s.recv(1024)) s.close 中间出现过TypeError: 'str' does not support the buffer interface stackoverflow中解释是Python3.X的str需要转换为utf-8才能识别,所以才c.send中添加了转换。 连接: http://stackoverflow.com/questions/5471158/typeerror-str-does-not-support-the-buffer-interface

Java字符串处理的两个工具类

在处理SQL语句时发现的两个类: 一:StringTokenizer DOC: http://docs.oracle.com/javase/7/docs/api/java/util/StringTokenizer.html Console输出:2 但是如果 讲SQL语句改为:"id =2" 即把=后面的空格删掉话 则输出下一个'and'单词。 所以StringTokenizer是通过String.split("\\s")完成的分割。 二:BreakIterator DOC(cn): http://download.oracle.com/technetwork/java/javase/6/docs/zh/api/java/text/BreakIterator.html console: 可以看出BreakIterator是分割了每个字符,包括空格

数据库分表的意义与数据库中单表的大小控制

转载来自:http://www.woqutech.com/?p=807 请问:MySQL库中单表的大小尽可能控制在多大?采取这种表大小限制的策略的原因是什么?一个MySQL服务器实例中,表的数量有限制吗?单个MySQL服务器实例中,表的大小的总和有限制吗?如果有,考虑的原因是什么?单台PC SERVER上建多个MySQL服务器实例,一般的实例数是多少?是基于什么样的考虑原因? MySQL数据库分库后,我们的建议单表大小控制在10G以下。限制分拆以后的表的大小有几个好处: 1、表比较小的话,DDL操作更快。由于MySQL部分DDL操作需要锁表,所以表越小,锁表的时间就越短。 2、表越小,数据查询访问的速度越快。MySQL是B树结构,表越小,树的分层越少,IO也会比较少。 3、表越小,最终扩容到MySQL的实例数越多。将数据拆分得越散,数据分布越均匀,扩容的话,能够用更多的服务器来承担并发压力。 建议MySQL服务器的配置:2路6核cpu、192G内存,配有8块SSD或者PCIe Flash卡。这样一台服务器上一般是部署4-8个数据库实例, 这个要根据数据库硬件最大可承载的的CPU,IO(包括IO性能和IO容量),网络容量来评估。 比如双十一的时候,8个实例的flash卡MySQL数据库物理主机,就已经把网络的千兆网卡打满了。 所以需要进行充分的测试,检查在充分的压力下,数据库的能力会先遇到什么瓶颈。表的大小总和并没有限制,如果你是一个正常情况下访问量非常少的表,它的限制就可能在于单机MySQL磁盘或者flash卡的容量大小了。

Mysql varchar(255) 可以存放多少个汉字实验

这是一个有255个 “我”的字符串插入到 一个 设置为varchar(255)的实例代码 StringBuffer sb = new StringBuffer(); for(int i=0;i<256;i++){ sb.append("我"); } PreparedStatement pstmt = conn_2.prepareStatement("insert into test_varchar values(?)"); pstmt.setString(1, sb.toString()); pstmt.execute(); 实验结果:   MySQL 数据库编码格式为 utf-8的情况下,一个varchar(255)就最多可以接受255个汉字。当将字符串增加到256时,出现  com.mysql.jdbc.MysqlDataTruncation: Data truncation: Data too long for column 'name' at row 1