简单生活

  • 实测阿里云RDS Serverless

    ·

    在4月底,阿里云RDS Serverless正式公测发布。第一时间申请了公测资格,并进行了测试验证。测试完成后,还是非常期待这个功能的商业化的,当前的公测版本也值得开发者们去了解和小范围(例如开发测试环境)尝试。

    00 什么是RDS Serverless

    RDS Serverless是一种独立于按量付费、包年包月的资源使用与计费模式。提供了一种自动化的弹性扩缩容的规格,用户无需提前选定固定规格,后端会根据系统压力进行自动升降配,并根据实际使用计费,当然,用户需要设置该规格最大和最小规格,限制最大、最小使用资源与费用。

    对于峰谷明显的业务系统,该模式一方面可以在需要时提供很高的资源规格应对压力,另一方面可以在低峰时降低资源使用,降低成本。

    01测试结论概述

    • 整体上,该Serverless版本的升/降配速度非常快,约10秒完成压力检测与变配,升配时性能表现非常平稳,降配时性能比较平稳。
    • 具体的,在系统压力突增时,约10秒内就可以完成检测与变配,完成升配后系统压力立刻得到一定程度的缓解;与之前的Aurora Serverless v2测试中,升配的时间是差不多的,都是10秒以内
    • 在系统压力下降时,降配的速度也非常快,约10秒完成检测与降配操作。另外,需要注意的是,当前的版本,因为降配非常快,也导致降配后,性能出现了一些波动,持续约10秒,波动幅度从约8毫秒的响应时间增长到30~50毫秒,在两次降配之后,都出现这样小波动。相比,Aurora降配更加“保守”,观测了50秒,之后才开始降配。在降配之后,Aurora的性能依旧非常平稳,没有任何波动。也就是说,降配过程中清除出内存池的数据页都是确确实实不再使用的,这里可能需要深入的观测InnoDB的Buffer Pool收缩时的表现,避免将可能使用数据页清理出内存。
    • 目前只支持基础版(单节点实例),应用场景还比较有限,不过对于开发测试环境,种类可用性要求没那么高,且性能峰谷明显的场景,是可以轻松节省超过50%成本的,而且在实际使用时,性能还会非常不错(最高扩展到8*RCU)。
    • 当然,现在阿里云RDS Serverless还是刚刚公测,申请公测资格通过后,可免费创建2个体验实例,最大规格为8*RCU,即约8c16g内存的实例,免费周期3个月,算是不错的羊毛了,具体的,可以通过RDS MySQL购买页找到公测申请链接。

    02 测试方法说明

    整体的测试方法与之前做Aurora Serverless v2类似。首先,启动一个单线程sysbench,作为测试“主进程”,程序运行900秒,在“主进程”运行300秒后,再启动一个“压力进程”(24并发的sysbench进程)向系统施压,该进程运行300秒后退出,在这个过程中,我们观测”主进程”的rt变化,以及整个过程中,实例规格的变化(依旧以buffer pool为指标)。更详细的描述可以参考:实测Aurora Serverless v2

    03 测试结果与分析

    3.1 整体过程

    • 下图黄点代表主进程每秒RT的变化;”蓝点”(连成线)代表秒级别buffer pool的变化。左侧纵坐标为响应时间,单位为毫秒;右边纵坐标为buffer pool大小,单位为GB
    • 在第300秒,“压力进程”给出额外压力之后,系统开始升配,经过三次升配之后,到最大规格
    • 在第600秒,“压力进程”退出,经过了4次降配,降级到最低规格

    3.2 升配过程

    从如下放大的图可以看到,在“压力线程”启动的第300秒,“主线程”的响应时间立刻增长到了300ms。

    • 该实例在之后的7秒内完成升配,实例响应时间也立刻降了下来,降到约75毫秒
    • 之后,再过10秒(约第317秒),完成了第二次升配,实例响应时间再次下降,约到30毫秒
    • 再过约10秒(约第328秒),再次升配,但是此时响应时间不再有什么变化

    3.3 降配过程

    • 第600秒,压力进程退出,约11秒后,完成降配。但是,在第15秒性能出现明显波动,持续10秒
    • 第650秒,完成第二次降配,4秒后性能出现波动,持续约5秒
    • 第670秒,再次降配,性能再次波动,并出现一个异常点,响应时间非常大(约200ms)
    • 之后,系统平稳运行

    04 其他

    • 当前RDS Serverless处于公测阶段,没有SLA保障,且仅支持基础版、区域支持也有限,虽然降配和升配都比较快,也比较稳定,但是还不适合生产环境。
    • 当前,实例规格区间为0.5~8 RCU,最大规格也还比较小。
    • 在这次对比测试中,也发现,相比AWS,阿里云在同一个可用区的网络延迟是更低的,仅5~10ms,而Aurora同可用区响应时间约为15~20ms。
    • 据了解,阿里云今年还是会在这个方向加大投入,还会有一些大的版本和改进发出来,拭目以待吧。

  • 去年11月,Amazon RDS推出的新的形态:Multi-AZ Cluster(三可用区三节点)。相比“原来的多AZ”(两个可用区)架构,新的Cluster模式是三节点架构,提供了更低的事务延迟,同时有更好的读扩展能力。国内的云厂商中,阿里云和腾讯云很早就有了三节点形态,一起看看,他们有哪些异同,在实际的业务场景中,哪些情况可以选择这种形态。

    AWS RDS三节点(Multi-AZ Cluster)是什么?

    这里将其主要特点概括如下:

    • 这是一种3*AZ部署模式,而原来的Multi-AZ是2AZ部署或者单AZ部署。
    • 使用了数据库的逻辑复制,而原来的双AZ使用的是EBS层的复制,这就使得Cluster的副本节点都可以直接提供读能力,有更好的读扩展能力。
    • 使用了类似MySQL半同步的复制技术,事务日志网络到达其中任意一个副本主节点事务就可以提交,所以主节点上的事务延迟会降低,性能会提升(对比基于EBS的两节点)。
    • 支持Graviton 2的规格和NVMe-based SSD存储,可以提供更好的性能。
    • 同时支持MySQL和PostgreSQL两个引擎。

    与阿里云、腾讯云数据库三节点的区别

    阿里云RDS提供的“三节点企业版”,支持MySQL引擎,通过Paxos协议(或其变种)同步。相比Amazon的方案,其中一个节点使用了日志存储,成本可以更低;三个节点,只有一个节点提供服务。腾讯云MySQL也支持三节点版本,使用了半同步复制,可以选择异步、半同步或者强同步三种模式,也只有一个节点可以提供服务。

    相比AWS,阿里云与腾讯云的三节点模式都可以由用户自由选择可用区分布,即可以都在一个可用区,也可以分布在两个或三个可用区,给了客户更强的灵活性。

    (more…)
  • SQL Server的用户体系和MySQL有非常大的不同,无论是在使用上、还是概念上。所以,这里梳理一下SQL Server的用户与认证的一些基础概念与使用。另外,这个概念在SQL Server相关资料中各个地方都会出现,是理解权限体系的基础。

    “login”“database user”

    在SQL Server中,”login”不是一个动词,而是一个”名称”(注:”log in”是动词),代表的是一个用于登录的对象(Object),这是一个服务器级别的对象,所以,它有自己的登录名(login name)、密码、默认语言、认证方式等。需要强调的是,它不是一个数据库(database)级别的对象。

    而”Database User”是一个数据库级别的对象,与之相对应的则是数据库级别的权限。”Database User”并不能连接或者登录SQL Server实例,所以,一般来说,也不需要密码。

    “login”因为是Server级别的,所以权限也都是Server级别的。本身不能赋予任何数据库相关的权限,但是,login可以和一个Database User建立映射,使用该login连接数据库的时候,该连接也就可以根据Database User权限进行相关的操作了。

    最常见、最简单的创建login和database user的命令如下:

      use zzxdb2;
      create table t_1(id int,nick nchar(12),birthday date);
    
      create login zzxdb2 with password='zzxdb2' ,CHECK_POLICY=OFF;
      create user zzxdb2 for login zzxdb2;
    
      -- 当没有赋予权限的时候,zzxdb2可以登录SQL Server,但是看不到zzxdb2下面的TABLE
      -- 所以,最后还需要赋予database user相应的权限,如下
      exec sp_addrolemember 'db_owner', 'zzxdb2'; 

    为什么容易混淆

    通常的系统中只有用户的概念,权限系统都是基于用户。而SQL Server在其上新增了Login这一层,与其他的系统都不同。另外,在一般的客户端中,在需要登录的时候,通常都是使用”user name”/”password”作为登录认证的凭证,而不是”Login”/”password”,所以初学者通常容易混淆,例如微软的Mac客户端Azure Data Studio:

    一些可以帮助理解”login”和”user”关系的一些问题

    1. 只创建login,而不map到一个具体的database用户,是否可以登录?

    答案是简单的:可以登录,但是没有数据库相关的权限。测试如下:

    先创建一个没有映射到”user”的”login”:

    CREATE LOGIN alogin WITH PASSWORD = 'alogin', CHECK_POLICY=OFF;
    -- 注: CHECK_POLICY可以让你设置简单密码,并不建议加上
    • 使用上面的”login”在Azure Data Studio中连接并进入SQL Server。可以看到,可以正常登录,但是因为没有database相关的权限,所以展示database里面的对象的时候,会失败,如下:

    也就说,”login”只有在与具体的某个database user建立了mapping之后,才可以访问对应的数据库。在上面例子中的”login”主体”alogin”,要访问和管理数据库9zcloud,是会失败的。

    当然,如果真的需要访问的话,那么我们需要先建一个database user,并在user和login之间建立mapping,具体操作如下:

    CREATE USER a_db_user_9zcloud FOR LOGIN alogin;  

    2. 创建用户,不映射到任何login,后续是否还可以重新映射?

    如果在用户创建的时候显式的声明,不映射到任何login,那么后续是否还可以重新映射到某个login?答案似乎没有那么明显了。遂测试如下:

    CREATE USER a_db_user_9zcloud WITHOUT LOGIN;
    ALTER USER  a_db_user_9zcloud WITH LOGIN='alogin';
    -- 报错如下:
    
    消息 33016,级别 16,状态 1,第 45 行
    The user cannot be remapped to a login. Remapping can only be done for users that were mapped to Windows or SQL logins.

    可见,如果在创建的时候显示声明不映射到任何”login”,那么就不能够再重新映射任何的”login”。

    3. 如果用户名和login主体名字不一样,客户端登录的时候使用哪个?

    答案是显然的,但是还是验证一下。

    具体的,如果数据库用户名和login用户名不一样,那么在登录连接SQL Server的时候,使用的是database user还是login的名称?具体看下面的例子,在使用客户端登录的时候,使用的alogin,还是使用a_db_user_9zcloud?

    CREATE LOGIN alogin WITH PASSWORD = 'alogin', CHECK_POLICY=OFF;
    CREATE USER a_db_user_9zcloud FOR LOGIN alogin;

    答案,当然是使用login的主体alogin。

    4. 在创建用户时如果映射到了某个login,同时也创建密码,那么这个密码有什么用?

    是啊,有什么用呢? 具体的,在创建用户时映射到某个具体的login,但是依旧指定一个密码,那么这个密码有什么用?测试验证如下:

    CREATE LOGIN alogin WITH PASSWORD = 'alogin', CHECK_POLICY=OFF;
    CREATE USER a_db_user_9zcloud FOR LOGIN alogin WITH PASSWORD = 'dbuser9zcloud';

    答案:你就不能这么用!!(注:仅当在contained database中可以使用密码,参考) 在明确映射到某个具体的login的用户,不需要密码,也无法指定密码。所以,上面的语句执行会失败,报如下错误:

    消息 33234,级别 16,状态 1,第 47 行
    
    The parameter PASSWORD cannot be provided for users that cannot authenticate in a database.

    另外,注意到login在创建的时候,是可以指定默认数据库(DEFAULT_DATABASE)的;创建用户的时候,可以指定默认的schema。

    其他内容

    • 在给一个对象(主体)赋权的时候,可以通过按照细粒度(某个表的某种权限)方式进行,也可以直接将其加入到某个角色组,那么这个角色组对应的权限就都有了。例如,将login加入到”sysadmin”(fixed server role),那么就有了所有sysadmin角色组的权限,sysadmin可以理解是一个超级权限组,如果在该组中,那么访问对象时不需要检查该账号的权限;与sysadmin对应的一个权限是”CONTROL SERVER”,如果使用GRANT则可以使用这个权限。
    • 另外,前文中偶尔会用到”主体”这个名称,英文对应SQL Server文档中的”Principals”,”主体”是SQL Server官方中文文档的翻译(参考)。可以理解为一个实体,或者前面对象的实例化或者实体,也就是说,某个具体的”server roles, logins, database roles, or users.” 都可以称作”Principals”。
    • SQL Server中的系统表sys.server_principals、sys.server_permissions会存储相关的元数据。
    • 在SQL Server官方文档中将”login”翻译为”登录名”(参考)。这也是为什么,一些客户端在让输入用户名的时候,其实是输入一个login主体名和对应的密码。
    • 在创建user的时候,如果没有显示的指定FOR LOGIN,没有指定WITHOUT LOGIN,那么该user将会被映射到同名的login上(还没有验证这一点,参考:If FOR LOGIN is omitted, the new database user will be mapped to the SQL Server login with the same name.)。
    • 另外,系统中还有一个名字为guest的login,默认是不可用的。
    • 在实际中,也有一些场景是需要创建user,而不映射到任何的login,后续会再考虑介绍这类场景。

    参考阅读

    • Determining Effective Database Engine Permissions:链接 如何查看系统中的账号权限
    • Database Engine Permissions SQL Server 2017 and Azure SQL Database: 链接
  • 长路漫漫 踏歌而行

    ·

    Canon EOS R5 RF24-70mm F2.8 ISO-100 ƒ5.6 1/200 By Pingping

  • 选择

    ·

    在前公司的时候,参加过一个叫《选择》的培训(参考),与其说这是一个关于管理的培训,倒不如说这是一个认识自己,认识人与人关系的培训,其背后的意义,并不仅仅适用于公司协作,更多的是在生活中,如何与自己”和解”,如何与他人”和解”。在这个课程中,当时的培训老师叫”龙子立”(参考),他在介绍中,介绍了什么是”价值观”,为什么”价值观”需要用具体的事情和衡量,为什么价值观需要付出代价。

    “付出”有时候是试金石

    付出就是一颗”试金石”。根据生活中的经验,通常,每个人都深深的认为自己是一个好人,是一个善良的人。但是,如果,试问:你今年有没有帮助过你的朋友或者其他人?无论事情大小。例如,

    • 驾车时,斑马线一侧有人在左右张望,而你可以通过的情况下,你是否愿意停下车来等他?
    • 常用的服务/软件/产品的体验调研,你是否愿意花十分钟认真的完成?
    • 如果你是一个资深的技术人员,你用过很多的开源软件,你有没有帮助过这个软件?
    • 你会不会为你经常使用的软件,而慷慨付费?
    • 你有没有帮助过陌生人,无论事情大小?
    • 你是否会由衷在他人面前/背后,因为认可而夸赞他人?
    • 你是否会由衷的认可与你意见相左的人的一些行为或者做法?”

    再比如:

    • 当你有权责的时候,你是否会借此伤害(或大或小)曾经让你”怒目”的人?
    • 当你有能力的时候,你是否愿意帮助那些曾经让你“怒目”的人?
    • 当你意识到你错了的时候(有时候也许你是对的),你是否敢于向你曾经言语伤害到的人道歉?

    再比如:

    • 当你在游戏/追剧正酣时,是否愿意为了孩子找不到一块积木而停下?
    • 你是否愿意为了带孩子去动物/植物园,而放弃周末早上温暖的被窝?
    • 你是否愿意花几个小时/几百块,为爱人挑选一个礼物(也许她不一定喜欢)?
    • 你是否愿意花几个小时/几百块,在重大节日(例如新年)为大家准备一份节日惊喜?

    无论上面哪件事情,你都需要付出代价,或大或小,有时候是几分钟时间、有时候是几个小时,有时候是几十块钱,有时候是几千块或者更多。如果你从不曾做过一件帮助他人的事情,那么大概很难说服自己,自己是一个善良的人。

    不以善小而不为,不以恶小而为之

    这是”刘皇叔”大约两千年前写给儿子的”要求”,却从不曾过时。如果每个人都要求自己能够做出惊世骇俗之举,显然是不可能的,从善也是如此,每个人只能从小事开始。实际上,如果在小事上做到善良,那么遇到大事/大节,则也更可能做出善良的选择。反之亦然,”小恶”做的多了,自然更容易一步步走向”大恶”。

    在实际生活中,能够做一些”小善”便已经很好了,例如,能够在斑马线前停下来等待行人优先通过,能够停下来耐心的为快递小哥带路到”春晓苑”,为自己经常使用的软件付费等。

    这一次做个善良的人,不纠结于以前,也不要为以后背负任何负担

    做善良的事情并不容易。我们通常会屈服于各种各样的理由,很多理由似乎都没有任何道理。在骑电动车的时候,来到一个红灯路口,同时现在穿过也很安全的时候,以前经常会纠结:“我昨天就没有等这个红灯,今天要充什么好人”。现在,我则反过来激励自己:“虽然,我昨天没有等这个红灯,也许我明天也不会等这个红灯,这并不妨碍我这一次,这一刻做一件正确的事情”。事实上,这么想,这么做,骑电动车时闯这个红灯的次数少了很多。

    这是一个建议,一个选项,而不是一个“人设”

    近几年,“人设崩塌”事件时有发生,做个善良的人的人设则更难维持(似乎是不可能),所以,这不是一个人设,而是一个建议,今天做一个好人,做个善良的人,做一件善良的事情,并不要求自己永远都这样,每个人的经历、所处的环境通常都非常复杂,甚至还有很多是刻在基因中的选择倾向,做一个“自私”人的同时,并不影响依旧去做一些善良的事情,做了一些善良的事情,那么这件事情上,你就是一个善良的人,我不要求自己一直能够做一个善良的人,而且我也很确定,任何人都很难这样。

    我不想,不打算背负任何“好人”的人设负担,但我依旧愿意做好这一件善良、正确的事情。

    好人不一定有好报,但是,依旧做一个好人

    虽然,社会舆论会不断的渲染,因为做了好人,会可能获得更好的结果,但是实际的情况是,影响是否会有“好报”的因素,非常多,而你自己是不是一个好人,只是一个非常小的因子。一件事情,是不是有好报,个人做个粗略的判断,运气大概占了四层,个人努力可能占了三层,另外,还有三层大概是更多的不可知,或者不确定的因素。至于,你是不是一个好人,在其中的影响甚微。虽然,法律、道德等,都会尽量将社会引导到好人好报、恶人恶报,但是,非常非常遗憾,好人也会有恶报,恶人也会有好报,这几乎是一定的。

    所以,选择做一个好人,不能纠结于此,也不能因为好人没有获得好报而放弃,也不能因为恶人没有恶报,而忿忿。

    善良的分寸

    尽自己的绵薄之力帮助他人,就非常不错了。如果愿意付出更多,已经是侠义心肠了。给自己订立的“分寸”有两个原则,其一,对自己生活没有什么影响,受助者也只是需要基础的帮助。

    其二,付出一份,最好能够给他人带来更多收获。例如,拿出 100 元帮助边远地区贫困学子,于自己可能是较小的付出,但是于他人,则是几个月的生计、是一份安心就学保障,自然就达到了一份付出,更多收获的效果。

    如丰子恺所在“不宠无惊过一生”中提到,“不乱于心,不困于情。不畏将来,不念过往”。

  • 这是一个记录。虽然微软的文档已经非常完善和友好了,但是涉及到一些软件版本等相关问题,配置并不畅通。

    安装

    本地环境是macOS Big Sur 11.4版本,使用的是Python 3.8.2版本。

    zzx@localhost % python3
    Python 3.8.2 (default, Apr  8 2021, 23:19:18)
    [Clang 12.0.5 (clang-1205.0.22.9)] on darwin
    Type "help", "copyright", "credits" or "license" for more information.
    >>>

    需要安装pyodbc、unixodbc、msodbcsql17、mssql-tools等工具(详细参考):

    pip3 install pyodbc
    brew install unixodbc

    测试脚本

    主要参考微软文档:Proof of concept connecting to SQL using pyodbc。测试连接脚本如下:

    import pyodbc
    # Some other example server values are
    # server = 'localhost\sqlexpress' # for a named instance
    # server = 'myserver,port' # to specify an alternate port
    server = 'x.x.x.x'
    # server = 'tcp:x.x.x.x,1433'
    database = 'xxx'
    username = 'xxx'
    password = 'xxx'
    cnxn = pyodbc.connect('DRIVER={ODBC Driver 17 for SQL Server};SERVER='+server+';DATABASE='+database+';UID='+username+';PWD='+ password)
    cursor = cnxn.cursor()
    
    #Sample select query
    cursor.execute("SELECT @@version;")
    row = cursor.fetchone()
    while row:
        print(row[0])
        row = cursor.fetchone()

    一下子就跑通了? 有经验的开发者都知道,那当然不能这么顺利,是吧。首先,遇到如下报错:

    Traceback (most recent call last):
      File "mssqlremotessh.py", line 10, in <module>
        cnxn = pyodbc.connect('DRIVER={ODBC Driver 17 for SQL Server};SERVER='+server+';DATABASE='+database+';UID='+username+';PWD='+ password)
    pyodbc.OperationalError: ('08001', '[08001] [Microsoft][ODBC Driver 17 for SQL Server]Client unable to establish connection (0) (SQLDriverConnect)')

    是哪个环节的问题?

    老实说,这个报错真的很不友好,无法看出来是什么地方的问题。首先,根据Github上一个issue建议首先通过isql命令(应该是unixODBC的工具)尝试连接一下SQL Server,果然有了新的发现:

    # 注意:下面命令的IP和密码都被修改了
    isql -v -k 'Driver={ODBC Driver 17 for SQL Server};Server=tcp:18.336.80.202,1433;Database=9zcloud;Uid=zzx;Pwd=********;'
    
    
    [08001][Microsoft][ODBC Driver 17 for SQL Server]SSL Provider: [OpenSSL library could not be loaded, make sure OpenSSL 1.0 or 1.1 is installed]
    [08001][Microsoft][ODBC Driver 17 for SQL Server]Client unable to establish connection
    [ISQL]ERROR: Could not SQLDriverConnect

    解决openssl版本依赖问题

    看起来似乎是ODBC依赖OpenSSL 1.0或者1.1,而查看了本地默认安装的应该是v3版本,查看如下:

    $ cd /usr/local/Cellar/ && ls
    $ cd openssl@3/3.0.1/bin
    $ ./openssl version
    $ OpenSSL 3.0.1 14 Dec 2021 (Library: OpenSSL 3.0.1 14 Dec 2021)

    自此,已经找到了问题的症结(也可能是问题的症结之一,是吧):似乎是ODBC只认这两个版本的openssl,沿着此线索搜索,发现,这个问题在Github的 issue 59@microsoft/homebrew-mssql-release 中讨论得比较多,而且,在下面的回答中也有一些办法可以尝试解决:在系统中,额外在安装openssl 1.1,并把链接库目录的软连接从3.0版本更换到1.1版本。(这么做,还是有点担心其他的软件运行有问题的,但是先这么做吧,把问题解决了),详细回答参考如下:

    具体的操作如下:

    zzx@localhost ~ % ls -lah /usr/local/opt/openssl
    lrwxr-xr-x  1 zzx  admin    25B 12 28 10:21 /usr/local/opt/openssl -> ../Cellar/openssl@3/3.0.1
    
    unlink /usr/local/opt/openssl
    
    # 这里要注意,你所安装的openssl版本和目录可能和以上截图中是不同的,所以要根据实际情况进行连接,例如我这里是1.1.1m版本,而不是截图中的1.1.1l版本。
    ln -s /usr/local/Cellar/openssl@1.1/1.1.1m /usr/local/opt/openssl

    Finnally,it works!!

    zzx@localhost ~ % ln -s /usr/local/Cellar/openssl@1.1/1.1.1m /usr/local/opt/openssl
    zzx@localhost ~ % isql -v -k 'Driver={ODBC Driver 17 for SQL Server};Server=tcp:19.36.80.2,1433;Database=9zcloud;Uid=zzx;Pwd=******;'
    +---------------------------------------+
    | Connected!                            |
    |                                       |
    | sql-statement                         |
    | help [tablename]                      |
    | quit                                  |
    |                                       |
    +---------------------------------------+
    SQL> select * from dbo.t_1;
    +------------+---------------------------------+-----------+
    | id         | nick                            | birthday  |
    +------------+---------------------------------+-----------+
    | 1          |                                 |           |
    | 2          | zzx                             |           |
    | 3          | yzs                             | 2008-09-23|
    +------------+---------------------------------+-----------+

    在回头去运行,最前面的示例脚本,也可以正常连接SQL Server,至此,剧终。所以,回头来看,今天的解决问题的堆栈如下:

    • unixODBC关于openssl版本兼容性的问题
    • 安装unixODBC & mssql-tools
    • 尝试python连接SQL Server
    • 尝试通过ssh tunnel连接SQL Server

    相关阅读

    • 更多关于什么是unixODBC,什么事isql,可以参考:unixODBC
    • Install the Microsoft ODBC driver for SQL Server (macOS):参考