刚加完班,想想这几天学的东西挺多的,虽然都是皮毛,但感觉还挺有成就感的。
公司刚走了俩领导,留下一个坑项目,我也是刚知道。三个人开发了一年啥没开发出来,然后现在到了交付时间了。忙的从四川分公司调了俩个人。说是想三个都裁掉,然后产品说那就没人干活了,然后还把我调过去帮忙写。
项目是spring boot的,我想想我用Python写,一个是以后还得我维护,二一个,权限什么的都不好做,开始我就想只做做边角功能就行了。然后发现分给我功能不属于边角,只能Java写了。
分工还有问题,本来应该写方法的,一个流程下边的,分给俩人做,这种技术上不行,工作效率上也不行。
我这几天看了几本Springboot实战的书,基本一掠而过。知道都是什么,然后看了文档里边的几个例子,就上手写代码了。
项目代码也没有太成熟,用了一个什么renren开源的库,我问过我单独写一个模块,就见了一个Springboot 服务,都用的官方默认的模块。注册服务那里用了公用的pom之后,折腾了我一上午没搞定,我就使用官方文档推荐的starters,分分钟搞定了。
Java静态语言,又是成员变量必须private定义,写的真麻烦,发现写Java果然需要ide,能生成代码,静态语言检查语法错误也方便,复制代码,需要导入也可以自动,感觉写起来还不错。
还有一个比较麻烦的就是,解析json和返回json数据的定义。我网上查找,看了几个例子,基本就懂了。
项目里我不需要关心权限相关的,所以感觉还比较简单。
通过这几天学习,感觉Java经过发展,他相关的工具链其实已经相当的成熟了。感觉给我一年的时间熟练开发项目,我这开发效率不会比Python低,现在开发更多的是找Java或者Spring解决方法,完全不需要知道这个是怎么来的。像我用Python判断IP是否是内网IP,我有很高效的方法,可以直接找到或者复制代码,我Java写的时候,我需要看很多,找到差不多的方案,然后写成公用类。如果之前写过,就直接复制就可以了。
还有就是http返回json的封装,我看了一下他们的项目,都没有统一,比如状态码,错误信息,我就定义了自己的。因为没有看过太多代码,也没有之前写过的公司项目借鉴,我竟然从我反编译的非开源的云平台项目里复制了一个文件,搞成我自己的了,还挺好用的,,,
总得来说写增删改查,搭建一个不需要太大定制化的大型公司项目来说,Springboot的一系列产品可以很轻松的搞定。这个是Python目前的环境做不到的。但是如果Python去封装,会比Java好看好写的很多。也许是因为Python做企业开发用的少,没有人去做这个吧,大公司项目迭代的原因也独立不出来了。
我觉得这几天做的东西很了不起了,后边还得帮他们做。感觉也是因为我之前积累导致了学这些东西还是很快的。现在最欠缺的就是相关源代码原理基本不知道,如果你说微服务架构我会知道,但你说Springboot是怎么封装起来的,这个我还是一头雾水,虽然注解我查了一下大体知道了,但是能把很多库统一标准起来,想想就头大。
Read more...
Archive for 算法-编程
趁国庆放假期间,正式立项开始搞我的游戏了。
emmm,其实从一开始自己学编程就各种研究做游戏,但都是坚持不下来等各种原因,啥没搞出来。
但是游戏框架倒是没少接触,自己脑子里想了好几个游戏,也分不同时间做过,然后每次都经历的过程差不多,选框架,选图片素材。开始的这种工作消耗了我基本好多时间,然后慢慢学框架发现这里不好做,那里不好实现,慢慢就放弃了。
有时候游戏还没开始,就想着跨平台,要搞个跨平台的框架。要做个手机游戏,首先想到的是苹果,安卓都要可以,找跨平台引擎写。时间都浪费在这里了。
期间写过一个微信小游戏,用了cocos creator,然后用了一个预置模板,然后加载特别慢,对这个引擎失望透顶。发现还不如我自己画的快。后来又写了一个小游戏,直接用的js库,ui什么的都自己画了,又快又爽。
用引擎就是会很多照顾新手,页面操作多,繁琐,虽然编程也可以。js的low,唯一好处就是web和微信支持,别的语言懒得学。像unreal,unity之类的搞3d太难了,虽然想搞。用框架就是依赖性太强,想改个东西还得看源代码,太低级的觉得太低级不想用,没啥必要用,太高级的又觉得都是费功能,太慢了。
用python之前考虑不跨平台,不想用。后来觉得去他妈的跨平台,老子先搞一个pc平台把我的想法实现了再说。然后想搞个无限地图的功能,找了一些现成的地图方案,发现缺陷太大,放弃。自己想了想,然后网上查了一下,发现跟我想法一样,自己用python撸了一个无限地图的功能,框架也是python的,发现巨慢无比,三十帧左右。也许是代码有问题可以优化,但是我想想即时把帧数优化上去了,后边加游戏逻辑还得慢,然后一直优化吧,直接放弃。然后找了一个c++写的小众游戏的引擎,功能很合我的意,官方有python绑定,看着例子写了个demo,感觉挺好。然后等我开始写深入功能的时候,发现ui是个问题,官方封装的代码太复杂,我c++不太懂,绑定第三方图像库也不了解。其实python的绑定封装的接口也乱,但是demo里边的东西,我大部分都了解了实现游戏逻辑没啥问题。又找了一圈别的库,又又又一次的放弃了。
折腾的比上边描述的要多的多,想起来写下来的就这些了。
前段时间我突然出来一个想法,想用commonlisp写个游戏,只是一个玩法好玩,想借助cl看看有没有好的发挥cl的特性。突然想明白一个事,我为什么想写游戏却局限于现在的技术栈里边呢。现在写web多,然后多考虑的是python,js之类的,用惯了不想换,但是又不是做这个擅长的事。以前上学学c,c++也都是只写逻辑,没有第三方依赖,最多写写vc,也是集成环境。突然想到,老子要用c写游戏了。
随便一搜就决定了用的技术,因为之前也了解了比较多的了。所以直接选点SDL,一个跨平台,一个c,百分比满意。然后官网找的一个书,一天看完了,发现使用很简单。图片音频这些加载,我又犯了强迫症,不行依赖额外的库。宁可使用第三方的开源代码放到项目里。后来又想通了,纠结这些事不对的。
我下定决心都用官方的,SDL_image mixer ttf,然后自己接触了这么多引擎框架,觉得cocos2d确实作者牛逼,一些游戏概念划分的很好。我参照cocos2d的理念,自己假期抽时间撸了一个c的小游戏框架,已经基本完善。
后边要做的主要就三块,一块是ui,这个也自己写,想了一下,总共用不了几个元素,自己撸还是来的快和爽,想怎么改怎么改,前期就是会丑一些。第二块就是物理,这里目前打算是用第三方的,其实也用不了太多的东西,但是自己撸数学懒得看,数学调试也麻烦,不然还得依赖别人写的库,不如直接用第三方的物理引擎。第三块就是游戏逻辑相关了,这里就是慢慢添加了,难道应该不大,就是消耗时间。
特别写完我的小框架后,就特别觉得之前为什么不用c写呢,陷入了python易用,写得快速的死胡同里了。最近因为写框架,写的c也不少,上班后写python的时候,每写完一行就想加个分号。我发现语言这东西不能一直换,思维什么的定势了不容易转换。
写c也没感觉说效率低多少,最主要的是要考虑内存申请和释放的问题。还有就是不能面向对象设计,每次都要传参数,就想怎么写的容易一点。但是c想写的容易一点就可以容易一点,但是像python,虽然本身设计带了很多设计模式,你想写容易一点,就得更深入挖掘python的知识,其实学起来反而不容易,除非写多了才会容易了。
c还有个问题,就是源码文件目录的设计,第三方库依赖的问题,虽然有ldd,otool之类的工具,但是我不清楚游戏业界都是怎么做的,我以后还得考虑,全源码编译。目前先软件包安装写代码。gcc 等一系列编译工具链也没看,大体功能知道,后边要用再看也来得及,现在主要还是pk代码要紧。
想起个问题就是为什么不用c++,这个写游戏是用的最多的,环境肯定好很多。但是一个就是c比较底层,写熟练了不局限于游戏这一块地方,系统编程用的也很多。c++面向对象确实比c好,但是太复杂了,想起了上学时那些关系什么的,产生了畏惧。其实我自己写自己用的代码,无所谓封装的好不好,但是综合权衡还是用了c,现在还是很满意的。
Read more...
python使用pyVmomi调用VMware api创建cluster,传入vim.cluster.DasConfigInfo,指定的参数不正确
先写解决方案:制定dasconfig的failoverLevel = 1,就解决了。
这是一个必传的参数。但是官网特别说明,所有参数都是可选的。All fields are optional. 然后报错“指定的参数不正确:”也没写哪个参数不正确。
我是google搜索找到了解决方案,而且还是六七年前的帖子,也就是说这个问题持续六七年了吗???
vmware文档啥分类没有,我找都是从manager到数据方法,或者dir看到了,直接搜索。太麻烦了。而且返回的数据是关联返回的,虽然可以制定返回的字段。
Read more...
centos 安装mysqlclient,mysql session错误的问题
折腾了我一个周五下午加一个周末的问题。
写的代码上线两个周了,之前只测试了同步跟列表的功能,展示没问题,上周测试了一下更新问题,开始删除没刷新,我还以为是前端老版本的编译有问题,发现接口确实调用了就没管了。
直到测试一个更新功能,发现接口调用成功了,但是数据没更新。还返回了http 200。我就看了一下代码,返回200不可能没执行到更新保存的代码。
发现只有在提交commit之前有查询操作,就会导致表更新失败。所以应该是个session问题。
试了我本机环境没问题,然后我就想到装的python包的版本问题,踩什么bug了吧。然后我对比了一下版本,我管理都是只写主要包的版本,依赖包的版本没有写,所以依赖包有的版本会高一点。
我选了几个可能的包,更换版本,发现不是这个原因。周末想想,如果是这个包的问题,应该早就发现了,会打补丁。
然后我就想到数据库的问题,我用的mariadb,测试系统是centos,然后我看了一下有新版本的mariadb,更新了一下,这里现在想想数据库的问题的概率也十分小了,而且是这么明显的bug。
mariadb的源巨慢无比,我又在尝试更新mysqlclient包,因为我记得安装的时候mariadb-devel不能用,网上说的用mysql-devel。我又从新试了一次,各种方法,发现不成功。
到下午快下班,安装完mariadb,又试了一遍mariadb-devel也不行。觉得还是用mysql,又安装称mysql。
但是发现数据库数据文件不兼容,升级的命令好像也不太行,我备份的导出数据库数据,导入又有外键关联的限制,懒得搞数据了。下班了。
周末有时间的时候就想了想,我之前虽然抓包测试环境mysql,发现没问题,但是没对比本机的。如果周一mysql不行,试试本机环境连线上数据库,排除一下是包的问题还是数据库问题。感觉周五的时候应该先排除问题再更新数据库才对。
周一来,同步了一下数据,更新了一下发现mysql还是不行。然后重新编译mysqlclient,测试发现通过了。
最后还是mysqlclient编译依赖有问题,使用mysql-devel编译,连接mariadb有问题。好像还不是所有的版本有这个问题。
Read more...
cocos2d-python在Mac上设置label居中不生效的问题
在Mac上写cocos2d游戏代码的时候,写了个label,调了几次没居中,突然想到是不是mac屏幕的原因。然后鼠标滑了一下看了一下还正好差一倍居中。
然后网上搜了一下,在github上找到了解决方案。
HiDPI屏幕都会有这种问题,有两种patch,一个改pyglet的,一个改cocos2d的,然后我手动改了一下cocos2d的代码解决了。
话说cocos2d不更新了,维护也不知道会不会改。突然感觉选择cocos2d有点虚了。
issues:https://github.com/los-cocos/cocos/issues/303
Read more...
kubernetes scheduler源码阅读-- scheduler.New()的参数
scheduler.New() 定义在kubernetes/pkg/scheduler/scheduler.go
返回一个Scheduler
type Scheduler struct {
config *factory.Config
}
首先先用New传过来的参数替换schedulerOptions默认配置
type schedulerOptions struct {
// 调度器的名字,pod创建的时候可以根据这个名字选择使用哪个调度器,默认值"default-scheduler"
schedulerName string
//
hardPodAffinitySymmetricWeight int32
disablePreemption bool
percentageOfNodesToScore int32
bindTimeoutSeconds int64
}
然后调用factory.NewConfigFactory创建一个factory.Configurator,需要传入一个factory.ConfigFactoryArgs
还有个configFactory,这几个差不都都是参数传进来的几个值,具体还不知道干什么的。先看几个参数吧。
cc.InformerFactory.Core().V1().Nodes() 对应类型 nodeInformer coreinformers.NodeInformer
其中cc.InformerFactory在kubernetes/cmd/kube-scheduler/app/options/options.go中初始化:
c.InformerFactory = informers.NewSharedInformerFactory(client, 0), 创建一个新的factory, 结构体主要为cc.client和informers map[reflect.Type]cache.SharedIndexInformer.
Core()是New了一个新的group, 感觉还是啥没有,还是factory那几个值。
V1()是New了一个v1,返回一个version,还是哪几个值.
Nodes() 传的还是那几个值,返回一个nodeInformer. 最重要的就是保留了factory,然后能够调用nodeInformer接口下的几个方法。后边用的吧。
nodeLister: args.NodeInformer.Lister(),
在NewConfigFactory()里创建configFactory的时候,调用了.Lister()方法。
func (f *nodeInformer) defaultInformer(client kubernetes.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
return NewFilteredNodeInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
}
func (f *nodeInformer) Informer() cache.SharedIndexInformer {
return f.factory.InformerFor(&corev1.Node{}, f.defaultInformer)
}
func (f *nodeInformer) Lister() v1.NodeLister {
return v1.NewNodeLister(f.Informer().GetIndexer())
}
调用太多,看代码最烦的就是调来调去,然后还有各种新数据定义,翻来翻去然后回不来了。。。
corev1.Node 这个里边应该都是返回的数据格式类型定义, 没细看。
看InformerFor里边defaultInformer是个真正调用的函数, InformerFor就是用来包装了一下
v1.NewNodeLister 看起来就是定义的restful api的请求。
看的有点细,其实这部分都是client-go里的,是封装的api请求,应该是分不同资源请求不同的interface
cc.PodInformer 看这个应该比较重要
c.PodInformer = factory.NewPodInformer(client, 0) 用来返回non-terminal状态的pod
configFactory其他初始化参数不看了,后边用到再看。
Read more...
kubernetes scheduler源码阅读-- kube-scheduler整个流程
代码读的master上最新的 1641ff411.
命令入口文件在kubernetes/cmd/kube-scheduler/scheduler.go
主要就两句,设置启动参数。其他的设置命令行参数和日志打印。具体不看了
command := app.NewSchedulerCommand()
command.Execute();
NewSchedulerCommand 在文件kubernetes/cmd/kube-scheduler/app/server.go
很多代码都是设置scheduler命令参数的,也是用的cobra这个库,跟docker是一样的。
opts, err := options.NewOptions() 读取默认配置
runCommand()执行命令
runCommand 比较有用的几行:
c, err := opts.Config()
这里边东西比较多,比如初始化kube-client与api交互,eventclient,选举相关的配置。没仔细看,代码在kubernetes/cmd/kube-scheduler/app/options/options.go
cc := c.Complete()
stopCh := make(chan struct{}) 这个channel传入了Run函数,Run只会在报异常或者这个channel关闭的时候返回
是用来配合context提示go协程退出的
函数最后调用return Run(cc, stopCh)
Run()
生成一个新的scheduler, sched, err := scheduler.New()
后边启动了事件传输,监控选举的,还有监控和指标收集的,这个先不看了。
再后边就是stopChannel配合context管理协程,还有一个leader选举的功能,是通过cc.LeaderElection参数来控制的.
leader选举功能开启是为了高可用的时候使用
无论是否leader选举,最后都进入sched.Run()
Read more...
Clojure安装mac开发环境
开始只在在线Clojure网站上进行一些测试,后来感觉不行,操作速度都太慢。决定还是安装个环境。
去clojure官网看了一下也不麻烦。
去官网下载个zip包,解压到目录。
进入目录创建一个bin目录,新建一个clojure文件.添加几行代码
Read more...
if [ x$* != x ]
then
java -cp /Users/a0x55aa/tools/clojure-1.8.0/clojure-1.8.0.jar clojure.main "$*"
else
java -cp /Users/a0x55aa/tools/clojure-1.8.0/clojure-1.8.0.jar clojure.main
fi
然后加入环境变量path种就行了,方便到处使用.
Docker源码阅读6-创建server启动和containerd的启动
接上次看的往下看
cli.Pidfile 创建pid文件"/var/run/docker.pid"
serverConfig := &apiserver.Config{
Logging: true,
SocketGroup: cli.Config.SocketGroup,
Version: dockerversion.Version,
EnableCors: cli.Config.EnableCors,
CorsHeaders: cli.Config.CorsHeaders,
}
这几个默认值为 SocketGroup 为docker, EnableCors false, CorsHeaders 这个看EnableCors
api := apiserver.New(serverConfig) 这个就是实例化了个Server,cfg为上边的serverConfig
cli.api = api
返回一个, 初始化cfg为serverConfig,看起来所有请求的路由都在这里了
type Server struct {
cfg *Config
servers []*HTTPServer
routers []router.Router
routerSwapper *routerSwapper
middlewares []middleware.Middleware
}
cli.Config.Hosts没有的话创建一个长度1的数组,有的话进入循环进行监听
listeners.Init
wrapListeners(proto, ls)
allocateDaemonPort(addr)
api.Accept(addr, ls...)
监听地址, 根据hosts初始化的多个httpserver。
migrateKey 这个看起来好像是为了升级还是啥的。把之前配置文件目录的key.json移动到/etc/docker/下边,并把旧的删除
具体不知道为啥这么做
registryService := registry.NewService(cli.Config.ServiceOptions) 返回一个DefaultService
newServiceConfig(options)里边,配置镜像仓库地址
containerdRemote, err := libcontainerd.New(cli.getLibcontainerdRoot(), cli.getPlatformRemoteOptions()...)
重头戏来了,
getLibcontainerdRoot /var/run/docker/libcontainerd
getPlatformRemoteOptions 里边好像就是设置了一些参数
libcontainerd.WithRemoteAddr 这个是设置了ContainerdAddr配置,containerd参数走这个,调用rpcAddr(addr)。
没设置 走libcontainerd.WithStartDaemon(true), 然后调用startDaemon(start)
type RemoteOption interface {
Apply(Remote) error
}
New里边先初始化remote
eventTsPath getLibcontainerdRoot/event.ts
option.Apply(r)这里应该就是真正设置参数到初始化的remote了。不知道为啥这么写
创建getLibcontainerdRoot也就是stateDir 700权限
如果没有rpcAddr 设置 stateDir/docker-containerd.sock
startDaemon默认是true的所以肯定执行r.runContainerdDaemon()
runContainerdDaemon里
pidFilename stateDir/docker-containerd.pid,下面判断pid文件是否正确,如果进程在运行赋值r.daemonPid,就返回结束了
如果没运行,先设置运行参数,然后执行命令启动docker-containerd
setOOMScore oomScoreAdjPath := fmt.Sprintf("/proc/%d/oom_score_adj", pid) 好像就把参数那个数写文件里了,默认-500
写进程号
建了一个r.daemonWaitCh channel,container进程结束后,关闭这个channel。赋值r.daemonPid
总的来说就是启动container进程
使用grpc创建rpc连接
r.rpcConn = conn
r.apiClient = containerd.NewAPIClient(conn) 返回
type aPIClient struct {
cc *grpc.ClientConn
}
就保存了rpc连接
getLastEventTimestamp就是看 stateDir/event.ts 文件,没数据就返回当前时间,如果有,里边保存的是序列号化的,反序列化一下返回
tsp, err := ptypes.TimestampProto(t)转了一下时间
r.restoreFromTimestamp = tsp
go r.handleConnectionChange()
大体看了一下,就是开个协程进行rpc连接探测, 连续失败到三次,如果进程存在kill.<-r.daemonWaitCh,然后r.runContainerdDaemon()启动
r.startEventsMonitor(); 监控请求事件
发送了一个"/types.API/Events"请求, 然后开个协程有事件就处理事件
处理完更新事件时间
处理事件这里先不仔细看了。感觉看下去脑子回不来了.
libcontainerd/remote_unix.go
startEventsMonitor()标记一下,以后看
主要就是server的启动和containerd的启动
Read more...
InfluxDB取TOP n数据数据进行limit
在用Grafana绘图,后端时序数据库用的InfluxDB。在进行绘图的时候用到取top n的数据。有一个top函数,但是里边不能有函数计算了。我是先group by tag 然后求和的。
查了好多看大部分都是top,开始搜的时候还搜的Grafana,后来想到这是influxdb的查询。找到官方文档,有一个limit和slimit.
这里是有区别的,slimit是相当于之前想法的limit,只去分组的top n。而limit是取每个分组下的top n。
但是order by 也不能 用聚合的字段来,还不知道排序怎么搞。
感觉influxdb还是很新的东西,好多东西太难搞了。也许是不了解。。
Read more...