一.问题描述
客户反馈,在使用我们的产品时,接口查询时会显示异常错误:Invalid URI: The Uri string is too long
二.解决思路
1.排查异常来源
从接口请求开始断点,一步一步找到异常来源代码
return await _conn.QueryAsync(sql, requestArgs);
这里_repo是使用的第三方库ClickHouse.Client的ClickHouseConnection
提供的QueryAsync方法。
查看QueryAsync的源代码
public static Task<IEnumerable<dynamic>> QueryAsync(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null) =>
QueryAsync<dynamic>(cnn, typeof(DapperRow), new CommandDefinition(sql, param, transaction, commandTimeout, commandType, CommandFlags.Buffered, default));
但没有找到对应的实现类,没有办法,只能换一个思路。
2.源码排查
在项目中没有看到实现的源代码,就试着转向Github, 看一下其他开发者有没有遇到同样的问题。
在issue中搜索too long
查看第一个结果,找到一条评论说遇到相同的问题。
在issue #270里面有相关介绍。
这位工程师说他也遇到相同的问题,提问说能不能支持将查询放在POST请求体中,Clickhouse在某个issue之后就已经支持该特性了。然后我点击进入该Clickhouse的issue。
显示为已关闭的issue,评论说这个功能已经实现了。回到之前Clickhouse-Client issue #270,找到如何在项目中开启这个功能。
查看提交的内容。
在测试代码里面找到了配置项
顺便看了一下支持的版本,我们的项目正好满足要求。
3.更新库版本
看了一下提交相关配置代码的日期。
在Release里面找提交代码之后的版本,7.6这个版本有相关描述。
我们项目的版本是4.4,所以我简单浏览了一下4.4到7.6的更新内容,发现了几个重点提示信息,不确定有有没有影响,先留个印象。
升级完成后,修改了相应的配置,接口就不再报错了。
4.解决更新异常
虽然接口不报错了,但是有一个后台批量保存的逻辑一直在报错。
System.InvalidOperationException: Column names not initialized. Call InitAsync once to load column data\n at ClickHouse.Client.Copy.ClickHouseBulkCopy.WriteToServerAsync(IEnumerable`1 rows,
正好留意到7.0.0有一个提示与它相关,抱着试试的态度看了一下相关issue,找到了相关测试代码,将新增的代码加入到本地开发代码后就不再报错了。
三.问题总结
这次问题排查遇到了一些坑,卡了很久,但还是有不少收获:
1.需要锁定问题根源。
刚开始看到报错信息以为是.net项目请求体大小限制,改了很多参数也没有效果,后面尝试打断点才发现是ClickHouse查询请求的报错。
2.利用Github搜集信息。
很多问题其实别人已经遇到过了,在Github issue找问题答案是比较快捷的一种方式。
3.留意版本更新说明。
像大版本更新这样的操作尤其需要注意,有很多新特性会导致代码兼容问题,需要做处理,Release里面会有提示信息。
评论