niyue

Archive for the ‘programming’ Category

用ChatGPT做paper prototyping

In programming on 1月 15, 2023 at 9:25 上午

ChatGPT是一个很有意思的技术,我最近看到一些人推荐说可以把chatGPT和软件开发流程做一些结合的想法,于是我也做了一些尝试。

我昨天把Kafka KIP-848整个设计文档都丢给ChatGPT读了一遍,然后开始问它问题,很多术语和可能的实现方向它都能立刻给出答案,结合自己的判断其实能很快深入实现层面。感觉和ChatGPT非常适合用来做快速的不用写代码只是方向探索性的原型设计和验证。

一次对话

比如我和它讨论文档里面的”Reconciliation Loops”,它能告诉我zookeeper/cassandra/etcd都用到了

当我有进一步实现层面的想法的时候,它也能快速告诉我可能的方案和问题

甚至当我有更复杂的改进想法的时候,它也能够应答告诉我这里可能碰到的一些问题

因为它的无所不知,所以你可以非常快的去提出一些可能的其他的设计和实现方案,比如我考虑是不是可以用关系数据库而不是etcd去实现这里的功能,它也能应答:

它甚至提出了使用SQLite的WAL mode而不是使用它之前说的触发器来解决这个问题,可以说是点子非常多了,这个对于原型设计过程中去找寻可能的思路是非常有帮助的。你甚至可以问它做出这种设计的原因是什么:

必要的时候也可以使用一些事实去验证它是不是在一本正经的胡说八道:

总结

结合ChatGPT的大量信息,我们能快速得到和验证很多开发过程中延伸的想法,只要我们保持自己的判断以及用额外的一些渠道去验证这些想法,其实可以把ChatGPT作为一个很好的快速原型的工具来使用。

disk mount conditioner模拟慢IO存储

In programming on 11月 26, 2022 at 5:13 下午

1. 背景

工作中偶尔会碰到一些系统环境的存储设备IO特别慢,尤其是云上一些存储,一般读取吞吐量在200MB/s,但是我一直使用MacBook作为本地开发的机器,它的磁盘真是飞快,即使是2019年的机器也能达到读取 2000MB/s的吞吐量,所以要想在本地环境下测试一些慢IO的性能测试就不很容易做到。

大概一年前的时候我用Docker里面的--device-read-bps的功能实现了一个基于容器的办法来在macOS下面模拟慢IO的存储设备。--device-read-bps背后使用了Linuxcgroups去做到这一点,不过通过Docker的话用户界面更友好一些。我把代码放在了https://github.com/niyue/slowio,大致的工作原理是:

macOS下应用程序 <==POSIX API==> samba shared volume <==samba==> samba server container in Docker <==cgroup limit==> 磁盘
  1. Docker会启动一个Samba的容器,这一容器受到了指定的读写IOPS以及读写带宽的限制
  2. macOS客户端会把Samba共享出来的卷挂载上来
  3. macOS上的应用访问Samba的共享卷的时候会受到通过Docker指定的读写的IOPS以及带宽的限制
  4. page cache under Docker for Mac’s Linux host needs to be cleared if you want to accurately measure this limit

这么做虽然可以工作,但是对于macOS上面的使用还是太复杂了,不仅得使用Docker,在里面部署Samba,还有一些明显的问题:

  1. 要注意清除Docker for Mac中的page cache,以保证这个限制是正确应用的
  2. Samba本身有自己的瓶颈(虽然一般模拟慢IO的时候不会超过这个瓶颈)
  3. 需要把文件拷贝到容器中去进行验证

2. dmc

我最近才发现macOS下面从High Sierra开始自带了一个叫做dmc (disk mount conditioner)的工具 [2],能够非常容易的做到模拟慢IO的存储,这里介绍一下这个工具的使用。

这个dmc到底是啥呢?按照它的manpage的介绍 [2],它是一个kernel里面内置的服务,通过它能够对特定的挂载点的磁盘IO访问进行降级,从而造成一种假象这个IO访问是在一种更慢的存储设备上进行的。它也能够让挂载点生成自己是一种不同的设备类型,列如SSD类型的磁盘可以被声称为HDD。一般存储设备的访问参数都会根据底层的设备类型而有所不同,这一设置也会对应变更各种参数,例如预读取的设置,磁盘IO的限流等。

它的功能使用其实很简单:

1. dmc list

dmc预置了8种不同的配置,通过dmc list可以列出。它们代表了一些典型的磁盘设备,对于我来说,我只要从中选择一种来使用就足够了。

> dmc list
  0: Faulty 5400 HDD
  1: 5400 HDD
  2: 7200 HDD
  3: Slow SSD
  4: SATA II SSD
  5: SATA III SSD
  6: PCIe 2 SSD
  7: PCIe 3 SSD

2. dmc show

对于每一种预置的设备来说,可以通过dmc show命令来查看它的参数。

❯ dmc show "7200 HDD"
Profile: 7200 HDD
 Type: HDD
 Access time: 17433 us
 Read throughput: 140 MB/s
 Write throughput: 140 MB/s
 I/O Queue Depth: 32
 Max Read Bytes: 33554432
 Max Write Bytes: 33554432
 Max Read Segments: 256
 Max Write Segments: 256

3. dmc start/stop

用户一般创建了一个目录作为挂载点之后,就可以通过dmc start以及dmc stop去设置这个挂载点的行为了。

sudo dmc start /tmp/data "7200 HDD"
sudo dmc stop /tmp/data

4. dmc status

设置完成之后,用户可以通过dmc status去查看某一挂载点的状态。

❯ dmc status /tmp/data
Disk Mount Conditioner: OFF
Profile: Custom
 Type: HDD
 Access time: 17433 us
 Read throughput: 140 MB/s
 Write throughput: 140 MB/s
 I/O Queue Depth: 32
 Max Read Bytes: 1048576
 Max Write Bytes: 1048576
 Max Read Segments: 256
 Max Write Segments: 256

就是这么简单。如果接下来想要验证下这个模拟是不是真的有效,可以通过使用fio [3]等存储测试的工具来验证。

3. 参考

[1] 华为云磁盘类型及性能介绍, https://support.huaweicloud.com/productdesc-evs/zh-cn_topic_0044524691.html

[2] dmc man page, https://manp.gs/mac/1/dmc

[3] fio, https://fio.readthedocs.io

l2tpvpn puppet module for Ubuntu

In programmingubuntu on 11月 10, 2012 at 11:31 下午

之前用Microsoft的MSDN订阅里面附带的Windows Azure的额度建了个Ubuntu的服务器,主要就在上面搭了一个L2TP的VPN服务用来翻墙。SSH tunnel倒是很容易翻墙,但是iPad和iPhone之类的设备没办法直接用SOCKS的代理,所以只好整了这么个VPN来翻墙,Mac上用起来也很方便。

在11月1日凌晨的时候微软忽然发邮件说MSDN带的Windows Azure额度上限到了,微软自动关闭了Windows Azure的服务。我确实是设置了超出额度就自动停止的条件的,所以预期下个月能够自动恢复。到了11月1日中午的时候,收到了额度恢复的通知邮件,开始没太在意,觉得是预期中的事情。不过后来使用VPN的时候发现没法连接上了,再去Windows Azure Portal里面看发现原来创建的两台虚拟机都不存在了,这个完全出乎我的意料,服务停止居然把数据都一下删掉了。刚好又临近十八大,一堆网站都被封了,于是只好考虑重新搭一次VPN。

之前主要是参考「Ubuntu下为Android/iOS搭建L2TP/IPSec VPN代理服务器」搭的VPN,再做一次当然也没啥难的,只是觉得很没意思,最后考虑这次用Puppet来自动化这个过程。以前写过些小的web app,都需要涉及搭一些环境来部署,碰到过好几次由于环境造成的问题,后来看到过Puppet这类的工具感觉很适合用来解决这类问题,这次借这个VPN的搭建顺便学习下。

用下来发现Puppet还是一个不错的产品,文档写的也比较好,我主要就看了Learning Puppet这个文档,之后具体用的时候参考了下Puppet的Type Reference就完成了这个l2tpvpn的Puppet module。前后大致一共花了20个小时,最后其实还没做到开始计划的一条命令行完成整个部署的程度,不过对Puppet有了个大概的了解,同时整个搭建VPN的过程大致简化到了一个十分钟的过程,其中大概还有五分钟是用在等待Windows Azure Portal的操作上面的。

最后剩余的一些自动化工作有些繁琐,也没有什么太大干劲去完成,就简单写了个文档描述了一下,所有的东西都丢到Github上面去了,https://github.com/niyue/l2tpvpn,以后如果要在Amazon EC2或者Windows Azure里面搭这么个环境应该都是非常容易的。这个Puppet module还是很简单的一个module,主要用来学习了。有些服务和文件配置的依赖的顺序什么的没有太仔细推敲,除了client/server的配置,基本也算把使用Puppet的整个流程走了一遍,几个部署的时候需要的参数都自动获取了,基本只要填个VPN的用户名密码就可以了。

重新建虚拟机的同时还顺带用iperf测试了一下家里连接到Windows Azure的东亚和东南亚数据中心的带宽。大概查了一下,东亚的数据中心应该是在香港,东南亚的数据中心是在新加坡,很不科学的手工测试了几次,iperf出来的结果差不太多,连接到两个数据中心里面的虚拟机都是大约600~800kbps的带宽,感觉连到新加坡还略快一些。

总的来说:

  1. 以后可以尽量多的使用Puppet来管理配置,越复杂的配置以及越长期的配置管理收益越大
  2. TODO: 使用Puppet来自动化管理更加复杂的配置文件,Puppet + Augeas, http://projects.puppetlabs.com/projects/1/wiki/Puppet_Augeas。目前的l2tpvpn为了能够达到idempotence,对/etc/ipsec.conf这个文件的修改可能会覆盖旧有的其他的修改,像我这种个人使用就搭一个VPN的情况不会有问题,但是如果更复杂的系统里面可能就会有问题
  3. Vagrant, http://vagrantup.com/, 看起来有点意思,以后有机会可以试试
  4. 比起Amazon EC2的console,Windows Azure Portal的性能真是弱爆了,创建新的虚拟机和添加新的endpoint感觉比Amazon EC2里面的操作都慢了一个数量级
  5. 终于能在十八大期间继续VPN了 🙂

Install mysql driver Ruby gem on Leopard

In macprogrammingruby on 10月 14, 2008 at 11:20 下午

Ruby, Rails and MySQL with Leopard 10.5.2 and XCode 3.0
评论中有一个comment介绍了如何安装在安装了x86_64架构的mysql后,如何在Leopard上安装mysql gem。

Google AppEngine

In ideaprogramming on 4月 15, 2008 at 10:43 上午

申请了Google AppEngine,前天刚得到批准,准备写点小东西看看。AppEngine是很有意思的一个东西,原来一直想写一些server side的应用,可惜一直没有环境来部署,也就一直没有实现。很多想做的东西也都因为没有Web环境来部署觉得用处不大就没有去做。不过现在有了AppEngine这些问题都迎刃而解了。

但是AppEngine只支持Python,开始想找个曲线救国的办法 – 找到一个Python实现的JVM或者Ruby VM,这样就可以在AppEngine上部署Java或者Ruby的应用(假设AppEngine的Python环境可以让这些虚拟机跑起来)。当然如果有Python-based JVM的话,还可以再这之上再跑Ruby的应用(JRuby)或者Groovy和Scala的应用了,想想就是一个很酷的事情。稍微花了些时间,可惜并没有找到这种的虚拟机实现,不知道是原来并没有这种需求还是技术上有什么难度,有PyPy为什么没有RuPy或者JaPy?

So *start learning Python* in this year~

Update:

这个(Compile Ruby to Python)已经很接近我想要找的东西了,可惜是用Ruby写的,如果是用Python写的话,那就应该可以在Google AppEngine的环境中动态的将Ruby编译成Python代码,于是就可以变成一个Ruby运行时了~

http://www.infoq.com/cn/news/2008/04/google-app-engine-simplifies-web

http://www.dougma.com/archives/81

http://ejohn.org/blog/running-java-in-javascript/

http://hotruby.accelart.jp/

web service related pronunciation

In programming on 12月 28, 2007 at 3:23 下午

Web service领域相关的名词术语实在太多,缩写记不清很麻烦,读起来也不知道如何读,今天特地花了些时间搜集了一下这些术语的读音,感觉还挺有意思的:

WSDL
Web Services Description Language, pronounced ‘wiz-dəl’ or spelled out, ‘W-S-D-L’
SOAP
这个最容易, ‘səup’
UDDI
UDDI is NOT pronounced “Uddy”, but as spelt.
jUDDI
pronounced ‘judy’,和上面的不一样:p
WSE
Web Services Enhancements, pronounced ‘wizzy’
JAXWS
pronounced ‘jax-weis’
WSE-WSDL
‘wizzy-wiz-dəl’…

Editing Ruby File in Vim

In programming on 12月 27, 2007 at 10:34 上午

在/usr/share/vim/vim70/filetype.vim(in MacOS X)中找到ruby类型的设置,为其增加不同的后缀,使得*.rb,*.rake等都识别为ruby代码进行语法高亮:

au BufNewFile,BufRead *.rb,*.rake,*.rbw,*.gemspec setf ruby

在.vimrc中设置以下内容,即可使得编辑*.rb和*.erb时tab缩进值为2,但是其他类型的文件仍然为4.

set expandtab ” To insert space characters whenever the tab key is pressed
set tabstop=4 ” To control the number of space characters that will be inserted when the tab key is pressed
set shiftwidth=4 ” To change the number of space characters inserted for indentation
set softtabstop=4 ” makes the spaces feel like real tabs
au BufRead,BufNewFile *.rb set expandtab
au BufRead,BufNewFile *.rb set tabstop=2
au BufRead,BufNewFile *.rb set shiftwidth=2
au BufRead,BufNewFile *.rb set softtabstop=2
au BufRead,BufNewFile *.erb set expandtab
au BufRead,BufNewFile *.erb set tabstop=2
au BufRead,BufNewFile *.erb set shiftwidth=2
au BufRead,BufNewFile *.erb set softtabstop=2

Ruby Guys are Mac Guys

In macprogramming on 11月 13, 2007 at 9:02 下午

See RubyConf 2007 picture. In the third picture, almost all machines are Macbook Pro. Show me the money~

rails file_column plugin使用

In programming on 8月 11, 2007 at 10:14 下午

Rails的file_column插件是一个简单但是功能比较完备的文件上传插件。这一插件已经有很长时间没有更新了(最后一次更新是在2005年),但是就其功能和兼容性来说,一般的使用似乎没有什么问题。其用法也相当简单,大致的看看网站上面的文档即可。但是如果要做一些自定义的工作的话,就需要直接看它的源代码了。代码量不多,包括测试代码也就10多个文件。

最容易碰到的自定义需求应该就是定制上传文件存储的位置了,默认是在public目录下根据不同的模型名称来建立目录,明显的,这很容易造成“污染”,导致public目录下面生成大量的子目录。在看了其源码之后,注释中说明是可以通过给file_column这一方法传入参数:root_path来覆盖默认值的。我将root_path设置到public目录的file子目录下,试了之后在开发模式下上传文件确实没有问题,但是进行functional testing的时候发现并不正确。我在模型中设置了对文件大小进行验证的validates_filesize_of。这一方法在测试运行时验证查找的路径是在public目录下查找,这明显是不正确的,也即,仅仅覆盖root_path参数虽然能够在开发模式下正常工作,但是functional testing有些不同,按照其注释中的说法以及源代码,进行单元测试时file_column会把RAILS_ROOT/test/tmp/file_column这一目录作为根目录,而不是RAILS_ROOT/public/。单元测试时应该在setup方法中调用setup_fixture_files,在teardown中调用teardown_fixture_files,这两个方法会把文件fixtures复制到RAILS_ROOT/test/tmp/file_column目录下测试,测试结束后就移除。但由于根目录被我们传入的参数root_path覆盖,导致测试时的代码无法通过。解决的办法有两个,一个是按照不同的运行h环境来设置根目录,代码如下: 

if RAILS_ENV != "test"
  file_column :image, {:root_path => File.join(RAILS_ROOT, "public", "files")}
end
if RAILS_ENV == "test"
  file_column :image, {
  :root_path => File.join(RAILS_ROOT, "test", "tmp", "file_column", "files")
  }
end

但是这样做也有一个缺点,那就是如果在测试模式下进行集成测试的话(如使用selenium进行测试),file_column又会到test/tmp/file_column下查找文件。这也是明显不正确的,会导致文件无法访问。另外一个做法,可以做到万无一失的–直接修改file_column这一插件的代码:-)

A Visual Studio Tip

In programming on 8月 11, 2007 at 12:03 上午

用Eclipse习惯了,切换到Visual Studio之后发现有很多不顺手的地方。Eclipse中有一个功能,使用Ctrl+Shift+R就能够快速根据文件名打开任意的文件资源。在IntelliJ IDEA中也有这一功能,Ctrl+Shift+N就可以搞定。但是Visual Studio中却没有,每每要到目录树中查找一个文件,十分耗时。

今天偶然间发现了可以利用Eclipse来“帮助”Visual Studio实现这一功能。做法十分简单,把Visual Studio中的项目导入到Eclipse中。比如这是一个C++的项目(VS中最经常遇到的),因此就需要经常打开*.cxx,*.cpp,*.h等类型的文件。在Eclipse中文件关联中将这些类型的文件设置为使用VS打开,这样就可以在Eclipse中使用Ctrl+Shift+R迅速定位文件,然后一按回车,文件就在VS中打开了:)